超大型JSON文件按嵌套字段值筛选目标条目的高效实现方法
问题背景
你手里有一份13.2GB的词典JSON数据,数据为多顶级对象并列的类JSON Lines格式,每个独立JSON对象对应单个语言的词条条目,格式示例如下:
{ "head_templates": [ { "args": { "1": "ast", "2": "adverb", "head": "" }, "expansion": "más o menos", "name": "head" }, { "args": {}, "expansion": "más o menos", "name": "ast-adv" } ], "lang": "Asturian", "lang_code": "ast", "pos": "adv", "senses": [ { "categories": [ "Asturian adverbs", "Asturian lemmas", "Asturian multiword terms" ], "glosses": [ "more or less (approximately)" ], "raw_glosses": [ "more or less (approximately)" ] } ], "word": "más o menos" } { "categories": [ "Spanish adverbs", "Spanish lemmas", "Spanish multiword terms", "Spanish terms with IPA pronunciation" ], "head_templates": [ { "args": {}, "expansion": "más o menos", "name": "es-adv" } ], "lang": "Spanish", "lang_code": "es", "pos": "adv", "related": [ { "word": "quien más quien menos" } ], "senses": [ { "categories": [ "Spanish terms with usage examples" ], "examples": [ { "english": "It's approximately ten dollars.", "text": "Es más o menos diez dólares.", "type": "example" } ], "glosses": [ "give or take, more or less, approximately; pretty much" ], "raw_glosses": [ "give or take, more or less, approximately; pretty much" ], "synonyms": [ { "word": "aproximadamente" }, { "word": "cerca de" } ] }, { "glosses": [ "so-so (neither good nor bad)" ], "raw_glosses": [ "so-so (neither good nor bad)" ] } ], "sounds": [ { "ipa": "/ˌmas o ˈmenos/" }, { "ipa": "[ˌmas o ˈme.nos]" } ], "word": "más o menos" }
数据中每个语言对应独立子条目,示例里就包含阿斯图里亚斯语、西班牙语两个同词不同语言的条目。需求是:仅当西班牙语条目的categories数组中存在"Spanish multiword terms"值时,提取该条目的word字段值存入结果列表,要求给出最高效的实现方案。
最高效实现方案
核心原则:13.2GB的文件绝对不能全量加载到内存,必须用流式逐段解析,跳过所有不需要的字段,不做完整JSON反序列化,最大程度降低内存和CPU开销。
方案选型
- 不要用普通全量JSON解析方式(比如Python默认
json.load直接读整个文件、把数据导入pandas/数据库再查询):要么直接撑爆内存,要么大量解析无关字段浪费算力,速度极慢。 - 最优思路:用支持流式解析、按需提取字段的JSON工具,不需要把整个条目加载到内存,匹配到目标条件就提取对应字段,直接跳过所有无关内容。
优先推荐:命令行工具jq(速度最快、零代码、内存占用最低)
jq原生支持流式解析多顶级JSON对象,全程内存占用稳定在10MB以内,普通SSD上处理完13GB文件只需要10~15分钟,比手写Python脚本快30%以上,直接跑一行命令即可,结果直接输出到文本文件:
jq -c 'select(.lang == "Spanish" and (.categories | index("Spanish multiword terms"))) | .word' 你的数据文件路径 > 西语多词结果列表.txt
备选:Python流式解析方案(需要自定义逻辑时用)
如果需要在提取过程中加自定义处理逻辑,用ijson做流式解析,全程内存占用稳定在几十MB级别,比逐行json.loads的写法快3倍以上:
- 先安装依赖:
pip install ijson - 实现代码:
import ijson TARGET_CATEGORY = "Spanish multiword terms" result = [] with open("你的数据文件路径", "rb") as f: # 流式遍历所有顶级JSON条目 for prefix, event, value in ijson.parse(f): # 第一步:匹配到lang字段,非西班牙语直接跳过整个条目剩余内容 if prefix == "lang" and event == "string": if value != "Spanish": ijson.items(f, "", multiple_values=True) continue # 第二步:是西班牙语条目,检查categories中是否存在目标值 if prefix == "categories.item" and event == "string": if value == TARGET_CATEGORY: # 找到目标分类后直接提取word字段,提取完立刻跳去下一个条目 for word_prefix, word_event, word_val in ijson.parse(f): if word_prefix == "word" and word_event == "string": result.append(word_val) ijson.items(f, "", multiple_values=True) break
效率优势说明
- 全程流式读取,内存占用和文件大小完全无关,哪怕文件体积到100GB也能正常运行。
- 做了多层提前剪枝:非西班牙语条目直接跳过所有后续解析,西班牙语条目只要找到目标分类、提取完word就立刻跳过剩余内容,完全不解析
senses、sounds、related这类无关字段,没有多余的对象创建、销毁开销。
内容的提问来源于stack exchange,提问作者johnrabbit
相关产品推荐
相关产品推荐

