【问题标题】:Opening A large JSON file打开一个大的 JSON 文件
【发布时间】:2012-05-29 17:55:11
【问题描述】:

当我尝试使用json.load() 打开时,我有一个 1.7 GB 的 JSON 文件,然后出现内存错误,如何在 python 中读取 JSON 文件?

我的 JSON 文件是一个包含特定键的大型对象数组。

编辑:好吧,如果它只是一大堆对象,并且事先知道对象的结构,那么就不需要使用我们可以逐行读取的工具。一行将只包含数组的一个元素。我注意到这是 json 文件的存储方式,对我来说它只是:

>>>for line in open('file.json','r').readline():
...    do something with(line) 

【问题讨论】:

  • 为什么会有这么大的 JSON 文件?几乎总是作为一个整体读入内存的格式非常不适合像这样的大型结构。考虑将数据存储在数据库中。
  • 你想用这些数据做什么?它来自哪里?
  • 我可能应该将它们存储在不同的文件中,但没有这样做:(,我想使用该数据进行情绪分析。

标签: python json nltk


【解决方案1】:

我已将 Dask 用于大型遥测 JSON-Lines 文件(换行符分隔)...
Dask 的好处是它为您做了很多工作。
有了它,您可以读取数据、处理数据并写入磁盘,而无需将其全部读入内存。
Dask 还将为您并行化并使用多个内核(线程)...

这里有更多关于 Dask 包的信息:
https://examples.dask.org/bag.html

import ujson as json #ujson for speed and handling NaNs which are not covered by JSON spec
import dask.bag as db

def update_dict(d):
    d.update({'new_key':'new_value', 'a':1, 'b':2, 'c':0})
    d['c'] = d['a'] + d['b']
    return d

def read_jsonl(filepaths):
    """Read's a JSON-L file with a Dask Bag

    :param filepaths: list of filepath strings OR a string with wildcard
    :returns: a dask bag of dictionaries, each dict a JSON object
    """
    return db.read_text(filepaths).map(json.loads)



filepaths = ['file1.jsonl.gz','file2.jsonl.gz']
#OR
filepaths = 'file*.jsonl.gz' #wildcard to match multiple files

#(optional) if you want Dask to use multiple processes instead of threads
# from dask.distributed import Client, progress
# client = Client(threads_per_worker=1, n_workers=6) #6 workers for 6 cores
# print(client)

#define bag containing our data with the JSON parser
dask_bag = read_jsonl(filepaths)

#modify our data
#note, this doesn't execute, it just adds it to a queue of tasks
dask_bag.map(update_dict)

#(optional) if you're only reading one huge file but want to split the data into multiple files you can use repartition on the bag
# dask_bag = dask_bag.repartition(10)

#write our modified data back to disk, this is when Dask actually performs execution
dask_bag.map(json.dumps).to_textfiles('file_mod*.jsonl.gz') #dask will automatically apply compression if you use .gz

【讨论】:

    【解决方案2】:

    对于简单的用途(即遍历顶级数组中的项目),json-stream-parser 看起来不错(我没有使用它)。它似乎是一个用 234 行纯 Python 从头开始​​实现的独立 JSON 解析器。

    它不需要将 JSON 存储为“每行一个对象”或类似的东西。 JSON可以是一行,也可以有换行,没关系。

    用法:

    import sys
    from json_stream_parser import load_iter
    for obj in load_iter(sys.stdin):
        print(obj)
    

    【讨论】:

      【解决方案3】:

      我在 yajl 库周围找到了另一个 python 包装器,即ijson

      由于以下原因,它比 yajl-py 更适合我:

      • yajl-py 没有在我的系统上检测到 yajl 库,我必须破解代码才能使其工作
      • ijson 代码更紧凑,更易于使用
      • ijson 可以与 yajl v1 和 yajl v2 一起使用,它甚至还有 纯 python yajl 替换
      • ijson 有非常好的 ObjectBuilder,它不仅可以帮助从解析的流中提取事件,还可以提取有意义的子对象,并且在您指定的级别

      【讨论】:

        【解决方案4】:

        当从本地磁盘访问大数据文件时,我发现 yajl(因此 ijson)比模块 json 慢得多。这是一个声称在与 Cython 一起使用时性能优于 yajl/ijson(仍然比 json 慢)的模块:

        http://pietrobattiston.it/jsaone

        正如作者所指出的,当文件通过网络接收时,性能可能会优于json,因为增量解析器可以更快地开始解析。

        【讨论】:

          【解决方案5】:

          您需要一个增量 json 解析器,如 yajl 及其 python 绑定之一。增量解析器从输入中读取尽可能少的内容,并在解码有意义的内容时调用回调。例如,从一个大的 json 文件中只提取数字:

          class ContentHandler(YajlContentHandler):
              def yajl_number(self, ctx, val):
                   list_of_numbers.append(float(val))
          
          parser = YajlParser(ContentHandler())
          parser.parse(some_file)
          

          请参阅http://pykler.github.com/yajl-py/ 了解更多信息。

          【讨论】:

          • 我的 json 文件是一大堆对象,可以帮助我解析吗?
          • @HirakSarkar:是的。您需要在 ContentHandler 类中定义适当的回调。
          • 在 python shell 中通过 easy_install 安装 yajl 后,我遇到了有线问题,它给出了 yajl 模块不存在的错误。我该怎么办。我的python版本是2.6
          • 您需要先安装 yajl 并确保“libyajl.so”在您的库路径中。
          • 好的,我解决了安装问题。这是我所做的我在 /etc/ld.so.conf.d/ 创建了一个名为 libyajl.lib 的文件我存储了 yajl xxx/lib 路径的路径然后我执行 ldconfig 之后我安装了 yajl-py之后我运行 python import yajl 的源代码工作正常,除了版本不匹配的警告。我给开发者发邮件说这个问题,他说没问题。
          猜你喜欢
          • 2017-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-17
          • 2016-06-22
          • 1970-01-01
          • 2018-03-22
          • 1970-01-01
          相关资源
          最近更新 更多