让我们从一个列表开始。您可以使用单个哈希图:
- 在行中存储
0
用户订单的数量
- 对于每个新订单,存储一个新行,计数递增
所以 yoru hashmap 如下所示:
key | value
-------------
0 | 5
1 | tomato
2 | celery
3 | apple
4 | pie
5 | meat
密钥的稳定增量确保每个密钥都是唯一的。鉴于 db 是键排序的,并且 pack 函数将整数转换为一组正确排序的字节数组,您可以获取列表的切片。要获取 5000 到 5050 之间的订单,您可以使用 bsddbCursor.set_range
或 leveldb createReadStream
(js api)
现在让我们扩展到多个用户订单。如果你可以打开几个hashmap你可以使用上面使用的几个hashmap。也许您会遇到一些系统问题(打开 fds 的最大 nb 或每个目录的最大文件数)。因此,您可以使用单个并为多个用户共享相同的 hashmap。
我在下面解释的内容适用于 leveldb 和 bsddb,因为您pack
使用字典顺序(字节顺序)正确键入。所以我会假设你有一个pack
功能。在 bsddb 中,您必须自己构建一个pack
函数。看看wiredtiger.packing
或bytekey以获得灵感。
原理是使用用户的 id 来命名键。它也称为键组合。
假设您的数据库如下所示:
key | value
-------------------
1 | 0 | 2 <--- count column for user 1
1 | 1 | tomato
1 | 2 | orange
... ...
32 | 0 | 1 <--- count column for user 32
32 | 1 | banna
... | ...
您使用以下(伪)代码创建此数据库:
db.put(pack(1, make_uid(1)), 'tomato')
db.put(pack(1, make_uid(1)), 'orange')
...
db.put(pack(32, make_uid(32)), 'bannana')
make_uid
实现如下所示:
def make_uid(user_uid):
# retrieve the current count
counter_key = pack(user_uid, 0)
value = db.get(counter_key)
value += 1 # increment
# save new count
db.put(counter_key, value)
return value
然后你必须进行正确的范围查找,它类似于单个复合键。使用 bsddb api cursor.set_range(key)
,我们检索user5000
和5050
for user之间的所有项目42
:
def user_orders_slice(user_id, start, end):
key, value = cursor.set_range(pack(user_id, start))
while True:
user_id, order_id = unpack(key)
if order_id > end:
break
else:
# the value is probably packed somehow...
yield value
key, value = cursor.next()
不进行错误检查。除此之外user_orders_slice(42, 5000, 5050)
,如果您从列表中删除项目,则不能保证切片会撕掉 51 个项目。查询说项目的正确方法50
是实现 user_orders_query(user_id, start, limit)`。
我希望你能明白。