Как я могу разделить столбец, содержащий массив некоторой структуры на отдельные столбцы? - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть следующие сценарии:

case class attribute(key:String,value:String)
case class entity(id:String,attr:List[attribute])


val entities = List(entity("1",List(attribute("name","sasha"),attribute("home","del"))),
entity("2",List(attribute("home","hyd"))))

val df = entities.toDF()

// df.show
+---+--------------------+
| id|                attr|
+---+--------------------+
|  1|[[name,sasha], [d...|
|  2|        [[home,hyd]]|
+---+--------------------+

//df.printSchema
root
 |-- id: string (nullable = true)
 |-- attr: array (nullable = true)
 |    |-- element: struct (containsNull = true)
      |    |    |-- key: string (nullable = true)
      |    |    |-- value: string (nullable = true) 

, что я хочу произвести:

+---+--------------------+-------+
| id|  name              |  home |
+---+--------------------+-------+
|  1| sasha              |del    |
|  2| null               |hyd    |
+---+--------------------+-------+

Как мне поступить?Я рассмотрел довольно много похожих вопросов по стеку, но не смог найти ничего полезного.

Мой основной мотив - использовать groupBy для разных атрибутов, поэтому хочу перенести его в вышеупомянутый формат.

Я посмотрел на функциональность взрыва.Он разбивает список на отдельные строки, я этого не хочу.Я хочу создать больше столбцов из массива attribute.

Подобные вещи, которые я нашел:

Spark - преобразовать Map в однострочный DataFrame

Разделить 1 столбец на 3 столбца в Spark Scala

Spark dataframe - Разделить столбец struct на 2 столбца

1 Ответ

0 голосов
/ 12 февраля 2019

Это можно легко уменьшить до PySpark, преобразующий столбец типа 'map' в несколько столбцов в фрейме данных или Как получить ключи и значения из столбца MapType в SparkSQL DataFrame .Сначала конвертируйте attr в map<string, string>

import org.apache.spark.sql.functions.{explode, map_from_entries, map_keys}

val dfMap = df.withColumn("attr", map_from_entries($"attr"))

, затем вам нужно просто найти уникальные ключи

val keys = dfMap.select(explode(map_keys($"attr"))).as[String].distinct.collect

, а затем выбрать на карте

val result = dfMap.select($"id" +: keys.map(key => $"attr"(key) as key): _*)
result.show
+---+-----+----+
| id| name|home|
+---+-----+----+
|  1|sasha| del|
|  2| null| hyd|
+---+-----+----+

Менее эффективный, но более лаконичный вариант - explode и pivot

val result = df
  .select($"id", explode(map_from_entries($"attr")))
  .groupBy($"id")
  .pivot($"key")
  .agg(first($"value"))

result.show
+---+----+-----+
| id|home| name|
+---+----+-----+
|  1| del|sasha|
|  2| hyd| null|
+---+----+-----+

, но на практике я бы советовал против этого.

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