12

ネストされた python 辞書の形で完全な逆インデックスがあります。その構造は次のとおりです。

{word : { doc_name : [location_list] } }

たとえば、辞書の名前を index とすると、「 spam 」という単語のエントリは次のようになります。

{ spam : { doc1.txt : [102,300,399], doc5.txt : [200,587] } }

Python dict はかなり最適化されており、プログラミングが容易になるため、この構造を使用しました。

任意の単語「スパム」について、それを含むドキュメントは次のように指定できます。

index['spam'].keys()

ドキュメント doc1 の投稿リスト:

index['spam']['doc1']

現在、cPickle を使用してこの辞書を保存およびロードしています。しかし、ピクルス化されたファイルは約 380 MB で、読み込みに長い時間がかかります - 112 秒 (約time.time()を使用して時間を計測しました) で、メモリ使用量は 1.2 GB になります (Gnome システム モニター)。ロードしたら、問題ありません。私は4GBのRAMを持っています。

len(index.keys())229758を与える

コード

import cPickle as pickle

f = open('full_index','rb')
print 'Loading index... please wait...'
index = pickle.load(f)  # This takes ages
print 'Index loaded. You may now proceed to search'

読み込みを速くする方法を教えてください。アプリケーションの起動時に一度だけロードする必要があります。あとは、クエリに応答するためのアクセス時間が重要です。

SQLite のようなデータベースに切り替えて、そのキーにインデックスを作成する必要がありますか? はいの場合、同等のスキーマを持つように値を保存する方法を教えてください。これにより、取得が容易になります。他に調べるべきことはありますか?

補遺

ティムの答えを使用pickle.dump(index, file, -1)すると、ピクルス化されたファイルはかなり小さくなります-約237 MB(ダンプに300秒かかりました)...そしてロードに半分の時間がかかります(61秒...以前の112秒とは対照的に.... time.time () )

しかし、スケーラビリティのためにデータベースに移行する必要がありますか?

今のところ、Tim の回答を承認済みとしてマークしています。

PS :Lucene や Xapian は使いたくない... この質問は、逆インデックスの保存に関するものです。以前の質問を削除できなかったので、新しい質問をしなければなりませんでした。

4

5 に答える 5

13

cPickle.dump/を使用する場合は、プロトコル引数を試してくださいcPickle.dumps。差出人cPickle.Pickler.__doc__

Pickler(file、protocol = 0)-ピクラーを作成します。

これは、ピクルスデータストリームを書き込むためのファイルのようなオブジェクトを取ります。オプションのproto引数は、指定されたプロトコルを使用するようにピッカーに指示します。サポートされているプロトコルは0、1、2です。下位互換性を保つために、デフォルトのプロトコルは0です。(プロトコル0は、テキストモードで開いたファイルに書き込み、正常に読み戻すことができる唯一のプロトコルです。0より大きいプロトコルを使用する場合は、ピクルスとアンピクルの両方で、ファイルがバイナリモードで開かれていることを確認してください。)

プロトコル1はプロトコル0よりも効率的です。プロトコル2はプロトコル1よりも効率的です。

負のプロトコルバージョンを指定すると、サポートされている最高のプロトコルバージョンが選択されます。使用するプロトコルが高いほど、生成されたピクルスを読み取るために必要なPythonのバージョンは新しくなります。

fileパラメータには、単一の文字列引数を受け入れるwrite()メソッドが必要です。したがって、開いているファイルオブジェクト、StringIOオブジェクト、またはこのインターフェイスを満たすその他のカスタムオブジェクトにすることができます。

JSONまたはYAMLの変換は、ほとんどの場合、pickle化よりも時間がかかる可能性があります。pickleはネイティブPython型を格納します。

于 2010-10-18T09:33:51.680 に答える
7

一度にすべてをロードする必要がありますか? メモリ内のすべてを必要とせず、いつでも必要な選択部分のみが必要な場合は、辞書を単一のファイルではなくディスク上のファイルのセットにマップするか、dict をデータベース テーブル。したがって、大量のデータ ディクショナリをディスクまたはデータベースに保存し、ピクルとエンコーディング (コーデックとハッシュマップ) を利用できるものを探している場合は、klepto.

kleptoファイルシステムをデータベースとして扱う (つまり、辞書全体を単一のファイルに書き込む、または各エントリを独自のファイルに書き込む) など、データベースに書き込むための辞書の抽象化を提供します。大きなデータの場合、辞書をファイル システムのディレクトリとして表し、各エントリをファイルにすることがよくあります。 kleptoはキャッシュ アルゴリズムも提供するため、辞書にファイル システム バックエンドを使用している場合は、メモリ キャッシュを利用することで速度の低下を回避できます。

>>> from klepto.archives import dir_archive
>>> d = {'a':1, 'b':2, 'c':map, 'd':None}
>>> # map a dict to a filesystem directory
>>> demo = dir_archive('demo', d, serialized=True) 
>>> demo['a']
1
>>> demo['c']
<built-in function map>
>>> demo          
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> # is set to cache to memory, so use 'dump' to dump to the filesystem 
>>> demo.dump()
>>> del demo
>>> 
>>> demo = dir_archive('demo', {}, serialized=True)
>>> demo
dir_archive('demo', {}, cached=True)
>>> # demo is empty, load from disk
>>> demo.load()
>>> demo
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> demo['c']
<built-in function map>
>>> 

kleptocompressionやなどの他のフラグもありmemmode、データの保存方法 (圧縮レベル、メモリ マップ モードなど) をカスタマイズするために使用できます。ファイルシステムの代わりに (MySQL などの) データベースをバックエンドとして使用することも同様に簡単です (まったく同じインターフェイス)。メモリ キャッシュをオフにすることもできるので、設定するだけですべての読み取り/書き込みがアーカイブに直接送信されますcached=False

kleptoカスタムkeymap.

>>> from klepto.keymaps import *
>>> 
>>> s = stringmap(encoding='hex_codec')
>>> x = [1,2,'3',min]
>>> s(x)
'285b312c20322c202733272c203c6275696c742d696e2066756e6374696f6e206d696e3e5d2c29'
>>> p = picklemap(serializer='dill')
>>> p(x)
'\x80\x02]q\x00(K\x01K\x02U\x013q\x01c__builtin__\nmin\nq\x02e\x85q\x03.'
>>> sp = s+p
>>> sp(x)
'\x80\x02UT28285b312c20322c202733272c203c6275696c742d696e2066756e6374696f6e206d696e3e5d2c292c29q\x00.' 

kleptoまた、メモリ内キャッシュの管理に役立つ多くのキャッシュ アルゴリズム ( mrulrulfuなど) を提供し、アルゴリズムを使用してダンプを実行し、アーカイブ バックエンドにロードします。

このフラグcached=Falseを使用してメモリ キャッシュを完全にオフにし、ディスクまたはデータベースに対して直接読み書きすることができます。エントリが十分に大きい場合は、各エントリを独自のファイルに配置するディスクに書き込むことを選択できます。両方を行う例を次に示します。

>>> from klepto.archives import dir_archive
>>> # does not hold entries in memory, each entry will be stored on disk
>>> demo = dir_archive('demo', {}, serialized=True, cached=False)
>>> demo['a'] = 10
>>> demo['b'] = 20
>>> demo['c'] = min
>>> demo['d'] = [1,2,3]

ただし、これによりロード時間が大幅に短縮されるはずですが、全体的な実行速度が少し低下する可能性があります。通常は、メモリ キャッシュに保持する最大量を指定し、適切なキャッシュ アルゴリズムを選択することをお勧めします。ニーズに合った適切なバランスを得るには、それをいじる必要があります。

kleptoここにアクセスしてください: https://github.com/uqfoundation

于 2014-08-11T13:42:40.720 に答える
3

Python 2.x での一般的なパターンは、モジュールの 1 つのバージョンを純粋な Python で実装し、オプションで高速化されたバージョンを C 拡張として実装することです。たとえば、picklecPickle. これにより、高速化されたバージョンをインポートし、これらのモジュールの各ユーザーに純粋な Python バージョンにフォールバックする負担がかかります。Python 3.0では、高速化されたバージョンは純粋な Python バージョンの実装の詳細と見なされます。ユーザーは常に標準バージョンをインポートする必要があります。標準バージョンは高速バージョンのインポートを試み、純粋な Python バージョンにフォールバックします。 pickle / cPickle のペアはこの処理を受けました。

  • プロトコル バージョン 0 は、元の「人間が判読できる」プロトコルであり、以前のバージョンの Python と下位互換性があります。
  • プロトコル バージョン 1 は古いバイナリ形式で、以前のバージョンの Python とも互換性があります。
  • プロトコル バージョン 2 は Python 2.3 で導入されました。新しいスタイルのクラスのより効率的な酸洗を提供します。プロトコル 2 によってもたらされる改善については、PEP 307 を参照してください。
  • プロトコル バージョン 3は Python 3.0 で追加されました。これはバイト オブジェクトを明示的にサポートしており、Python 2.x では unpickle できません。これはデフォルトのプロトコルであり、他の Python 3 バージョンとの互換性が必要な場合に推奨されるプロトコルです。
  • プロトコル バージョン 4 は Python 3.4 で追加されました。非常に大きなオブジェクトのサポート、より多くの種類のオブジェクトのピクル、およびいくつかのデータ形式の最適化が追加されています。プロトコル 4 による改善点については、 PEP 3154を参照してください。

辞書が巨大で、Python 3.4 以降とのみ互換性がある必要がある場合は、次を使用します。

pickle.dump(obj, file, protocol=4)
pickle.load(file, encoding="bytes")

また:

Pickler(file, 4).dump(obj)
Unpickler(file).load()

とは言うものの、2010 年jsonには、このモジュールは、単純型のエンコードで 25 倍、デコードで 15 倍高速でしpickleた。私の 2014 年のベンチマークではmarshal>>と表示されていpickleますjsonmarshal's、特定の Python バージョンと結合しています。

于 2014-11-11T12:42:24.053 に答える
0

'long'の長さに応じて、行う必要のあるトレードオフについて検討する必要があります。(長い)起動後にすべてのデータをメモリに準備するか、部分的なデータのみをロードします(その後、日付を分割する必要があります。複数のファイルを使用するか、SQLiteなどを使用してください)。たとえばsqliteから辞書にすべてのデータを事前にロードすることで改善がもたらされるとは思えません。

于 2010-10-18T09:36:26.917 に答える
0

YAMLJSONなどの代替ストレージ形式を使用してみましたか? jsonPython は、私が思うモジュールを使用して Python 2.6 から JSON をネイティブにサポートし、YAML 用のサードパーティ モジュールがあります。

shelveモジュールを試すこともできます。

于 2010-10-18T09:16:10.273 に答える