如何用PySpark将特定结构多份JSON转换为目标DataFrame?
问题描述
现有多份结构如下的JSON数据:
Association字段可包含一个或多个对象Characteristic的键值对数量不固定
需要基于这些JSON构建两个指定结构的DataFrame:
- 第一个DataFrame包含根对象的基础信息 +
Characteristic中的键值对作为列 - 第二个DataFrame包含根对象ID + 每个
Association的详细信息
若实现复杂,也可将Characteristic保存为与根对象ID关联的独立表。请问最优实现方案是什么?
JSON结构示例:
{"vl:VNETList": {"Template": {"ID": "SomeId","Object": [{"ID": "my_first_id","Context": {"ID": "Avngate"},"Name": "Model Description","ClassID": "PID","Association": [{"Object": {"ID": "test.svg","Context": {"ID": "Avngate"}},"@type": "is fulfilled by"},{"Object": {"ID": "Project Description","Context": {"ID": "Avngate"}},"@type": "is an element of"}],"Characteristic": [{"Name": "InfoType","Value": "image/svg+xml"},{"Name": "LOCK","Value": false},{"Name": "EXFI","Value": 10000}]},{"ID": "my_second_id","Context": {"ID": "Avngate2"},"Name": "Model Description2","ClassID": "PID2","Association": [{"Object": {"ID": "test2.svg","Context": {"ID": "Avngate"}},"@type": "is fulfilled by"}],"Characteristic": [{"Name": "Dbtencoding","Value": "unicode"}]}]}}}
最优实现方案(基于Python Pandas)
核心思路
- 先解析JSON,提取出
Object数组(所有根对象的集合) - 拆分每个根对象的基础信息、
Characteristic、Association三部分 - 分别处理生成目标DataFrame,针对
Characteristic的不同数据特征,提供两种处理方式
步骤1:解析JSON数据
读取并解析JSON,提取目标根对象列表:
import pandas as pd import json # 读取单份JSON文件(多份文件可循环读取合并) with open('data.json', 'r') as f: data = json.load(f) # 提取根对象集合 objects_list = data['vl:VNETList']['Template']['Object']
步骤2:生成第一个DataFrame(根对象+Characteristic)
根据Characteristic的键重叠度选择不同处理方式:
方式A:Characteristic展平为列(适合键重叠度高的场景)
将每个根对象的Characteristic键值对直接合并到基础信息中:
processed_objects = [] for obj in objects_list: # 提取基础信息,排除嵌套的关联字段 base_info = {k: v for k, v in obj.items() if k not in ['Association', 'Characteristic']} # 展平Context的ID为单独列 base_info['Context_ID'] = obj['Context']['ID'] del base_info['Context'] # 将Characteristic转为键值对字典 char_dict = {item['Name']: item['Value'] for item in obj['Characteristic']} # 合并基础信息与Characteristic processed_objects.append({**base_info, **char_dict}) # 生成主DataFrame df_main = pd.DataFrame(processed_objects)
生成的df_main结构示例:
| ID | Name | ClassID | Context_ID | InfoType | LOCK | EXFI | Dbtencoding |
|---|---|---|---|---|---|---|---|
| my_first_id | Model Description | PID | Avngate | image/svg+xml | False | 10000 | NaN |
| my_second_id | Model Description2 | PID2 | Avngate2 | NaN | NaN | NaN | unicode |
方式B:Characteristic单独存表(适合键差异极大的场景)
若Characteristic的键多且重复率低,单独存表可避免大量空值,节省存储空间:
main_data = [] char_data = [] for obj in objects_list: # 主表仅保留根对象核心信息 base_info = { 'ID': obj['ID'], 'Name': obj['Name'], 'ClassID': obj['ClassID'], 'Context_ID': obj['Context']['ID'] } main_data.append(base_info) # 构建Characteristic关联表,绑定根对象ID for char in obj['Characteristic']: char_data.append({ 'Object_ID': obj['ID'], 'Char_Name': char['Name'], 'Char_Value': char['Value'] }) df_main = pd.DataFrame(main_data) df_characteristics = pd.DataFrame(char_data)
df_characteristics结构示例:
| Object_ID | Char_Name | Char_Value |
|---|---|---|
| my_first_id | InfoType | image/svg+xml |
| my_first_id | LOCK | False |
| my_first_id | EXFI | 10000 |
| my_second_id | Dbtencoding | unicode |
步骤3:生成第二个DataFrame(根对象ID+Association信息)
将每个Association条目与根对象ID关联,展平嵌套结构:
association_data = [] for obj in objects_list: obj_id = obj['ID'] # 遍历每个Association,绑定根对象ID for assoc in obj['Association']: assoc_info = { 'Object_ID': obj_id, 'Assoc_Type': assoc['@type'], 'Assoc_Object_ID': assoc['Object']['ID'], 'Assoc_Context_ID': assoc['Object']['Context']['ID'] } association_data.append(assoc_info) df_associations = pd.DataFrame(association_data)
生成的df_associations结构示例:
| Object_ID | Assoc_Type | Assoc_Object_ID | Assoc_Context_ID |
|---|---|---|---|
| my_first_id | is fulfilled by | test.svg | Avngate |
| my_first_id | is an element of | Project Description | Avngate |
| my_second_id | is fulfilled by | test2.svg | Avngate |
方案优势
- 基于Pandas的操作简洁高效,支持大规模JSON数据处理
- 两种
Characteristic处理方式可灵活适配不同数据特征 - 多份JSON文件可通过循环读取合并,扩展性强
内容的提问来源于stack exchange,提问作者Valouf
相关产品推荐
相关产品推荐

