如何使用PySpark解析非标准结构的JSON文件?
PySpark解析动态键JSON数据的问题与解决
问题场景
给定如下格式的JSON文件:
{ "42": {"name": "MeowBark", "id": 42, "category": "pet store"}, "67": {"name": "Chef's Kiss", "id": 67, "category": "restaurant"} }
使用以下PySpark代码读取:
stores = spark.read.json(stores, multiLine=True).cache()
得到的DataFrame不符合预期,结构如下:
| key1 | key2 |
|---|---|
| {MeowBark, true, pet store} | {Chef's Kiss, false, restaurant} |
需要仅用PySpark操作实现正确解析,避免依赖Pandas的转置方法。
问题原因
原JSON的顶层是动态数字键(如42、67),Spark默认会将每个顶层键解析为一个DataFrame列,导致生成key1、key2这类动态列,且列内的结构体未被展开为单独字段。
解决方法
核心思路是将动态键的结构转换为Map类型,再通过explode将Map拆分为多行,最后展开结构体字段。以下提供两种可行方案:
方案一:基于已读取的列转换为Map
# 1. 读取原始JSON stores_df = spark.read.json("path/to/your/file.json", multiLine=True) # 2. 将所有列转换为Map(键为列名,值为对应结构体) from pyspark.sql.functions import create_map, lit, explode, chain cols = stores_df.columns map_col = create_map(list(chain(*[(lit(c), stores_df[c]) for c in cols]))) # 3. 拆分Map为行,得到store_id和store_info两列 exploded_df = stores_df.select(explode(map_col).alias("store_id", "store_info")) # 4. 展开结构体字段为单独列 final_df = exploded_df.select( "store_id", "store_info.name", "store_info.id", "store_info.category" ) final_df.show()
方案二:直接读取文本并解析为Map
这种方法跳过Spark自动拆分列的步骤,直接解析整个JSON为Map:
# 1. 读取整个JSON文件为单一文本列 text_df = spark.read.text("path/to/your/file.json", wholetext=True) # 2. 定义结构体和Map类型 from pyspark.sql.functions import from_json from pyspark.sql.types import MapType, StructType, StructField, StringType, IntegerType store_struct = StructType([ StructField("name", StringType()), StructField("id", IntegerType()), StructField("category", StringType()) ]) map_type = MapType(StringType(), store_struct) # 3. 解析文本为Map结构 parsed_df = text_df.select(from_json("value", map_type).alias("stores")) # 4. 拆分Map为行并展开字段 exploded_df = parsed_df.select(explode("stores").alias("store_id", "store_info")) final_df = exploded_df.select( "store_id", "store_info.name", "store_info.id", "store_info.category" ) final_df.show()
执行后会得到预期的结构化DataFrame:
| store_id | name | id | category |
|---|---|---|---|
| 42 | MeowBark | 42 | pet store |
| 67 | Chef's Kiss | 67 | restaurant |
内容的提问来源于stack exchange,提问作者jmoore00
相关产品推荐
相关产品推荐

