【问题标题】:Which data structure to store binary strings and query with hamming distane使用汉明距离存储二进制字符串和查询的数据结构
【发布时间】:2016-06-06 19:39:27
【问题描述】:

我正在寻找一种数据结构来处理包含 512 个二进制值的数十亿个二进制字符串。

我的目标是向结构发送查询并获得一个结果集,其中包含距离较近的所有数据。

我的第一个想法是使用 kd 树。但是那些树对于高维来说非常慢。 我的第二个想法是使用 lsh 方法(minHash/superbit)lsh。但为此,我还必须有一个结构来执行有效的搜索

对如何处理这些大数据有什么想法吗?

**更新** 一些细节说明:

  • 因为汉明距离只存在一个上限,可能是 128。但我不知道上限
  • 插入或删除会很好,但我也可以重建图表(数据库每周只更新一次)
  • 结果集必须包含所有相关节点(我不是在找knn)

【问题讨论】:

  • 请说明需求。这个结果集是否必须包含给定距离内的所有节点?距离有上限和下限吗?您能否承受大量开销来索引和组织数据?会有插入或删除吗?
  • 你好 Prune,是的,结果集应该包含所有在距离上限以下的节点。不存在下限。插入和删除会很好,但我也可以重建图表。
  • 查询和更改的比例是多少?数据库设计很可能取决于更改(添加和删除)的相对频率。
  • 另外,可能的距离值是多少?是否值得在此基础上进行优化?
  • 数据库应该每周更新一次,所以插入/删除并不那么重要。及时我不知道最大汉明距离。也许所有 512 位中的 128 位应该是正确的

标签: distance hamming-distance bigdata


【解决方案1】:

在不知道您的预期搜索参数的情况下,很难进行过度优化。也就是说,我认为一个好的方法是构建 B 或 T 树,然后针对数据的二进制性质优化该结构。

具体来说,您有 64 个字节的数据作为 512 个元素的位串。您的估计是您将拥有“数十亿”条记录。这大约是 232 个值,所以 1/16th 的空间会被填满? (这符合您的预期吗?)

无论如何,尝试将数据分解为字节,让每个字节成为关键级别。如果设置位的概率是统一的,您可能可以压缩级别记录。 (如果不是,如果说设置位更有可能在键的前面,那么您可能只想分配 256 个下一级指针并让一些为空。这并不总是值得的。)

您的所有级别都是相同的——它们将代表字符串的另外 8 位。因此,计算一个表,该表针对一个字节映射距离该字节S 内的所有字节值,0 hamming(a,b).

要遍历树,请将搜索距离设为 SD。设置 D = SD。阅读顶层块。查找块中小于查询距离min(8, D) 的所有 8 位值。对于每个值,计算精确的距离 hamming(query, value) 并使用 D = D - hamming(query, value) 递归到该子树的较低块。

【讨论】:

  • 你好,谢谢你的这个想法。但我不明白如何解释这棵树。正常的 B 树只有 2 个孩子。但是如何将一个字节拆分为左右节点呢?
  • 二叉树有左右节点。尽管有名字,B-trees 和 T-trees 不是二元的。它们是 n 元的,通常取决于存储结构和输入数据之间的实际(基于存储)关系来确定 n,这可能因节点而异。在这种情况下,我的建议是让节点为 256 进制,代表字符串的 8 位。
  • 啊当然……我的错。好点子!我会测试它。
【解决方案2】:

我在这里看到的最大设计问题是闭包要求:我们需要返回给定向量距离 N 内的所有项,对于任意 N。数据空间是稀疏的:“十亿”大约是 2^33,但我们有 512 位信息,因此每 2^(512-33) 个可能性只有 1 个条目。对于随机分布的密钥,任意两个节点之间的期望距离为 256;预期的最近邻距离约为 180。

这使我期望您的搜索将取决于非随机数据集群,并且您的搜索将通过识别该集群来促进。对于初始数据,这将是一个有点痛苦的预处理步骤,但应该非常值得。

我对此的一般方法是首先以某种通常快速的方式识别这些集群。从返回一个非常通用的距离度量的散列函数开始。例如,对于任何向量,计算到一组正交参考向量中的每一个的距离。对于 16 位,您可能会采用以下集合(以十六进制列出):0000、00FF、0F0F、3333、5555,一个连续的“交替位”“颗粒”。将此哈希作为 4 位距离的简单元组返回,a总共 20 位(长向量实际上可以节省,因为其中一个大小是 2^(2^N))。

现在,这个哈希元组可以让您粗略估计汉明距离,这样您就可以更轻松地对向量进行聚类:相似的向量必须具有相似的哈希值。

在每个簇中,找到一个中心元素,然后通过与该中心的距离来表征簇中的每个元素。为了更快的速度,给每个节点一个最近的邻居列表和距离,所有这些都在集群内。这为您提供了每个集群的图表。

类似地连接所有集群中心,将直接边缘连接到更近的集群中心。如果您的数据可以合理地进行搜索,那么我们将能够保证,对于具有集群中心 Ac 和 Bc 的任意两个节点 A、B,我们将有 d(A, Ac) + d(B, Bc)


查询过程现在稍微快了一些。对于目标向量 V,求哈希值。找到足够接近其邻域中的某些东西可能匹配的总值的集群中心([实际距离] - [查询范围] - [集群半径])。这将允许您立即消除整个集群,并可能为您提供整个“命中”集群。对于每个边缘集群(一些,但不是所有节点都符合条件),您需要找到一个通过接近蛮力的方式工作的节点(从距离集群中心的可行距离范围的中间开始),然后执行对每个节点的邻居进行广度优先搜索。

我希望这会给您带来与最佳性能相当的东西。它还可以很好地适应添加和删除,只要这些添加和删除的频率不足以更改其他节点的集群成员资格。


向量集很简单。写出 16 位情况的位模式:

0000 0000 0000 0000   16 0s
0000 0000 1111 1111    8 0s, 8 1s 
0000 1111 0000 1111    4 0s, 4 1s, repeat
0011 0011 0011 0011    2 0s, 2 1s, repeat
0101 0101 0101 0101    1 0s, 1 1s, repeat

【讨论】:

  • 明显的精神愚蠢;谢谢。编辑即将推出。
  • 嗨 Prune,你的方法听起来很棒!但是为什么第一个集群只使用 16 位呢?我该如何描述这样的哈希指标?
  • 我只用了 16 来说明主体。将案例从 16 位扩展到 512 位,使用一组 10 个向量,距离占 9 位,哈希键中总共有 90 位。在什么意义上你需要“描述”散列键?
  • 嗯,好的,谢谢。比我不需要其他哈希函数来描述密钥。我将测试这些方法。目前我不明白如何生成正交向量。是否有算法或者我必须使用暴力破解并使用点积进行测试?
猜你喜欢
  • 2011-06-14
  • 1970-01-01
  • 2011-07-29
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
相关资源
最近更新 更多