使用键值数据库作为具有持久索引的集合

Posted

技术标签:

【中文标题】使用键值数据库作为具有持久索引的集合【英文标题】:Using key-value databases as a set with persistent indices 【发布时间】:2012-12-17 22:35:29 【问题描述】:

由于以下内容有点长:这里是 tl;dr;版本:是否存在用于快速键值查找的现有键/值最佳实践,例如具有持久索引的基于哈希的集合?

我对键值数据库领域很感兴趣,但至今未能弄清楚如何有效地实现以下用例:

假设我们想要序列化一些数据并通过一个持久的、唯一的整数索引在其他地方引用它们。例如:Key = unsigned int, Value = MyData。

数据库应具有快速键查找并确保 MyData 是唯一的。

现在,当我在数据库中插入一个新值时,我可以为其分配一个新的索引键,例如数据库的当前大小或为了防止删除项目后发生冲突,我可以在外部保留一些计数器。

但是我如何确保不会将相同的 MyData 值插入到我的数据库中?到目前为止,在我看来,键值数据库似乎无法有效地实现这一点 - 这是正确的吗? IE。我确实想要遍历整个数据库只是为了确保 MyData 值不在其中...

那么,实现这一点的最佳做法是什么?

对于背景:我在 KDevelop 上工作,我们将上述内容用于我们的代码分析缓存。我们实际上有上述用例1 的自定义实现。如果您对内部结构感兴趣,请搜索 Bucket 和 ItemRepository,并查看 2 了解 ItemRepository 的示例用法。

但您可能会同意,这段代码很难理解,因此也很难维护。我想将它的性能与可能导致代码更简单的替代解决方案进行比较——但前提是它不会导致严重的性能损失。考虑到围绕 OpenLDAP MDB、Kyoto Cabinet 和 LevelDB 等键值存储性能的炒作,这就是我想开始的地方。

我们在 KDevelop 中拥有的——据我所知——基本上是一种混合的磁盘/内存哈希映射,它会定期保存到磁盘(这当然会导致严重的数据损坏,以防万一崩溃等)。项目根据它们的散列值存储在一个位置,只要散列函数速度快,这当然也允许相对快速的值查找。增加的转折是您还可以获得某种持久性数据库索引,可用于非常有效地查找项目。

所以 - 长话短说 - 如何使用诸如 LevelDB、Kyoto Cabinet、OpenLDAP MDB 之类的键/值数据库来做到这一点 - 你能说出它的名字吗?

【问题讨论】:

【参考方案1】:

听起来您想做 OpenLDAP 对其平等索引所做的事情。可能这和OrientDB的例子一样,我没看过。

主表由一个单调递增的整数键(称为entryID)索引,并存储数据值。相等索引由值的散列索引,并存储与散列匹配的 entryID 列表。由于散列可能有冲突,仅相等索引中的条目的存在并不能证明唯一性或重复性。您仍然需要检查实际值。

如果您使用的是 MDB、BDB 或其他支持重复键的数据库,一种更快/更简单的方法是只保留一个表,使用哈希作为键。在 MDB 和 BDB 中都有一个 GET_BOTH 请求,它匹配键和数据以执行提取。如果成功,那么您肯定知道该值已经存在。否则,它允许您保存任何数据值,而不必担心是否存在哈希冲突。

这里需要注意的是,在使用重复键的 MDB 中,值的大小限制为小于磁盘页面的一半。

【讨论】:

谢谢,这听起来正是我想要的。【参考方案2】:

除非我在这里遗漏了什么——通常你的哈希算法是一致的,并且会为相同的数据提供相同的密钥。因此,您应该只需要查找密钥以查看它是否已经存在,或者处理数据库返回给您的(可能重复的密钥)错误。

afaik Key/Value DBs 可以并且将为您强制执行唯一值约束,即如果您尝试保存已经存在的值,您将收到错误。

【讨论】:

是的,散列算法是一致的,但对于破坏你推理的任意值不是唯一的,不是吗?详细说明:您将使用什么作为要插入的任意值的键?对于给定的值,它必须是唯一的,并且查找速度相对较快(即没有 O(N) 算法来遍历所有值以找到合适的键)。 你可以使用非任意密钥。就像您跟踪最大值的序列号,或者像“FirstKey”“SecondKey”“ImportantAppKey”或类似的字符串描述符......对吗?如果您使用序列号,您甚至可以将“顶部”保存到数据库 - 如果您有 100 个“桶”,则 DBNAME.top = 100。或类似的。 这是 OrientDB code.google.com/p/orient/wiki/Indexes 的一个示例 - 也许您的 NOSQL 数据库可以自动生成索引并使用这些索引来代替或添加任意键? @milianw,不,它不会破坏推理:如果已经添加了另一个 MyData,它将使用相同的键添加,这意味着您只需要检查分配给现有密钥(如果密钥已经存在)并将旧值与新值进行比较,如果他们同意,则它已经存在 OrientDB 的例子看起来很有趣,这正是我想要的。【参考方案3】:

你的值字符串有多大?

我会将它们存储在一个密钥中,让数据库完成所有工作。

适用于大多数 KV 存储的典型 LevelDB 样式是使用一对键,前缀表示类型

例如:

Key = 'i' + ID 
Value = valueString

Key = 'v' + valueString
Value = ID

在需要允许多个相同 valueStrings 的系统中,您可以将 ID 移动到第二个键的尾部

Key = 'v' + valueString + ID
Value = empty

【讨论】:

以上是关于使用键值数据库作为具有持久索引的集合的主要内容,如果未能解决你的问题,请参考以下文章

阵列等的磁盘存储

Properties持久化键值对

android上持久键值存储的最佳机制是啥(具有大值)

Python基本数据类型--集合

java学习---Redis基础操作

java学习---Redis基础操作