LoginSignup
51
50

More than 5 years have passed since last update.

PythonでLevelDBを使ってみる(plyvel)

Last updated at Posted at 2015-01-15

LevelDBとは?

ファイルに保存するタイプのkey-value storeで、key => valueのひも付けを高速に読み書きできるGoogle製のライブラリです。PythonのここではLevelDBをplyvelというライブラリを使ってpythonで使ってみるチュートリアルをご紹介します。(plyvel以外にもPythonのLevelDBライブラリは存在しますが、使ってみた感じplyvelの出来がよさそうでしたので)

こういうたぐいのものでは古くはBerkeleyDBや、モダンなものだと日本の平林さんが作成されたKyotoCabinetが有名です。サーバ型ではmemcachedRedisがありますが、LevelDBはサーバ型ではなく、ローカルのファイルを操作するライブラリです。たくさんのサーバ・プロセスなどからkey-valueのデータを共有して保存したいときはmemcachedやKyotoTycoon, Redisなどの方が向いているでしょう。

Pythonにはキーに値をひもづけて管理するデータ構造としてdictがありますが、メモリ上に乗り切らない大量のデータなどを扱いたいときに便利なライブラリです。

事前知識

  • LevelDBはあるバイト列であるkeyに, あるバイト列であるvalueをひもづけて管理するkey-value store。keyからvalueを高速にルックアップすることができる。
  • LevelDBのデータベースはディレクトリになっている。
  • LevelDBデータベースは同時にたかだか1つのプロセスでしか開けない。(既に別のプロセスが開いているとエラーになる)
  • サーバではないので、通信でkey-valueを操作するものではない。(ローカルのファイルを操作するライブラリである。)
  • plyvelはnativeのleveldbのライブラリを使っているC拡張で実装されている(ゆえに速いがライブラリのインストールとコンパイルが必要)
  • LevelDBのキーと値にはバイナリ値を与えることになる。
    • 保存したい値がstringではない場合はpickleやmsgpackなど、なんらかの方法でシリアライズする必要がある
    • pythonのunicode型の値はval.encode('utf-8')などでバイナリにエンコードしてあげる必要あり

インストール(1/2)

まずleveldbのネイティブライブラリが必要なのでインストールします。MacでHomebrewを使っている人はbrewで入れると楽です。

$ brew install leveldb

他のプラットフォームではMakefileがあるようですので、makesudo make installでインストールできるのではないでしょうか。

インストール(2/2)

plyvelをインストールしましょう。なんでこんな綴りかよくわからないですが、とにかくplyvelです。

$ pip install plyvel

システムのincludeパスにPython.hがなかったりすると拡張ライブラリがコンパイルできなくてエラーになるかもしれません。Linuxならpython-develなどのパッケージが入ってるか確認してみるとよいでしょう。

DBをopenしてcloseしてみる

LevelDBのデータベースはディレクトリになってるので注意。

import plyvel
my_db = plyvel.DB('/tmp/test.ldb', create_if_missing=True)  # なければつくる
my_db.close()

create_if_missing=Falseの場合、DBファイルが存在しなければ例外が発生します。

key => valueを登録する

LevelDBはバイト列にバイト列をひもづけることしかできないので基本は以下のようになります。

my_db.put('key1', 'value1')
my_db.put(u'ほげ'.encode('utf-8'), u'ほげバリュー'.encode('utf-8'))  # unicodeを使うときはバイト列にする

あるキーに、複雑なデータ構造をひもづけて保存したいときは下記のpickleやMessagePackを使う方法を試してみてください。

keyから値を取り出す

そのまんま、getしてください。

value1 = my_db.get('key1')
value2 = my_db.get(u'ユニコードのキーはencodeでバイト列にする'.encode('utf-8'))

keyを削除

deleteメソッドで消します。

my_db.delete('key1')
my_db.delete(u'ユニコードのキーはencodeでバイト列にする'.encode('utf-8'))

保存されている項目をイテレーション

キーと値をたくさん登録して、最後に全部をCSVに出したいとか、そういうことってありますよね。LevelDBでも当然保存されてるキーと値をイテレータで取り出すことができます。

my_db.put('key1', '1')
my_db.put('key2', '1')
my_db.put('key3', '3')

for key, value in my_db:
    print '%s => %s' % (key, value)

# 出力:
# key1 => 1
# key2 => 2
# key3 => 3

キーの範囲を指定したり、キーのprefixを指定して取り出すこともできるようです。詳しくはplyvelのドキュメントのiteratorsのセクションを見て見てください。

構造化されたvalueを登録してみる: pickle

冒頭にも書きましたが、valueはバイト列でなければいけないので、keyに対してdictやlist/などの構造化されたデータをひもづけてLevelDBに保存したい場合、シリアライズする必要があります。Pythonにpickleというシリアライズ用のライブラリが標準であるので、これを使うと簡単です。Pickleは基本的なデータ型だけでなく、関数やオブジェクトなどもシリアライズすることができ、非常に強力です。ただ、Python以外の言語ではpickleデータをデシリアライズ(元のデータ構造に戻す)ことが難しいので他の言語でもデータを流用したい場合は後述のMessagePack形式でシリアライズするとよいでしょう。

fukuzatsu1 = dict(a=10, b=20, c=[123, 234, 456])
my_db.put('key1', fukuzatsu1)  # エラーになる

import pickle
serialized1 = pickle.dumps(fukuzatsu1)
my_db.put('key1', serialized1)  # OK 

# valueを使うとき
serialized1 = my_db.get('key1')
fukuzatsu1 = pickle.loads(serialized1)
print fukuzatsu1['a']  # => 10

pickleの使い方は詳しくはpickleのドキュメントを参照してください。

構造化されたvalueを登録してみる: msgpack

pickleの他にはMessagePackという日本発のシリアライジングフォーマットがおすすめです。MessagePackはデータをコンパクトかつ高速にシリアライズできることが特徴です。MessagePackをPythonで使うときはmsgpack-pythonというパッケージをインストールします。

$ pip install msgpack-python

msgpackではpickleのdumps/loadsに変わってpackb/unpackbを使います。

fukuzatsu1 = dict(a=10, b=20, c=[123, 234, 456])

import msgpack
serialized1 = msgpack.packb(fukuzatsu1, encoding='utf-8')
my_db.put('key1', serialized1)

# valueを使うとき
serialized1 = my_db.get('key1')
fukuzatsu1 = msgpack.unpackb(serialized1, encoding='utf-8')
print fukuzatsu1['a']  # => 10

詳しくはmsgpack-pythonのAPIドキュメントを参照してください。

参考リンク

51
50
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
50