У меня есть простой набор данных со схемой:
root
|-- columns: map (nullable = true)
| |-- key: string
| |-- value: struct (valueContainsNull = false)
| | |-- a: integer (nullable = true)
| | |-- b: long (nullable = true)
| | |-- c: float (nullable = true)
| | |-- d: double (nullable = true)
|-- ...
|-- ...
Пример:
+---------------------------------------------------+
|columns |
+---------------------------------------------------+
|[k0 -> [,,,, 2,], k1 -> [,,,, AB,], k2 -> [,,M,,,] |
+---------------------------------------------------+
Я хочу преобразовать свой набор данных в новый набор данных со схемой:
root
|-- columns: map (nullable = true)
| |-- key: string
| |-- value: string
Правила преобразования:
- Размер структуры не определен.
- Получить 1-й непустой элемент из структуры значений (в виде строки).
Пример вывода:
+----------------------------+
|columns |
+----------------------------+
|[k0 -> 2, k1 -> AB, k2 -> M |
+----------------------------+
Вот мое решение UDF
val my_udf: UserDefinedFunction = udf((m: Map[String, Row]) => m.map { case (k, v) => (k, v.toSeq.find(_ != null).map(_.toString)) })
df.select(my_udf(col("columns")))
Можно ли переписать его с помощью встроенных функций Spark?
Примерно так:
df.withColumn("data", expr("transform(fields.items(), (k, v) -> (k, get-1st-not-null-element-from-v)"))
Вот еще одна попытка (Spark 3.0 +):
df.select(map_entries(col("fields")).as("array"))
.select(
expr(
"transform(array, (e, _) -> " +
"struct(cast(e.key as string), coalesce(e.value.a, e.value.b, e.value.c, e.value.d, ...)))"
).as("entries")
)
.select(map_from_entries(col("entries")))