在Python中打开大型JSON文件

在Python中打开大型JSON文件,python,json,nltk,Python,Json,Nltk,当我试图用JSON.load()打开时,我有一个1.7GB的JSON文件,然后它给出了内存错误,如何用python读取JSON文件 我的JSON文件是一个包含特定键的大型对象数组 编辑:如果它只是一个大的对象数组,并且事先知道对象的结构,那么就不需要使用工具,我们可以逐行读取它。一行只包含数组的一个元素。我注意到这就是json文件的存储方式,对我来说,它就像 >>>for line in open('file.json','r').readline(): ... do s

当我试图用JSON.load()打开时,我有一个1.7GB的JSON文件,然后它给出了内存错误,如何用python读取JSON文件

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

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

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

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

class ContentHandler(YajlContentHandler):
    def yajl_number(self, ctx, val):
         list_of_numbers.append(float(val))

parser = YajlParser(ContentHandler())
parser.parse(some_file)

有关更多信息,请参阅。

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

由于以下原因,它对我更有效:

  • yajl py没有在我的系统上检测到yajl库,我不得不破解代码以使其正常工作
  • ijson代码更紧凑,更易于使用
  • ijson可以同时使用yajl v1和yajl v2,它甚至有纯python的yajl替换
  • ijson有非常好的ObjectBuilder,它不仅可以帮助从解析流中提取事件,还可以在您指定的级别上提取有意义的子对象
当从本地磁盘访问大型数据文件时,我发现yajl(因此ijson)比module
json
慢得多。这是一个声称与Cython一起使用时性能优于yajl/ijson(仍然比
json
慢)的模块:

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

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

它不需要将JSON存储为“每行一个对象”或类似的内容。JSON可以是一行,也可以有换行符,这并不重要

用法:

导入系统 从json\u流\u解析器导入加载\u iter 对于负载中的obj(系统标准): 打印(obj)
我已将Dask用于大型遥测JSON行文件(以换行符分隔).
Dask的好处在于它为您做了很多工作。
使用它,您可以读取数据、处理数据并写入磁盘,而无需将数据全部读入内存。
Dask还将为您并行化并使用多个内核(线程)

有关Dask行李的更多信息,请点击此处:


为什么有这么大的JSON文件?一种几乎总是作为一个整体读入内存的格式非常不适合这样的大型结构。考虑将数据存储在数据库中。你想用这些数据做什么?它来自哪里?我可能应该将它们存储在不同的文件中,但没有这样做:(,我想使用这些数据进行情绪分析。我的json文件是一个大的对象数组,这有助于我分析吗?@HirakSarkar:是的。你需要在ContentHandler类中定义适当的回调。我甚至在python shell中通过easy_install安装yajl之后,都遇到了一个有线问题。这会导致错误,因为yajl模块不在那里。W我该怎么办呢?我的python版本是2.6。你需要先安装yajl,并确保“libyajl.so”在你的库路径中。好的,我解决了安装问题。下面是我所做的我在/etc/ld.so.conf.d/创建了一个名为libyajl.lib的文件在那里我存储了yajl x.x.x/lib路径,然后我做了一个ldconfig,之后我从源代码安装了yajl-py,之后我运行了python import,除了版本不匹配的警告外,yajl工作正常h、 我就那个问题给开发者发了邮件,他说没问题。
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