PySpark分组生成JSON后explode提取字段报错如何解决
报错的核心根源是to_json函数的使用不符合你的需求:to_json会将输入的struct结构序列化为纯JSON字符串,你生成的metadata字段类型为字符串,而非结构化的struct类型。后续经collect_list聚合得到的jsonmetadata是字符串数组,每个元素都是普通文本,自然无法通过.运算符提取struct属性,这和报错提示need struct type but got string完全对应。
方案1(推荐,已验证生效)
无需提前做JSON序列化,直接收集struct数组即可,既保留了结构化查询能力,需要输出JSON格式时可随时对整个数组调用to_json:
df2 = (df1.select("FileName","ID", struct("SourceFileName","FileReceivedTimestamp","FileSize").alias("metadata")) .groupby("FileName","ID") .agg(collect_list(col("metadata")).alias("jsonmetadata")))
此时jsonmetadata为struct数组,explode后可直接提取字段:
display(df2.select(explode(col("jsonmetadata")).alias("MetadataArray") ,col("MetadataArray.SourceFileName").alias("SourceFileName") ))
该方案对应的Schema如下:
root |-- FileName: string (nullable = true) |-- ID: string (nullable = true) |-- jsonmetadata: array (nullable = true) | |-- element: struct (containsNull = false) | | |-- SourceFileName: string (nullable = true) | | |-- FileReceivedTimestamp: string (nullable = true) | | |-- FileSize: string (nullable = true)
方案2(适配必须提前存储JSON字符串的场景)
如果业务要求提前将字段转成JSON字符串存储,提取属性前需要先通过from_json将字符串反序列化为struct结构:
from pyspark.sql.functions import from_json, explode # 定义JSON对应的结构Schema metadata_schema = "struct<SourceFileName:string, FileReceivedTimestamp:string, FileSize:string>" display(df2.select(explode(col("jsonmetadata")).alias("MetadataArray") ,from_json(col("MetadataArray"), metadata_schema).alias("metadata_struct") ,col("metadata_struct.SourceFileName").alias("SourceFileName") ))
内容的提问来源于stack exchange,提问作者btt3165

