使用以下结构解压缩后,我大约有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
}
}
答案 0 :(得分:2)
这是一个使用jq的流解析器生成由$ id1,$ id2和对应的感兴趣值组成的流的解决方案;然后可以将该流传输到另一个工具(例如awk,如果方便的话)以生成所需的文件。
以下,我们使用jq食谱中的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 program.jq | awk ....
有关使用awk产生所需结果的示例,请参见jq, split a huge json of array and save into file named with a value
jq的流解析器避免以牺牲速度为代价使用RAM,因此通常仅在没有其他选择时才使用--stream选项。从问题的描述来看,您似乎可以使用jq的常规解析器处理某些压缩文件,因此您可能希望快速处理这些文件,而对那些太大的文件保留“ atomize”方法。
如果出现id1_id2.json冲突,问题描述并不清楚该怎么办。如果不可能发生这种碰撞,那么当然没有问题。否则,将由创建这些文件的程序来管理该突发事件。
答案 1 :(得分:1)
您可以将jq
与--stream
选项(jq - I/O (Streaming))一起使用,该选项以流方式读取文本,从而允许程序立即开始处理大型JSON文本,而不是在解析完成后开始处理(将整个文件存储在RAM中)。
假设您输入的id字符串存储在shell变量上下文中
id1=1023; id2=0101
将庞大的gzip
的输出放入以下过滤器
jq --arg v1 "$id1" --arg v2 "$id2" --stream 'fromstream(inputs)| objects | .flow[$v1][$v2]' > "$id1"_"$id2".json
(或)如果无法预先获取ID名称,而您需要在运行时获取ID名称,则直接将其名称用作
jq --stream 'fromstream(inputs)| objects | .flow."1023"."0101"'
答案 2 :(得分:0)
我首先想到的是将文件视为流,并逐行读取。已经有一些库将json文件视为流。例如,您可以从ijson库中检出片段:
对于JSON之类的
{
"earth": {
"europe": [
{"name": "Paris", "type": "city", "info": { ... }},
{"name": "Thames", "type": "river", "info": { ... }},
// ...
],
"america": [
{"name": "Texas", "type": "state", "info": { ... }},
// ...
]
}
}
治疗如下:
import ijson
parser = ijson.parse(urlopen('http://.../'))
stream.write('<geo>')
for prefix, event, value in parser:
if (prefix, event) == ('earth', 'map_key'):
stream.write('<%s>' % value)
continent = value
elif prefix.endswith('.name'):
stream.write('<object name="%s"/>' % value)
elif (prefix, event) == ('earth.%s' % continent, 'end_map'):
stream.write('</%s>' % continent)
stream.write('</geo>')