在Python中,加载大型JSON列表的最佳方式是什么?

4

我可以访问一组文件(每个文件大小在80-800MB之间)。不幸的是,每个文件只有一行内容。该行包含一个JSON对象(列表的列表)。如何最好地将其加载和解析为较小的JSON对象?


这个问题被关闭为重复,因为这里接受的答案是与此答案完全相同的。 - Trenton McKinney
3个回答

8

模块pandas 0.21.0现在支持read_json中的chunksize。您可以一次加载和操作一个chunk:

import pandas as pd
chunks = pd.read_json(file, lines=True, chunksize = 100)
for c in chunks:
    print(c)

这个不起作用,试试使用 ijson。在受限的 t1.micro 实例上使用 python3.7 和一个 170 MB 的文件,执行以下 pandas 命令会返回如下错误:Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib64/python3.7/site-packages/pandas/io/json/_json.py", line 765, in next obj = self._get_object_parser(lines_json) ... loads(json, precise_float=self.precise_float), dtype=None MemoryError - jbass

4

这里已经有一个类似的帖子 链接。他们提出的解决方案如下:

import json
with open('file.json') as infile:
  o = json.load(infile)
  chunkSize = 1000
  for i in xrange(0, len(o), chunkSize):
    with open('file_' + str(i//chunkSize) + '.json', 'w') as outfile:
      json.dump(o[i:i+chunkSize], outfile)

3
“killed”,这是Python Shell所显示的。 - ashish
3
这个问题要求将数据加载并解析成更小的 JSON 对象,而不是仅仅将其转储到一个输出文件中。在这里,你只是将原始的 JSON 输入分成固定长度的块,这些单独的块几乎肯定无法被解析为合法的 JSON。 - smci

4
如果您想避免将整个列表加载到内存中,可以首先将文件处理为文本:
使用堆栈来跟踪括号/引号的打开和关闭。扫描字符串以查找任何开放者或当前闭合者。当浏览文本时,仅寻找文本闭合者。读取打开器时将其推入,找到关闭器时将其弹出。
JSON 的完整设置是 [ -> ]{ -> }" -> "。不过应排除掉\ "。 您可以在http://www.json.org/上检查规范。
然后,每当遇到一个 ] 并且在弹出匹配的 [ 后,栈只有一个项目(顶级 '[')时,则知道是开始新行的时候了。
最后,请确保第一个 [ 和最后一个 ] 不出现在您的输出中。
这将为列表的每个项目提供单独的 JSON 对象,每个对象在文件的单独一行上。
如果深入研究 Python JSON 库,应该有一些解析 JSON 的函数。您可以利用它们,即使它们不是公共接口的一部分。
当然,您也可以使用 JSON 库加载字符串,然后根据其他答案中的方式逐个(或多个)输出它。

1
当标准库中配备了完美的JSON模块时,为什么需要这种低级扫描方法?请参见@linker的答案。 - jdi
我猜他不想在内存中实际存储JSON对象,因为JSON库的公共接口不允许这样做。不过我提到过他可以入侵该库并使用一些辅助函数,尽管我还没有查看它们。 - chees
是的,但内存问题并不是其他答案建议的一次批处理的问题。它不必是生产解决方案,只需将其批处理为较小的对象即可。 - jdi
我实际上没有考虑到 OP 明确表示它将始终是一个 JSON 列表的列表。因此,如果 OP 确实想要实时处理,逐个字符扫描是合理的。但是,如果内存不是问题,那么使用 C 加速的 JSON 模块会解析得更快。 - jdi
没错。我在我的回答中添加了一些上下文,以指示他可能想在哪些情况下使用此解决方案。当他接受其中一个答案时,我们将会知道他的目标是什么。 - chees
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接