1

小さな辞書をシリアル化するために多くのソリューションがあります。json.loads/json.dumpspickleshelveujson、あるいはsqliteを使用しては。キー:クライアント/サーバーのないデータの可能性が100ギガバイトのためのPythonでvalueストア、

しかし、おそらく100 GBのデータを扱う場合、閉じる/シリアライズ時にデータ全体を書き換える可能性のあるモジュールを使用することはできません。

redisは、クライアント/サーバー方式を使用しているため実際にはオプションではありません。

質問:100+ GBのデータを扱うことができる、サーバーではないバリューストアがPythonで頻繁に使用されていますか?

import mydb 
d = mydb.mydb('myfile.db') 
d['hello'] = 17   # able to use string or int or float as key 
d[183] = [12, 14, 24] # able to store lists as values (will probably internally jsonify it?) 
d.flush()    # easy to flush on disk 

注:私は、標準の "Python的" d[key] = valueの構文で解決策を探しています

BsdDB(BerkeleyDBの)が廃止されるようです。 LevelDB for Pythonがあるようですが、よく知られているようには見えません。また、Windows上で使用できるようになっているバージョンのhaven't foundもあります。どちらが最も一般的なものでしょうか?

+3

SQLiteのは、偉大な動作するはずです。それを使用する際に問題がありましたか?そのDBMSは小さくても、DB自体が大きくなる可能性があります。 https://stackoverflow.com/questions/14451624/will-sqlite-performance-degrade-if-the-database-size-is-greater-than-2-ギガバイト – Himanshu

+0

@Himanshu SQLiteでの使用法は実際にはありません'db [key] = value'や' db.put( 'key'、 'value') 'のように単純ですが、代わりにSQLを使っています...そして、私はTABLEやSELECTにINSERTを避けたいのです。単純なキーです:value 'db [key] = value' set/get。 – Basj

+0

データをより詳しく記述できますか? 100 GBの何?最小値/中央値/最大値の大きさはどれくらいですか? 100 GBを構成するキー/バリューペア数はいくつですか? –

答えて

4

あなたはSQLiteデータベースにキーと値のインターフェースを提供しsqlitedictを使用することができます。

SQLite limits pageは、page_sizemax_page_countに応じて、理論上の最大値は140TBです。しかし、Python 3.5.2-2ubuntu0〜16.04.4(sqlite3 2.6.0)のデフォルト値はpage_size=1024max_page_count=1073741823です。これにより、〜1100 GBの最大データベースサイズが得られます。

あなたのようなパッケージを使用することができます。メモリ使用量について

from sqlitedict import SqliteDict 

mydict = SqliteDict('./my_db.sqlite', autocommit=True) 
mydict['some_key'] = any_picklable_object 
print(mydict['some_key']) 
for key, value in mydict.items(): 
    print(key, value) 
print(len(mydict)) 
mydict.close() 

更新

。 SQLiteでは、データセットがRAMに収まる必要はありません。デフォルトでは最大でcache_sizeページをキャッシュします。これはわずか2MiBです(上記と同じPython)。あなたのデータで確認するために使用できるスクリプトは次のとおりです。実行する前に:

pip install lipsum psutil matplotlib psrecord sqlitedict 

sqlitedct.py

#!/usr/bin/env python3 

import os 
import random 
from contextlib import closing 

import lipsum 
from sqlitedict import SqliteDict 

def main(): 
    with closing(SqliteDict('./my_db.sqlite', autocommit=True)) as d: 
     for _ in range(100000): 
      v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)] 
      d[os.urandom(10)] = v 

if __name__ == '__main__': 
    main() 

./sqlitedct.py & psrecord --plot=plot.png --interval=0.1 $!のようなファイル名を指定して実行して。私のケースでは、このチャートを生成します。 chart

そして、データベースファイル:

$ du -h my_db.sqlite 
84M my_db.sqlite 
+0

非常にいいベンチマーク、ありがとう@サア!好奇心を持っていること:「閉じる(...)」とは何ですか?: 'する? – Basj

+0

グラフのCPUのy軸は0〜200%、平均150%、y軸は正しいですか? – Basj

+0

@Basj 1)['contextlib.closing'](https://docs.python.org/3/library/contextlib.html#contextlib.closing)。 2) 'sqlite3'は' _sqlite3'バイナリで動作しているときにGILをリリースする独自のスレッドを作成するので、それはだと思います。それは100%以上になります。 – saaj

3

これはHDF5と考えています。それにはいくつかの利点があります。

  • 多くのプログラミング言語から使用できます。
  • 優れたh5pyパッケージを使用してPythonから使用できます。
  • 大きなデータセットを含め、バトルテストが行​​われました。
  • 可変長の文字列値をサポートします。
  • 値は、ファイルシステムのような「パス」(/foo/bar)によってアドレス指定できます。
  • 値は配列にできます(通常はそうですが、必ずしもそうである必要はありません)。
  • オプションの組み込み圧縮。
  • オプションでチャンクを徐々に書き込むことを許可する "チャンク"。
  • データセット全体を一度にメモリにロードする必要はありません。

それはあまりにもいくつかの欠点を持っている:それは難しい、単一のアプローチを定義することのポイントに、

  • を非常に柔軟。
  • 公式のHDF5 Cライブラリなしでは使用できない複雑なフォーマットです(ただし、多くのラッパーがあります(例:h5py)。
  • バロックC/C++ API(Pythonはそうではありません)。
  • 並行ライター(またはライター+リーダー)はほとんどサポートされていません。書き込みは、粗粒度でロックする必要があります。

あなたは、単一のファイル(または実際には複数のそのようなファイル)内の階層内の値(スカラーまたはN次元 配列)を格納するための方法として、HDF5と考えることができます。単一のディスクファイルに値を格納するだけの最大の問題は、いくつかのファイルシステムを圧倒することです。 1つの "ディレクトリ"に100万の値を入れたときに落ちることのないファイル内のファイルシステムとしてHDF5を考えることができます。

+1

HDF5はデータベースではなく、シリアル化形式です。全体をメモリにロードする必要があります。 – amirouche

+0

ありがとうございます。 (編集された)質問のように、それを使用する方法を示す3行または4行のコードを含めることができますか?すなわち 'import ...'を実行した後、DBを作成して 'd [key] = value'を作成し、それをディスクにフラッシュします。 – Basj

+0

@amirouche:明らかにHDF5はデータベースではありません。質問はデータベースを要求しませんでした。 HDF5では、スライス、ハイパースラブ、単一の配列や属性を階層的なファイルなどに読み込むことができます。メモリには何もロードする必要はありません。とにかくOPのデータは100GBのオーダーであり、100GBのメインメモリはコモディティサーバや最近のデスクトップでも簡単に見つかります。 –

0

まず、bsddb(またはその名前がOracle BerkeleyDBの下にある)は非推奨ではありません。

LevelDB/RocksDB/bsddbの経験がwiredtigerより遅いので、私はwiredtigerを推奨しています。

wiredtigerはmongodbのストレージエンジンなので、実稼働環境で十分にテストされています。私のAjguDBプロジェクトの外では、Pythonでwiredtigerをほとんどまたは全く使用していません。私は約80GBのwikidataとコンセプトを格納して照会するためにwiredtiger(AjguDB経由)を使用します。

ここでは、python2 shelveモジュールを模倣できるクラスの例を示します。ここで

import json 

from wiredtiger import wiredtiger_open 


WT_NOT_FOUND = -31803 


class WTDict: 
    """Create a wiredtiger backed dictionary""" 

    def __init__(self, path, config='create'): 
     self._cnx = wiredtiger_open(path, config) 
     self._session = self._cnx.open_session() 
     # define key value table 
     self._session.create('table:keyvalue', 'key_format=S,value_format=S') 
     self._keyvalue = self._session.open_cursor('table:keyvalue') 

    def __enter__(self): 
     return self 

    def close(self): 
     self._cnx.close() 

    def __exit__(self, *args, **kwargs): 
     self.close() 

    def _loads(self, value): 
     return json.loads(value) 

    def _dumps(self, value): 
     return json.dumps(value) 

    def __getitem__(self, key): 
     self._session.begin_transaction() 
     self._keyvalue.set_key(key) 
     if self._keyvalue.search() == WT_NOT_FOUND: 
      raise KeyError() 
     out = self._loads(self._keyvalue.get_value()) 
     self._session.commit_transaction() 
     return out 

    def __setitem__(self, key, value): 
     self._session.begin_transaction() 
     self._keyvalue.set_key(key) 
     self._keyvalue.set_value(self._dumps(value)) 
     self._keyvalue.insert() 
     self._session.commit_transaction() 

@saaj答えから適応テストプログラム:

python test-wtdict.py & psrecord --plot=plot.png --interval=0.1 $! 
:次のコマンドラインを使用して

#!/usr/bin/env python3 

import os 
import random 

import lipsum 
from wtdict import WTDict 


def main(): 
    with WTDict('wt') as wt: 
     for _ in range(100000): 
      v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)] 
      wt[os.urandom(10)] = v 

if __name__ == '__main__': 
    main() 

基本的には、 それはキーが文字列のみ可能wiredtigerバックエンドの辞書です

私は次の図を生成しました:

$ du -h wt 
60M wt 

先行書き込みログが有効になっているwt performance without walは:

wt performance with wal

$ du -h wt 
260M wt 

これは、パフォーマンス細くおよび圧縮なしです。最近、文書は次のように更新されるまで

Wiredtigerは全く知られている制限はありません。

WiredTigerはペタバイトのテーブルをサポートし、64ビットまで4ギガバイト、およびレコード番号まで記録されます。

http://source.wiredtiger.com/1.6.4/architecture.html

+0

ありがとうございます。 'wiredtiger'を使ってコードの例を挙げられますか?あなたは 'import wiretiger'のような単純なAPIでそれを使うことができますか?wt [wired hello] = 17' wt [183]​​ = [12,14、 1) 'wt [key] = value'構文2)文字列またはintまたはfloatをキーとして使用できる3)リストを値として格納できる4)簡単にディスク上でフラッシュする – Basj

+0

Python 2またはPython 3用ですか? – amirouche

+0

私はPython 2 @amiroucheを使用します。 – Basj

関連する問題