一种常见的方法(至少对我来说是通用的)是将位字符串分成几个块,并在这些块上进行查询以进行精确匹配,作为预过滤步骤。如果使用文件,则创建的文件数应与块数(例如此处为4)一样多,每个块都在前面排列,然后对文件进行排序。您可以使用二进制搜索,甚至可以在匹配块的上方和下方扩展搜索以获取奖金。
然后,您可以对返回的结果执行按位汉明距离计算,该结果应该只是整个数据集的较小子集。可以使用数据文件或SQL表来完成。
回顾一下:假设您在数据库或文件中有一堆32位的字符串,并且您想要查找3个汉明距离以内或小于“查询”位字符串的字符串中的每个哈希:
创建一个包含四列的表:每列将包含32位哈希(从1到4)的8位(作为字符串或整数)切片。或者,如果您使用文件,则创建四个文件,每个文件都是具有以下内容的切片的排列每个“行”的前面有一个“ islice”
在qslice 1到4中以相同的方式对查询位字符串进行切片。
查询此表,使任何一个qslice1=islice1 or qslice2=islice2 or qslice3=islice3 or qslice4=islice4
。这将为您提供8 - 1
查询字符串中7位()之内的每个字符串。如果使用文件,请在四个排列的文件中的每个文件中进行二进制搜索以得到相同的结果。
对于每个返回的位串,通过查询位串成对计算精确的汉明距离(从数据库或置换文件的四个切片中重建索引侧位串)
第4步中的操作数应比整个表的完整成对汉明计算少得多,并且在实践中非常有效。此外,很容易使用并行机制将文件分片为更小的文件。
当然,根据您的情况,现在您正在寻找一种排序的自联接,即所有相距一定距离的值。恕我直言,相同的方法仍然有效,尽管您将必须从一个起始点向上和向下扩展以共享共享起始块的排列(使用文件或列表),并计算所得簇的汉明距离。
如果在内存而不是文件中运行,则100M 32位字符串数据集的范围为4 GB。因此,四个排列的列表可能需要大约16GB以上的RAM。尽管我使用内存映射文件获得了出色的结果,但是对于类似大小的数据集,它必须使用更少的RAM。
有可用的开源实现。空间中最好的是恕我直言,这是由Moz(C ++)为Simhash完成的,但设计用于64位字符串而不是32位。
这种有界的距离距离方法是Moses Charikar在其“ simhash”开创性论文和相应的Google专利中首次描述了AFAIK :
- 汉明空间中的近似最近邻搜索
[...]
给定每个由d个比特组成的比特向量,我们选择N = O(n 1 /(1+))个比特的随机排列。对于每个随机排列σ,我们按σ排列的位的字典顺序保持位向量的排序顺序Oσ。给定查询位向量q,我们通过执行以下操作找到近似的最近邻居:
对于每个排列σ,我们在Oσ上执行二进制搜索以找到最接近q的两个位向量(按由σ排列的位获得的字典顺序)。现在,我们按照与q匹配的最长前缀长度的顺序,在二进制搜索返回的位置之上和之下的每个排序顺序Oσ中搜索元素。
Monika Henziger在她的论文“查找几乎重复的网页:算法的大规模评估”中对此进行了扩展:
3.3算法C的结果
我们将每个页面的位串划分为12个非重叠的4字节片段,创建20B片段,并计算出至少有一个共同点的所有页面的C相似度。该方法可以确保找到差异最大为11的所有页面对,即C相似度373,但可能会因较大差异而错过一些页面。
Gurmeet Singh Manku,Arvind Jain和Anish Das Sarma在论文“检测Web爬网的几乎重复项”中也对此进行了解释:
- 汉明距离问题
定义:给定f位指纹和查询指纹F的集合,请确定现有指纹是否最多与k位在F上有所不同。(在上述问题的批处理模式版本中,我们具有一组查询指纹,而不是单个查询指纹)
[...]
直觉:考虑一个2 df位真正随机指纹的排序表。仅关注表中的最高有效d位。这些d位数字的列表在某种意义上相当于“几乎是一个计数器”,其中(a)存在相当多的2 d位组合,并且(b)很少有d位组合被复制。另一方面,最低有效的f-d位是“几乎随机的”。
现在选择d,使| d − d | 是一个小整数。由于对表进行了排序,因此单个探针足以识别在d个最高有效位中与F匹配的所有指纹。由于| d − d | 很小,此类匹配的数量也预计会很小。对于每个匹配的指纹,我们可以很容易地找出它在最多k个比特位置上是否与F不同(这些差异自然会限制在f-d个最低有效比特位置上)。
上面描述的过程可以帮助我们找到在k位位置上不同于F的现有指纹,所有指纹都被限制在F的最低有效f-d位之中。这可以处理很多情况。为了涵盖所有情况,只需建立少量其他排序表即可,这将在下一节中正式概述。
注意:我对一个仅DB的相关问题发布了类似的答案