【发布时间】:2021-07-29 09:05:03
【问题描述】:
我有一个包含结构数组的嵌套源 json 文件。结构的数量因行而异,我想使用 Spark(scala)从结构的键/值动态创建新的数据框列,其中键是列名,值是列值。
缩小的 json 记录示例
{"key1":{"key2":{"key3":"AK","key4":"EU","key5":{"key6":"001","key7":"N","values":[{"name":"valuesColumn1","value":"9.876"},{"name":"valuesColumn2","value":"1.2345"},{"name":"valuesColumn3","value":"8.675309"}]}}}}
数据框架构
scala> val df = spark.read.json("file:///tmp/nested_test.json")
root
|-- key1: struct (nullable = true)
| |-- key2: struct (nullable = true)
| | |-- key3: string (nullable = true)
| | |-- key4: string (nullable = true)
| | |-- key5: struct (nullable = true)
| | | |-- key6: string (nullable = true)
| | | |-- key7: string (nullable = true)
| | | |-- values: array (nullable = true)
| | | | |-- element: struct (containsNull = true)
| | | | | |-- name: string (nullable = true)
| | | | | |-- value: string (nullable = true)
到目前为止做了什么
df.select(
($"key1.key2.key3").as("key3"),
($"key1.key2.key4").as("key4"),
($"key1.key2.key5.key6").as("key6"),
($"key1.key2.key5.key7").as("key7"),
($"key1.key2.key5.values").as("values")).
show(truncate=false)
+----+----+----+----+----------------------------------------------------------------------------+
|key3|key4|key6|key7|values |
+----+----+----+----+----------------------------------------------------------------------------+
|AK |EU |001 |N |[[valuesColumn1, 9.876], [valuesColumn2, 1.2345], [valuesColumn3, 8.675309]]|
+----+----+----+----+----------------------------------------------------------------------------+
这里有一个由 3 个结构组成的数组,但是这 3 个结构需要动态地拆分为 3 个单独的列(3 个的数量可能会有很大差异),我不知道该怎么做。
样本期望输出
请注意,values 数组中的每个数组元素都生成了 3 个新列。
+----+----+----+----+-----------------------------------------+
|key3|key4|key6|key7|valuesColumn1|valuesColumn2|valuesColumn3|
+----+----+----+----+-----------------------------------------+
|AK |EU |001 |N |9.876 |1.2345 |8.675309 |
+----+----+----+----+-----------------------------------------+
参考
我相信所需的解决方案是something similar to what was discussed in this SO post,但有两个主要区别:
- 在 SO 帖子中,列数被硬编码为 3,但在我的情况下,数组元素的数量是未知的
- 列名需要由
name列驱动,列值由value驱动。
...
| | | | |-- element: struct (containsNull = true)
| | | | | |-- name: string (nullable = true)
| | | | | |-- value: string (nullable = true)
【问题讨论】:
标签: json scala apache-spark