Как извлечь элементы из массива [String], который начинается с определенного значения в Scala? - PullRequest
3 голосов
/ 06 июня 2019

У меня есть фрейм данных Scala со следующей схемой:

filter_msg.printSchema()
root
|-- value: array (nullable = true)
|    |-- element: string (containsNull = true)

и образец данных:

|[SD:GK, 3.16.0, OS:Linux, (x86_64), AID:176]|

Я хочу извлечь значения из этой строки массива, где элемент начинается, скажем, с SD, и получить значение, а затем, если его ОС получит значение. Проблема в том, что позиция в строке массива не всегда одинакова, она постоянно меняется, поэтому я не могу использовать

filter_msg.select($"value".getItem(1).as("SD"))

Вывод должен дать мне фрейм данных:

Output=GK | Linux
Output.printSchema()
String,String

Ответы [ 4 ]

0 голосов
/ 07 июня 2019

Вот еще один подход с использованием регулярных выражений и функции regexp_extract:

import org.apache.spark.sql.functions.{concat_ws, regexp_extract}

val df = Seq(
  Seq("SD:GK", "3.16.0", "OS:Linux", "(x86_64)", "AID:176")
).toDF

df.withColumn("to_str", concat_ws(",", $"value")) //concatenate array items into one string i.e: SD:GK,3.16.0,OS:Linux,(x86_64),AID:176
  .select(
    regexp_extract($"to_str", "SD:(\\w+),", 1) as "SD", //extract SD 
    regexp_extract($"to_str", "OS:(\\w+),", 1) as "OS"  //extract OS
  ).show(false)

// Output
// +---+-----+
// |SD |OS   |
// +---+-----+
// |GK |Linux|
// +---+-----+
0 голосов
/ 06 июня 2019

Вы можете преобразовать в rdd и извлечь значения, как показано ниже

// If you can conferm the data are always in same order
filter_msg.rdd.map(_.getAs[mutable.WrappedArray[String]](0))
  .map(row => {
    val sd = row(0).split(":").tail.head
    val os = row(2).split(":").tail.head
    (sd, os)
  } )
  .toDF("sd", "os")

Или вы можете использовать в качестве @SleightX упомянутых

filter_msg.rdd.map(_.getAs[mutable.WrappedArray[String]](0))
  .map(row => {
    val sd = row.filter(_.startsWith("SD:")).head.split(":").tail.head
    val os = row.filter(_.startsWith("OS:")).head.split(":").tail.head
    (sd, os)
  } )
  .toDF("sd", "os")

Вывод:

+---+-----+
|sd |os   |
+---+-----+
|GK |Linux|
+---+-----+
0 голосов
/ 06 июня 2019

UDF может использоваться:

val df = Seq(Array("SD:GK", "3.16.0", "OS:Linux", "(x86_64)", "AID:176")).toDF("value")

val extractArrayValues = (prefix: String, values: Seq[String]) =>
  values.filter(_.startsWith(prefix + ":")).map(_.split(":")(1)).headOption

val extractUDF = udf(extractArrayValues)
val result = df.select(
  extractUDF(lit("SD"), $"value").alias("SD"),
  extractUDF(lit("OS"), $"value").alias("OS")
)

Результат:

+---+-----+
|SD |OS   |
+---+-----+
|GK |Linux|
+---+-----+
0 голосов
/ 06 июня 2019

К сожалению, я не знаком с искрой, но если у вас просто есть массив [String], то должно хватить следующего

<script src="https://scastie.scala-lang.org/nYZgm5ODSESLHkqb9iEDgw.js"></script>

И в случае, если вы не можете запустить фрагмент кода здесь, в текстовом формате:

val array = Array("bla", "blie", "OS:Linux", "Fu", "Bar")

val os = array.filter(_.startsWith("OS:")).head.split(":").tail.head

println(os)

Выходы:

Linux

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...