2011-02-18 7 views
8

文書コレクションの検索エンジンの逆インデックスを作成しています。今、私は辞書の辞書としてインデックスを保存しています。つまり、各キーワードは、docIDs->発生位置の辞書にマップされます。cPickleを使用して大規模な辞書を直列化すると、MemoryErrorが発生します。

データモデルは次のようになります。 {単語:{doc_name:[location_list]}}

メモリにインデックスを構築する正常に動作しますが、私がディスクにシリアル化しようとすると、私は、MemoryErrorを打ちます。私のコードは次のとおりです。

# Write the index out to disk 
serializedIndex = open(sys.argv[3], 'wb') 
cPickle.dump(index, serializedIndex, cPickle.HIGHEST_PROTOCOL) 

私のプログラムは約50%のメモリ(1.6Gb)を使用しています。私がcPickleを呼び出すとすぐに、私のメモリ使用量はクラッシュする前に80%に急上昇します。

なぜcPickleはシリアル化に非常に多くのメモリを使用していますか?この問題に近づくための良い方法はありますか?

答えて

10

cPickleはサイクル検出を行うため、余分なメモリを使用する必要があります。データにサイクルがないと確信できる場合は、マーシャルモジュールを使用してみることができます。

+1

チャームのように働いた。信じられないほど単純な修正 - 基本的に "ピクル"を "マーシャル"に変更して完了しました。私はcPickleがサイクル検出を実行したことを認識しませんでした。マーシャルを使用することで、ディスクへの書き込みは20分ではなく数秒で完了し、メモリ消費量は30%から約0%に減少しました。ありがとう! –

+0

シンプルなソリューションと簡潔な説明、素晴らしい100%。 – mitchus

+0

おかげで、ありがとう@gnibbler! –

0

試してみることができる他のピクルスライブラリーがあります。変更可能なcPickle設定もあります。

その他のオプション:辞書を小さな部分に分割し、各部分をcPickleします。その後、すべてを読み込むときに一緒に戻してください。

申し訳ありませんが、これはあいまいです。私は頭の上に書いています。他に誰も答えてくれていないので、まだ役立つかもしれないと思いました。

0

このジョブでは、間違ったツールを使用している可能性があります。膨大な量の索引データを保持したい場合は、SQLObjectまたはSQL AlchemyのようなORMを持つSQLiteディスク上のデータベース(もちろん、通常のデータベースのみ)を使用することを強くお勧めします。私がいたので:あなたがメモリ不足になるよう

これらは...

を追加し、互換性などの日常的なものの世話をするために、フォーマットを最適化し、同時にメモリ内のすべてのデータを保持していないだろうとにかくほぼ同じことに取り組んでいますが、主に私はとても素敵な人ですから、必要なことをするデモが表示されます(現在のディレクトリにSQLiteファイルが作成されます。名前は既に存在するので、最初は空白にしてください):

import sqlobject 
from sqlobject import SQLObject, UnicodeCol, ForeignKey, IntCol, SQLMultipleJoin 
import os 

DB_NAME = "mydb" 
ENCODING = "utf8" 

class Document(SQLObject): 
    dbName = UnicodeCol(dbEncoding=ENCODING) 

class Location(SQLObject): 
    """ Location of each individual occurrence of a word within a document. 
    """ 
    dbWord = UnicodeCol(dbEncoding=ENCODING) 
    dbDocument = ForeignKey('Document') 
    dbLocation = IntCol() 

TEST_DATA = { 
    'one' : { 
     'doc1' : [1,2,10], 
     'doc3' : [6], 
    }, 

    'two' : { 
     'doc1' : [2, 13], 
     'doc2' : [5,6,7], 
    }, 

    'three' : { 
     'doc3' : [1], 
    }, 
}   

if __name__ == "__main__": 
    db_filename = os.path.abspath(DB_NAME) 
    if os.path.exists(db_filename): 
     os.unlink(db_filename) 
    connection = sqlobject.connectionForURI("sqlite:%s" % (db_filename)) 
    sqlobject.sqlhub.processConnection = connection 

    # Create the tables 
    Document.createTable() 
    Location.createTable() 

    # Import the dict data: 
    for word, locs in TEST_DATA.items(): 
     for doc, indices in locs.items(): 
      sql_doc = Document(dbName=doc) 
      for index in indices: 
       Location(dbWord=word, dbDocument=sql_doc, dbLocation=index) 

    # Let's check out the data... where can we find 'two'? 
    locs_for_two = Location.selectBy(dbWord = 'two') 

    # Or... 
    # locs_for_two = Location.select(Location.q.dbWord == 'two') 

    print "Word 'two' found at..." 
    for loc in locs_for_two: 
     print "Found: %s, p%s" % (loc.dbDocument.dbName, loc.dbLocation) 

    # What documents have 'one' in them? 
    docs_with_one = Location.selectBy(dbWord = 'one').throughTo.dbDocument 

    print 
    print "Word 'one' found in documents..." 
    for doc in docs_with_one: 
     print "Found: %s" % doc.dbName 

これはcertですこれを行うための唯一の方法(または必然的に最良の方法)ではありません。 DocumentテーブルまたはWordテーブルをLocationテーブルとは別のテーブルにする必要があるかどうかは、データと一般的な使用方法によって異なります。あなたの場合、「Word」テーブルはおそらくインデックス作成と一意性に関するいくつかの設定が追加された別個のテーブルになる可能性があります。

+0

お寄せいただきありがとうございます。今のところ、pickleの代わりにマーシャリングを使用するつもりですが、これを再訪し、将来dbベースのソリューションに移行する可能性があります。乾杯! –

+0

@Stephen Poletto - marhsalが動作すればそれはクールだ、それは動作し、これは後世のためにここに残ることができる:) – detly

関連する問題