8

ドキュメントのコレクションに検索エンジンの転置インデックスを書いています。現在、辞書の辞書としてインデックスを保存しています。つまり、各キーワードはdocID->出現位置の辞書にマップされます。

データモデルは次のようになります。{word:{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.6 Gb)を使用しています。cPickleを呼び出すとすぐに、クラッシュする前にメモリ使用量が80%に急上昇します。

cPickleがシリアル化に大量のメモリを使用するのはなぜですか?この問題に取り組むためのより良い方法はありますか?

4

3 に答える 3

10

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

于 2011-02-18T04:38:59.493 に答える
0

あなたが試すことができる他のピクルスライブラリがあります。また、変更できるcPickle設定がある場合もあります。

その他のオプション:辞書を細かく分割し、各部分をcPickleします。次に、すべてをロードするときにそれらを元に戻します。

申し訳ありませんが、これはあいまいです。頭のてっぺんから書き留めているだけです。誰も答えていないので、それでも役立つかもしれないと思いました。

于 2011-02-18T04:37:27.133 に答える
0

このジョブに間違ったツールを使用している可能性があります。大量のインデックス付きデータを保持したい場合は、SQLite オンディスク データベース (または、もちろん通常のデータベース) をSQLObjectSQL Alchemyなどの ORM と共に使用することを強くお勧めします。

これらは、互換性、目的に合わせたフォーマットの最適化、すべてのデータを同時にメモリに保持しないなどのありふれたことを処理して、メモリが不足するようにします...

追加:とにかくほぼ同じことに取り組んでいましたが、主に私はとてもいい人なので、必要なことを行うように見えるデモを次に示します (現在のディレクトリに 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

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

于 2011-02-18T05:54:17.870 に答える