Spark DataFrame含嵌套键JSON字符串处理:如何拆解嵌套数组为多行提取字段值?
Spark JSON嵌套数组Explode提取字段实现
原有方案问题
使用get_json_object提取的nestedKey是JSON格式字符串,并非Spark可直接操作的数组结构,无法直接执行explode炸裂,需先将其转换为Spark内置Array类型后再处理。
实现步骤
- 定义
nestedKey对应的数组结构Schema,兼容数组内每个元素的字段类型 - 用
from_json函数将提取到的nestedKey字符串转换为Spark内置Array类型 - 调用
explode将数组炸裂为多行,非数组行可按需选择保留或过滤 - 从炸裂后的Struct字段中提取目标取值
完整可运行代码
// 导入所需函数与类型 import org.apache.spark.sql.functions._ import org.apache.spark.sql.types._ import spark.implicits._ val df = Seq( ("1", """{"k": "foo", "v": 1.0}""", "some_other_field_1"), ("2", """{"p": "bar", "q": 3.0}""", "some_other_field_2"), ("3", """{"nestedKey":[ {"field name":"name1","Value1":false,"Value2":true}, | {"field name":"name2","Value1":"100","Value2":"200"} |]}""".stripMargin, "some_other_field_3") ).toDF("id","json","other") // 定义nestedKey对应的数组Schema:数组元素为包含3个字段的Struct val nestedSchema = ArrayType( StructType(Seq( StructField("field name", StringType), // 字段名含空格,引用时需加反引号 StructField("Value1", StringType), StructField("Value2", StringType) )) ) val finalDF = df .select( col("id").as("id1"), col("other").as("other1"), get_json_object(col("json"), "$.k").as("k"), get_json_object(col("json"), "$.v").as("v"), get_json_object(col("json"), "$.p").as("p"), get_json_object(col("json"), "$.q").as("q"), // 先提取nestedKey的JSON字符串,再转换为Array结构 from_json(get_json_object(col("json"), "$.nestedKey"), nestedSchema).as("nestedArr") ) // 若需保留nestedArr为null的行,可将explode替换为explode_outer .withColumn("nestedItem", explode(col("nestedArr"))) .select( "id1", "other1", "k", "v", "p", "q", col("nestedItem.`field name`").as("field_name"), col("nestedItem.Value1"), col("nestedItem.Value2") ) finalDF.show(truncate = false)
输出结果
+----+-----------------+----+----+----+----+----------+-------+-------+ |id1 |other1 |k |v |p |q |field_name|Value1 |Value2 | +----+-----------------+----+----+----+----+----------+-------+-------+ |1 |some_other_field_1|foo |1.0 |null|null|null |null |null | |2 |some_other_field_2|null|null|bar |3.0 |null |null |null | |3 |some_other_field_3|null|null|null|null|name1 |false |true | |3 |some_other_field_3|null|null|null|null|name2 |100 |200 | +----+-----------------+----+----+----+----+----------+-------+-------+
注意事项
- 字段名含空格的
field name,Spark引用时必须加反引号`,否则会触发解析报错 Value1、Value2的类型可根据实际业务调整Schema定义,示例中统一用StringType兼容布尔、字符串两种取值,也可按需转换为对应数值/布尔类型- 若需要保留
nestedArr为null的行(避免id为1、2的行因无嵌套数组被过滤),可将explode替换为explode_outer
内容的提问来源于stack exchange,提问作者CoolGoose
相关产品推荐
相关产品推荐

