如何仅用PyArrow将嵌套JSON的results列表转换为Arrow表
问题:将JSON中的results列表转为Arrow表(仅使用PyArrow)
给定如下JSON数据:
consumption_json = """ { \"count\": 48, \"next\": null, \"previous\": null, \"results\": [ { \"consumption\": 0.063, \"interval_start\": \"2018-05-19T00:30:00+0100\", \"interval_end\": \"2018-05-19T01:00:00+0100\" }, { \"consumption\": 0.071, \"interval_start\": \"2018-05-19T00:00:00+0100\", \"interval_end\": \"2018-05-19T00:30:00+0100\" }, { \"consumption\": 0.073, \"interval_start\": \"2018-05-18T23:30:00+0100\", \"interval_end\": \"2018-05-18T00:00:00+0100\" } ] } """
原本通过Python的json库解析后再用pa.Table.from_pylist()转换的方式可以得到目标表,但出于性能考虑希望仅用PyArrow完成转换。目前已通过pa.json.read_json()读取JSON得到包含嵌套results字段的表,使用pc.list_flatten()处理后得到扁平化的结构体数组,需要将其转为目标Arrow表。
解决方案
pc.list_flatten()返回的是StructArray类型,我们可以直接利用PyArrow的API将其转换为表,有两种简洁的方式:
方法1:直接转换StructArray(推荐)
这是最直接的方式,StructArray的字段会自动映射为表的列:
import pyarrow as pa import pyarrow.compute as pc # 读取JSON数据 reader = pa.BufferReader(bytes(consumption_json, encoding='ascii')) table_from_reader = pa.json.read_json(reader) # 扁平化results字段的列表,得到StructArray flat_struct = pc.list_flatten(table_from_reader["results"]) # 将StructArray转换为目标表 target_table = pa.Table.from_struct_array(flat_struct) print(target_table)
方法2:手动提取字段构造表
如果需要自定义列名或调整列顺序,可以手动提取每个字段构造表:
import pyarrow as pa import pyarrow.compute as pc reader = pa.BufferReader(bytes(consumption_json, encoding='ascii')) table_from_reader = pa.json.read_json(reader) flat_struct = pc.list_flatten(table_from_reader["results"]) # 提取每个字段并构造表 target_table = pa.Table.from_arrays( [ flat_struct.field("consumption"), flat_struct.field("interval_start"), flat_struct.field("interval_end") ], names=["consumption", "interval_start", "interval_end"] ) print(target_table)
输出结果
上述代码执行后,会得到如下格式的Arrow表(PyArrow会自动解析时间戳字段为timestamp[s]类型,而非原方法中的string类型;如果需要转为string类型,可以使用pc.cast()进行转换):
pyarrow.Table consumption: double interval_start: timestamp[s] interval_end: timestamp[s] ---- consumption: [[0.063,0.071,0.073]] interval_start: [[2018-05-18 23:30:00,2018-05-18 23:00:00,2018-05-18 22:30:00]] interval_end: [[2018-05-19 00:00:00,2018-05-18 23:30:00,2018-05-17 23:00:00]]
内容的提问来源于stack exchange,提问作者Jack Chidley
相关产品推荐
相关产品推荐

