今回はpure pythonのDatabase、CodernityDBのご紹介です。
日本語の紹介も無さそうでしたので簡単に紹介させていただきます。
Documentationとして作成しようかと思ったんですがそこまで纏められなかったので...
間違っている部分などありましたらご指摘いただけますと幸いです。
CodernityDBとは
- Opensource
- Native Python database
- fast
- マルチプラットフォーム
- スキーマレス
- 複合インデックス(Multiple indexes)
などの特徴を持つNoSQLデータベースです。
Indexについて
現在、CodernityDBには大きく分けて2つのIndexが実装されています。
Hash Index
- 利点
速い
- 欠点
レコードはInsert/Update/Deleteの順番には並びません。
出来る処理は 特定のキーを問い合わせる or 全てのキーの反復処理 のみ
B Plus Tree Index
- 利点
レコードが順番に並びます(キーに依存します)
範囲クエリを問合せできます
- 欠点
Hash based indexesよりも遅いです
基本的な使い方
CodernityDBの使い方は非常に単純です。
ここではInsert/Count/Update/Delete/Getの5つについて実行するための簡単なコードを書いておきます。
ここには書いていない処理について、もしくはもっと詳しく知りたいような場合には公式:Quick tutorialをご覧下さい。
Insert(simple)
from CodernityDB.database import Database db = Database('/tmp/tut1') db.create() insertDict = {'x': 1} print db.insert(insertDict)
この方法は最も単純なInsertですが、_id fieldが自動生成され、特定のレコードを検索することは出来ません。
Insert
from CodernityDB.database import Database from CodernityDB.hash_index import HashIndex class WithXIndex(HashIndex): def __init__(self, *args, **kwargs): kwargs['key_format'] = 'I' super(WithXIndex, self).__init__(*args, **kwargs) def make_key_value(self, data): a_val = data.get("x") if a_val is not None: return a_val, None return None def make_key(self, key): return key db = Database('/tmp/tut2') db.create() x_ind = WithXIndex(db.path, 'x') db.add_index(x_ind) print db.insert({'x': 1})
Count
from CodernityDB.database import Database db = Database('/tmp/tut1') db.open() print db.count(db.all, 'x')
Get
from CodernityDB.database import Database db = Database('/tmp/tut2') db.open() print db.get('x', 1, with_doc=True)
Delete
from CodernityDB.database import Database db = Database('/tmp/tut2') db.open() curr = db.get('x', 1, with_doc=True) doc = curr['doc'] db.delete(doc)
Update
from CodernityDB.database import Database db = Database('/tmp/tut2') db.create() curr = db.get('x', 1, with_doc=True) doc = curr['doc'] doc['Updated'] = True db.update(doc)
Tips
error
raise IndexConflict("Already exists")
db.create, db.add_indexで既にある場合に発生するエラーです。
struct.error: 'I' format requires 0 <= number <= 4292967295
indexが4GBを超えた時に発生するエラーです。
エラーが発生した場合には、formatを'Q'に変更したり、indexを変更するなどの対応が必要です。
もし、db.path/id_buckが4GBを超えている場合、それはあなたが作成したindexが4GBを超えているのではなく、CodernityDBがDefaultで作成するmain indexによるものです。この場合はdb.createにwith_id_index=Falseを指定することで解決できるかもしれません。これはmain indexを作成させないようにするオプションです。
ただし、with_id_index=Falseを指定した場合は、id indexをUniqueHashIndexを用いてformat 'Q'で作成するか、Sharded indexesを使用してシャーディングを行う必要があります。Sharded Indexでformat 'I'を用いる場合には、10 shardsで10*4GBのindexを持つことが出来ます。shardの数はsh_numで設定します。
- UniqueHashIndexを使用した例
from CodernityDB.database import Database from CodernityDB.hash_index import HashIndex, UniqueHashIndex class BigIDIndex(UniqueHashIndex): def __init__(self, *args, **kwargs): kwargs['key_format'] = '<32s8sQIcQ' super(BigIDIndex, self).__init__(*args, **kwargs) class MyIDIndex(HashIndex): def __init__(self, *args, **kwargs): kwargs['key_format'] = 'Q' super(MyIDIndex, self).__init__(*args, **kwargs) def make_key_value(self, data): a_val = data.get("x") if a_val is not None: return a_val, None return None def make_key(self, key): return key db = Database('/tmp/tut1') db.create(with_id_index=False) db.add_index(BigIDIndex(db.path, 'id')) db.add_index(MyIDIndex(db.path, 'x')) db.insert({'x': 1})
ValueError: bad marshal data, TypeError: 'str' object does not support item assignmentが発生することを確認していますが、今のところ解決策を見つけられていません。
膨大な量のデータをInsertする場合にはSharded Indexを利用するか、データを分けることを検討した方が良いかもしれません。
- Sharded Indexを使用した例
from CodernityDB.sharded_hash import ShardedUniqueHashIndex, ShardedHashIndex from CodernityDB.tree_index import TreeBasedIndex class CustomIdSharded(ShardedUniqueHashIndex): custom_header = 'from CodernityDB.sharded_hash import ShardedUniqueHashIndex' def __init__(self, *args, **kwargs): kwargs['sh_nums'] = 10 super(CustomIdSharded, self).__init__(*args, **kwargs) class TreeIndex(TreeBasedIndex): def __init__(self, *args, **kwargs): kwargs['node_capacity'] = 10 kwargs['key_format'] = 'I' super(TreeIndex, self).__init__(*args, **kwargs) def make_key_value(self, data): t_val = data.get('x') if t_val is not None: return t_val, None return None def make_key(self, key): return key db = Database('/tmp/tut1') db.create(with_id_index=False) db.add_index(CustomIdSharded(db.path, 'id')) db.add_index(TreeIndex(db.path, 'x')) db.insert({'x': 1})
このエラーについて、詳しくはこちらを参照して下さい。