web-dev-qa-db-ja.com

Pythonで大きなjsonファイルをロードするためのメモリ効率の良い高速な方法はありますか?

500MBのjsonファイルがいくつかあります。 「些細な」json.loadを使用してコンテンツを一度にロードすると、大量のメモリを消費します。

ファイルを部分的に読み取る方法はありますか?それがテキストの行区切りファイルである場合、行を反復処理できます。私はそれに類似を探しています。

助言がありますか?ありがとう

56
duduklein

この質問には、より良い回答があった重複がありました。 https://stackoverflow.com/a/10382359/1623645 を参照してください。これは ijson を示唆しています。

更新:

試してみましたが、ijsonはJSONに対して、SAXはXMLに対してです。たとえば、これを行うことができます:

import ijson
for prefix, the_type, value in ijson.parse(open(json_file_name)):
    print prefix, the_type, value

ここで、prefixは、JSONツリー内のドット区切りインデックスです(キー名にドットが含まれている場合はどうなりますか?Javascriptにとっても悪いことでしょう...)、theType'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array'の1つであるSAXのようなイベントを記述し、valueはオブジェクトの値、またはthe_typeがマップの開始/終了のようなイベントの場合はNone /アレイ。

プロジェクトにはいくつかのdocstringsがありますが、グローバルなドキュメントは不十分です。 ijson/common.pyを掘り下げて、探していたものを見つける必要がありました。

71
Jim Pivarski

そのため、問題は各ファイルが大きすぎることではなく、ファイルが多すぎることであり、メモリに追加されているようです。 Pythonのガベージコレクターは、不要な参照を保持している場合を除き、問題ないはずです。詳しい情報がなければ何が起こっているのかを正確に伝えることは困難ですが、次のことを試すことができます。

  1. コードをモジュール化します。次のようなことをしてください:

    for json_file in list_of_files:
        process_file(json_file)
    

    グローバル状態に依存せず、グローバル状態を変更しないような方法でprocess_file()を記述した場合、ガベージコレクターはその役割を果たせるはずです。

  2. 個別のプロセスで各ファイルを処理します。すべてのJSONファイルを一度に解析する代わりに、1つだけを解析するプログラムを作成し、シェルスクリプト、またはsubprocess.Popenを介してスクリプトを呼び出す別のpythonプロセスから各ファイルを渡します。エレガントさはやや劣りますが、他に何も機能しない場合、あるファイルから次のファイルへの古いデータを保持しないようにします。

お役に立てれば。

14
jcdyer

はい。

jsonstreamerを使用できます。これは、任意のサイズのチャンクを解析できるように記述したSAXのようなプッシュパーサーです。 get here そしてREADME=をチェックアウトしてください。'C 'yajlライブラリを使用しているため高速です。

8
kashif

メモリ不足についての言及で、実際にメモリを管理しているのかどうか質問しなければなりません。 「del」キーワードを使用して、新しいオブジェクトを読み取ろうとする前に古いオブジェクトを削除していますか? Python削除した場合、何かを静かにメモリに保持してはいけません。

3
Aea

「ガベージコレクターはメモリを解放する必要があります」

正しい。

そうではないので、他の何かが間違っています。一般的に、無限のメモリ増加の問題はグローバル変数です。

すべてのグローバル変数を削除します。

すべてのモジュールレベルのコードをより小さな関数にします。

3
S.Lott

別のアイデアは、MongoDBのようなドキュメントストアデータベースにロードすることです。 JSONの大きな塊をうまく処理します。 JSONのロードと同じ問題が発生する場合がありますが、ファイルを1つずつロードすることで問題を回避してください。

パスが機能する場合は、クライアントを介してJSONデータとやり取りでき、潜在的にblob全体をメモリに保持する必要はありません。

http://www.mongodb.org/

2
George Godik

@codeapeに加えて

カスタムJSONパーサーを作成して、処理しているJSON BLOBの構造を把握できるようにしてみます。キー名のみなどを印刷します。階層ツリーを作成し、それをチャンクする方法を(自分で)決定します。この方法で、@ codeapeが提案することを実行できます-ファイルを小さなチャンクなどに分割します

1
George Godik