読者です 読者をやめる 読者になる 読者になる

CORDEA blog

Programming及びFedora21等のLinux OSのことが多めです。

CodernityDBのご紹介

Database Python

今回はpure pythonのDatabase、CodernityDBのご紹介です。
日本語の紹介も無さそうでしたので簡単に紹介させていただきます。
Documentationとして作成しようかと思ったんですがそこまで纏められなかったので...
間違っている部分などありましたらご指摘いただけますと幸いです。

 

CodernityDBとは

などの特徴を持つNoSQLデータベースです。
 
 

Indexについて

現在、CodernityDBには大きく分けて2つのIndexが実装されています。

Hash Index

  • 利点

  速い

  • 欠点

  レコードはInsert/Update/Deleteの順番には並びません。
  出来る処理は 特定のキーを問い合わせる or 全てのキーの反復処理 のみ
 

B Plus Tree Index

  • 利点

  レコードが順番に並びます(キーに依存します)
  範囲クエリを問合せできます 

  • 欠点

  Hash based indexesよりも遅いです

 
 

formatについて

CodernityDBには多くのformatがあります。

公式:Key-format及びフォーマット文字 - Python Documentationを確認して下さい。

  
 

基本的な使い方

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.createwith_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})

このエラーについて、詳しくはこちらを参照して下さい。