我有大约 96 gzip
的 JSON,使用以下结构解压缩后,这是超过 350 GB 的 JSON 文件
{
"structe": {},
"beta": {},
"flow": {
"1023": {
"0101": {
"-LEjllNyHqdHYGntO6vu": {
"status": "1",
"t": 1528736191996
},
"-LEjllcXKaVOQu3BDpHF": {
"status": "1",
"t": 1528736192996
}
},
"0102": {
"-LEjllNyHqdHYGntO6vu": {
"status": "1",
"t": 1528736191996
},
"-LEjllcXKaVOQu3BDpHF": {
"status": "1",
"t": 1528736192996
}
}
},
"1024": {
"0103": {
"-LEjllNyHqdHYGntO6vu": {
"lat": 51.128676733981,
"lng": -113.9318991267252,
"status": "1",
"t": 1528736191996
},
"-LEjllcXKaVOQu3BDpHF": {
"lat": 51.128676733981,
"lng": -113.9318991267252,
"status": "1",
"t": 1528736192996
}
}
}
}
}
我无法将其加载到 RAM 中,现在我想流式传输此文件并将路径 flow->1023(let id1)->0101(let id2)
拉入新的 id1_id2.json
文件。任何想法如何能够快速做到这一点。
我正在寻找的输出就像
文件名=1023_0101.json
{
"-LEjllNyHqdHYGntO6vu": {
"status": "1",
"t": 1528736191996
},
"-LEjllcXKaVOQu3BDpHF": {
"status": "1",
"t": 1528736192996
}
}
最佳答案
这里有一个解决方案,使用 jq 的流解析器来生成一个由 $id1、$id2 和相应的感兴趣值组成的流;然后可以将该流传输到另一个工具(例如 awk,如果方便的话)以生成所需的文件。
下面,我们使用 jq Cookbook 中的 atomize
:
def atomize(s):
fromstream(foreach s as $in ( {previous:null, emit: null};
if ($in | length == 2) and ($in|.[0][0]) != .previous and .previous != null
then {emit: [[.previous]], previous: $in|.[0][0]}
else { previous: ($in|.[0][0]), emit: null}
end;
(.emit // empty), $in) ) ;
主 jq 程序(使用 --stream -n -c 调用)很简单:
atomize(inputs)
| select(type == "object" and .flow)
| .flow
| keys_unsorted[] as $id1
| (.[$id1] | keys_unsorted[]) as $id2
| $id1, $id2, .[$id1][$id2]
因此,对于每个 gzip 文件 $gz,管道将如下所示:
gunzip -c $gz | jq -nc --stream -f 程序.jq | awk ....
有关使用 awk 生成所需结果的示例,请参阅 jq, split a huge json of array and save into file named with a value
注意事项和附录
jq 的流解析器避免以速度为代价使用 RAM,因此通常使用 --stream 选项只是作为最后的手段。从问题的描述来看,您似乎可以使用 jq 的常规解析器处理一些压缩文件,因此您可能希望快速处理这些文件,而对那些太大的文件保留“原子化”方法。
注意
问题描述没有明确如果出现 id1_id2.json 冲突该怎么办。如果没有这种碰撞的可能,那当然就没有问题。否则,将由创建这些文件的程序来管理该意外情况。
关于python - 将巨大的 JSON 文件流式解析为小文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58408121/