在LMDB

时间:2015-04-22 14:21:07

标签: key-value key-value-store lmdb

我是键值商店的新手。我想尝试LMDB作为持久关联数组,并希望能够使用长长度密钥,如文件路径或URL。

LMDB定义编译时常量MDB_MAXKEYSIZE = 511,对密钥长度施加最大值。

我应该使用什么技术在LMDB之上实现持久性长长度密钥字典?某种散列和碰撞解决方案?或者使用不同的MAXKEYSIZE重新编译,例如2048?或者LMDB是这项工作的错误工具?

2 个答案:

答案 0 :(得分:2)

在我自己的使用中,我通过SHA-256散列任意长度的字符串键来处理类似的情况,为B +树生成一个固定大小的32字节摘要密钥。这个策略需要注意以下两点:

  1. 您完全失去了执行前缀字符串查找的能力。对于用例,例如您所描述的用例,这通常不是一个重大问题。

  2. 如果您需要能够枚举所有原始字符串键,您需要将原始字符串存储在另一个LMDB子数据库中,以便您可以基于SHA执行查找256摘要以检索其对应的原始字符串 - 该字符串将作为键/值对的值存储在子数据库中,因此不受MDB_MAXKEYSIZE限制。这确实增加了空间要求,为完整扫描中的每个游标操作添加了额外的树查找,并且不会按字典顺序生成字符串。如果您能够容忍这些限制,这是一种可行的方法。

答案 1 :(得分:1)

使用散列算法生成较短长度摘要的建议非常适用于您不需要保留密钥顺序的情况。然而,在很多情况下,订单很重要,在这些情况下,LMDB仍然是一个很棒的选择。

例如,如果您尝试查看以字母" x"开头的所有文件。在公共父目录中,您希望保留键的顺序。在这种情况下,您当然可以使用更高的最大密钥大小来编译LMDB。但这不是唯一的策略。

您可以使用密钥摘要保留密钥顺序的算法。您无法获得密钥大小的减少,但您可以选择子目录的整个内容作为连续组。

或者您可以将多维结构映射到键上。从根ID 0开始,每个子目录都有一个唯一的目录ID,文件和子目录条目在一个公共父目录ID中分组。

[DirID,filename] = null - the null value means it's a file.
[DirID,dirname] = DIRID - the ID means it's a subdirectory.

这有很多好处。密钥长度适用于每个文件和目录名称,而不适用于完整目录路径。所以你不必重新编译LMDB。它还可以节省内存,因为完整的路径不会一遍又一遍地重复。并且文件和目录排序顺序保留在每个父目录ID中。此外,它打开了许多持久稀疏矩阵功能的大门,您可以在此结构之上构建它们。

但完全披露:这也是一个缺点。要获得完整路径或按顺序列出文件,您必须继续通过子目录进行递归,并且您在此过程中需要多次磁盘命中。

所以最后,你必须看看你正在做什么以及将来你想去哪里,并为你的具体案例选择最合适的关键设计策略。如果你正确地获得了密钥结构,那么在添加新功能时,您可以避免以后丢弃所有代码。