小さな辞書をシリアル化する多くの解決策があります:json.loads
/json.dumps
、pickle
、shelve
、ujson
、またはsqlite
。
しかし、おそらく100 GBのデータを処理する場合、閉じる/シリアル化するときにデータ全体を書き換える可能性のあるモジュールを使用することはできなくなります。
redis
はクライアント/サーバースキームを使用するため、実際にはオプションではありません。
質問:Pythonで頻繁に使用されるキー:値ストア、サーバーレス、100 GB以上のデータを処理できるものはどれですか?
標準の「Pythonic」d[key] = value
構文のソリューションを探しています。
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
注: BsdDB (BerkeleyDB)は推奨されないようです。 PythonのLevelDB があるようですが、それはよく知られていないようです-そして 見つかりません Windowsで使用する準備ができているバージョンです。最も一般的なものはどれですか?
SQLiteデータベースへのキーと値のインターフェイスを提供する sqlitedict を使用できます。
SQLite 制限ページ は、理論上の最大値が140 TB page_size
とmax_page_count
によって異なる]と述べています。ただし、Python 3.5.2-2ubuntu0〜16.04.4(sqlite3
2.6.0)はpage_size=1024
とmax_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 $!
のように実行します。私の場合、それはこのチャートを生成します:
そしてデータベースファイル:
$ du -h my_db.sqlite
84M my_db.sqlite
HDF5 を検討します。これにはいくつかの利点があります。
/foo/bar
)でアドレス指定できます。また、いくつかの欠点もあります。
h5py
)。).HDF5は、単一のファイル(または実際には複数のファイル)内の階層内に値(スカラーまたはN次元配列)を格納する方法と考えることができます。値を単一のディスクファイルに格納するだけの場合の最大の問題は、一部のファイルシステムを圧倒することです。 HDF5は、1つの「ディレクトリ」に100万個の値を入れても落ちないファイル内のファイルシステムと考えることができます。
まず、bsddb(またはその新しい名前のOracle BerkeleyDB)は非推奨ではありません。
経験から、LevelDB/RocksDB/bsddbは wiredtiger よりも遅いため、wiredtigerをお勧めします。
ワイヤードタイガーはmongodbのストレージエンジンであるため、本番環境で十分にテストされています。 Python私のAjguDBプロジェクトの外では、wiredtigerをほとんど、またはまったく使用していません。私は(AjguDBを介して)wiredtigerを使用して、約80GBのウィキデータと概念を格納およびクエリしています。
以下は、python2 shelve モジュールを模倣できるクラスの例です。基本的に、それはキーが文字列のみであるwiredtigerバックエンド辞書です:
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の回答からの適応テストプログラム:
#!/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()
次のコマンドラインを使用します。
python test-wtdict.py & psrecord --plot=plot.png --interval=0.1 $!
次の図を生成しました。
$ du -h wt
60M wt
ログ先行書き込みがアクティブな場合:
$ du -h wt
260M wt
これには、パフォーマンスの調整と圧縮がありません。
Wiredtigerには、最近まで既知の制限がありませんでした。ドキュメントは次のように更新されました。
WiredTigerは、ペタバイトテーブル、最大4GBのレコード、最大64ビットのレコード数をサポートしています。