表达Berkeley DB的多个列中的蟒蛇?
-
25-09-2019 - |
题
说我有一个包含用户名,名字,姓氏一个简单的表。
我如何表达这种在Berkeley DB的?
我目前使用bsddb作为接口。
干杯。
解决方案
您必须选择一个“列”为重点(必须是唯一的,我想这将是你的情况“用户名”) - 的唯一途径搜索将永远不可能发生。其他列可以做成你所喜欢的任何方式,关键的一个字符串值,从酸洗简单与同时保证在任何列永远不会发生字符的加盟,比如'\ 0' ,许多种“可读的文本字符串”
如果您需要能够通过不同的按键来搜索你需要设置为“指数”到你的主表等,补充和独立bsddb数据库 - 它的大量的工作,而且有大量的文献的主题。 (或者,也移动到更高的抽象的技术,如SQLite,它整齐地处理代表你的索引; - )
。其他提示
TL,博士:为了表达在多列排序键值存储就像你需要了解的键组成的伯克利分贝。你看我的了解 bsddb 其他的答案了解更多信息。
有几种方法可以做到,使用命令键/值存储。
在简单的办法是存储文档为JSON值与正确的密钥。
现在,你可能想通过那些列建立索引,而不必遍历所有的HashMap来找到正确的对象来检索文件。对于您可以使用 secondaryDB ,将建立自动索引您。或者你也可以自己建立索引。
如果你不想处理键包装(和它是启动一个好主意),你可以利用 DB.set_bt_compare 这将允许您使用的cPickle ,JSON或msgpack两个键同时还具有使SENS创建索引和查询执行的顺序值。这是比较慢的方法,但引入的图案的键组合物
要充分利用什么下令关键是,你可以利用Cursor.set_range(key)
的设置数据库的位置在查询的开始。
另一种模式,被称为 EAV图案存储随后的方案(entity, attribute, value)
并然后通过使用该元组的排列建立各种索引元组。我了解到这种模式STUDING datomic。
有关更少的ressource饿了数据库,你会去“静态类型化”的方式和存储尽可能的在“元数据”表和拆分文献中常见的信息(这是真正的RDBMS表)到自己的HashMap中。
要得到你开始在这里是用bsddb一个例子数据库(但你可以使用其他命令键/值存储像wiredtiger或性LevelDB建立它)实现了EAV模式。在此实现我交换EAV的IKV它转换为唯一标识符,键,值。在全部测试的结果是,你有一个完全索引模式少文档数据库。我认为这是效率和易用性的使用之间的良好平衡。
import struct
from json import dumps
from json import loads
from bsddb3.db import DB
from bsddb3.db import DBEnv
from bsddb3.db import DB_BTREE
from bsddb3.db import DB_CREATE
from bsddb3.db import DB_INIT_MPOOL
from bsddb3.db import DB_LOG_AUTO_REMOVE
def pack(*values):
def __pack(value):
if type(value) is int:
return '1' + struct.pack('>q', value)
elif type(value) is str:
return '2' + struct.pack('>q', len(value)) + value
else:
data = dumps(value, encoding='utf-8')
return '3' + struct.pack('>q', len(data)) + data
return ''.join(map(__pack, values))
def unpack(packed):
kind = packed[0]
if kind == '1':
value = struct.unpack('>q', packed[1:9])[0]
packed = packed[9:]
elif kind == '2':
size = struct.unpack('>q', packed[1:9])[0]
value = packed[9:9+size]
packed = packed[size+9:]
else:
size = struct.unpack('>q', packed[1:9])[0]
value = loads(packed[9:9+size])
packed = packed[size+9:]
if packed:
values = unpack(packed)
values.insert(0, value)
else:
values = [value]
return values
class TupleSpace(object):
"""Generic database"""
def __init__(self, path):
self.env = DBEnv()
self.env.set_cache_max(10, 0)
self.env.set_cachesize(5, 0)
flags = (
DB_CREATE |
DB_INIT_MPOOL
)
self.env.log_set_config(DB_LOG_AUTO_REMOVE, True)
self.env.set_lg_max(1024 ** 3)
self.env.open(
path,
flags,
0
)
# create vertices and edges k/v stores
def new_store(name):
flags = DB_CREATE
elements = DB(self.env)
elements.open(
name,
None,
DB_BTREE,
flags,
0,
)
return elements
self.tuples = new_store('tuples')
self.index = new_store('index')
self.txn = None
def get(self, uid):
cursor = self.tuples.cursor()
def __get():
record = cursor.set_range(pack(uid, ''))
if not record:
return
key, value = record
while True:
other, key = unpack(key)
if other == uid:
value = unpack(value)[0]
yield key, value
record = cursor.next()
if record:
key, value = record
continue
else:
break
else:
break
tuples = dict(__get())
cursor.close()
return tuples
def add(self, uid, **properties):
for key, value in properties.items():
self.tuples.put(pack(uid, key), pack(value))
self.index.put(pack(key, value, uid), '')
def delete(self, uid):
# delete item from main table and index
cursor = self.tuples.cursor()
index = self.index.cursor()
record = cursor.set_range(pack(uid, ''))
if record:
key, value = record
else:
cursor.close()
raise Exception('not found')
while True:
other, key = unpack(key)
if other == uid:
# remove tuple from main index
cursor.delete()
# remove it from index
value = unpack(value)[0]
index.set(pack(key, value, uid))
index.delete()
# continue
record = cursor.next()
if record:
key, value = record
continue
else:
break
else:
break
cursor.close()
def update(self, uid, **properties):
self.delete(uid)
self.add(uid, **properties)
def close(self):
self.index.close()
self.tuples.close()
self.env.close()
def debug(self):
for key, value in self.tuples.items():
uid, key = unpack(key)
value = unpack(value)[0]
print(uid, key, value)
def query(self, key, value=''):
"""return `(key, value, uid)` tuples that where
`key` and `value` are expressed in the arguments"""
cursor = self.index.cursor()
match = (key, value) if value else (key,)
record = cursor.set_range(pack(key, value))
if not record:
cursor.close()
return
while True:
key, _ = record
other = unpack(key)
ok = reduce(
lambda previous, x: (cmp(*x) == 0) and previous,
zip(match, other),
True
)
if ok:
yield other
record = cursor.next()
if not record:
break
else:
break
cursor.close()
db = TupleSpace('tmp')
# you can use a tuple to store a counter
db.add(0, counter=0)
# And then have a procedure doing the required work
# to alaways have a fresh uid
def make_uid():
counter = db.get(0)
counter['counter'] += 1
return counter['counter']
amirouche = make_uid()
db.add(amirouche, username="amirouche", age=30)
print(db.get(amirouche))