Jak mogę dodać lub zamienić pola w strukturze na dowolnym poziomie zagnieżdżonym?Dodawanie kolumny zagnieżdżonej do Spark DataFrame
Wejście:
val rdd = sc.parallelize(Seq(
"""{"a": {"xX": 1,"XX": 2},"b": {"z": 0}}""",
"""{"a": {"xX": 3},"b": {"z": 0}}""",
"""{"a": {"XX": 3},"b": {"z": 0}}""",
"""{"a": {"xx": 4},"b": {"z": 0}}"""))
var df = sqlContext.read.json(rdd)
dała następujący schemat:
root
|-- a: struct (nullable = true)
| |-- XX: long (nullable = true)
| |-- xX: long (nullable = true)
| |-- xx: long (nullable = true)
|-- b: struct (nullable = true)
| |-- z: long (nullable = true)
Wtedy mogę to zrobić:
import org.apache.spark.sql.functions._
val overlappingNames = Seq(col("a.xx"), col("a.xX"), col("a.XX"))
df = df
.withColumn("a_xx",
coalesce(overlappingNames:_*))
.dropNestedColumn("a.xX")
.dropNestedColumn("a.XX")
.dropNestedColumn("a.xx")
(dropNestedColumn
jest wypożyczony z tej odpowiedzi: https://stackoverflow.com/a/39943812/1068385. Po prostu szukam odwrotnej operacji na tego)
a schemat staje.
root
|-- a: struct (nullable = false)
|-- b: struct (nullable = true)
| |-- z: long (nullable = true)
|-- a_xx: long (nullable = true)
Oczywiście nie zastąpi (lub dodać) a.xx
ale zamiast tego dodaje nowe pole a_xx
na poziomie głównym.
Chciałbym móc to zrobić w zamian:
val overlappingNames = Seq(col("a.xx"), col("a.xX"), col("a.XX"))
df = df
.withNestedColumn("a.xx",
coalesce(overlappingNames:_*))
.dropNestedColumn("a.xX")
.dropNestedColumn("a.XX")
Tak, że doprowadziłoby to do tego schematu:
root
|-- a: struct (nullable = false)
| |-- xx: long (nullable = true)
|-- b: struct (nullable = true)
| |-- z: long (nullable = true)
Jak mogę to osiągnąć?
Praktyczny cel w tym przypadku ma być niewrażliwy na wielkość liter z nazwami kolumn w wejściowym JSON. Ostatni krok będzie prosty: zbierz wszystkie nakładające się nazwy kolumn i zastosuj koalescencję na każdym z nich.
wziąłeś rozwiązanie? –
@ShankarKoirala: nie ze Spark. W Hive było trywialnie używać COALESCE do osiągnięcia tego, co chciałem. – Arvidaa