#apache-spark
#apache-spark
Вопрос:
У меня есть столбец, содержащий массив структур. Это выглядит так:
|-- Network: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- Code: string (nullable = true)
| | |-- Signal: string (nullable = true)
Это всего лишь небольшая выборка, внутри структуры намного больше столбцов, чем это. Есть ли способ взять массивы в столбце для каждой строки, объединить их и превратить в одну строку? Например, у нас может быть что-то вроде этого:
[["example", 2], ["example2", 3]]
Есть ли способ превратить в:
"example2example3"?
Комментарии:
1. какую версию Spark вы используете?
Ответ №1:
Предполагая наличие df
фрейма данных со следующей схемой:
df.printSchema
df
с примерами данных:
df.show(false)
Вам нужно сначала разобрать сетевой массив, чтобы выбрать элементы структуры Code и signal.
var myDf = df.select(explode($"Network").as("Network"))
Затем вам нужно объединить два столбца с помощью функции concat(), а затем передать выходные данные функции collect_list(), которая объединит все строки в одну строку типа array<string>
myDf = myDf.select(collect_list(concat($"Network.code",$"Network.signal")).as("data"))
Наконец, вам нужно объединить в требуемый формат, что можно сделать с помощью функции concat_ws(), которая принимает два аргумента, первый из которых является разделителем, который должен быть помещен между двумя строками, а второй аргумент представляет собой столбец с типом array<string>, который является нашим результатом из нашего предыдущего шага. В соответствии с вашим вариантом использования, нам не нужно размещать разделитель между двумя объединенными строками, поэтому мы сохраняем аргумент разделителя как пустую кавычку.
myDf = myDf.select(concat_ws("",$"data").as("data"))
Все вышеуказанные шаги можно выполнить в одной строке
myDf= myDf.select(explode($"Network").as("Network")).select(concat_ws("",collect_list(concat($"Network.code",$"Network.signal"))).as("data")).show(false)
Если вы хотите выводить данные непосредственно в строковую переменную, используйте:
val myStr = myDf.first.get(0).toString
print(myStr)
Ответ №2:
Существует библиотека под названием spark-hats (Github, небольшая статья), которая может оказаться очень полезной в таких ситуациях.
С его помощью вы можете легко сопоставить массив и вывести конкатенацию рядом с элементами или даже где-то еще, если вы укажете полное имя.
Настройка
import org.apache.spark.sql.functions._
import za.co.absa.spark.hats.Extensions._
scala> df.printSchema
root
|-- info: struct (nullable = true)
| |-- drivers: struct (nullable = true)
| | |-- carName: string (nullable = true)
| | |-- carNumbers: string (nullable = true)
| | |-- driver: string (nullable = true)
|-- teamName: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- team1: string (nullable = true)
| | |-- team2: string (nullable = true)
scala> df.show(false)
--------------------------- ------------------------------
|info |teamName |
--------------------------- ------------------------------
|[[RB7, 33, Max Verstappen]]|[[Redbull, rb], [Monster, mt]]|
--------------------------- ------------------------------
Команда, которую вы ищете
scala> val dfOut = df.nestedMapColumn(inputColumnName = "teamName", outputColumnName = "nextElementInArray", expression = a => concat(a.getField("team1"), a.getField("team2")) )
dfOut: org.apache.spark.sql.DataFrame = [info: struct<drivers: struct<carName: string, carNumbers: string ... 1 more field>>, teamName: array<struct<team1:string,team2:string,nextElementInArray:string>>]
Вывод
scala> dfOut.printSchema
root
|-- info: struct (nullable = true)
| |-- drivers: struct (nullable = true)
| | |-- carName: string (nullable = true)
| | |-- carNumbers: string (nullable = true)
| | |-- driver: string (nullable = true)
|-- teamName: array (nullable = true)
| |-- element: struct (containsNull = false)
| | |-- team1: string (nullable = true)
| | |-- team2: string (nullable = true)
| | |-- nextElementInArray: string (nullable = true)
scala> dfOut.show(false)
--------------------------- ----------------------------------------------------
|info |teamName |
--------------------------- ----------------------------------------------------
|[[RB7, 33, Max Verstappen]]|[[Redbull, rb, Redbullrb], [Monster, mt, Monstermt]]|
--------------------------- ----------------------------------------------------