【问题标题】:The best way to search millions of fuzzy hashes搜索数百万个模糊哈希的最佳方法
【发布时间】:2015-08-14 08:39:02
【问题描述】:

我有一个数据库表中大约一千万个文件的spamsum 复合哈希,我想找到彼此相当相似的文件。 Spamsum 哈希由两个最大 64 字节的 CTPH 哈希组成,如下所示:

384:w2mhnFnJF47jDnunEk3SlbJJ+SGfOypAYJwsn3gdqymefD4kkAGxqCfOTPi0ND:wemfOGxqCfOTPi0ND

它们可以分为三个部分(在冒号上拆分字符串):

  1. 块大小:384 在上面的哈希中
  2. 第一个签名:w2mhnFnJF47jDnunEk3SlbJJ+SGfOypAYJwsn3gdqymefD4kkAGxqCfOTPi0ND
  3. 二次签名:wemfOGxqCfOTPi0ND

块大小是指第一个签名的块大小,第二个签名的块大小是第一个签名的两倍(这里:384 x 2 = 768)。每个文件都有这些复合哈希之一,这意味着每个文件都有两个具有不同块大小的签名。

只有当它们的块大小对应时,才能比较垃圾邮件签名。也就是说,上面的复合散列可以与任何其他包含块大小为 384 或 768 的签名的复合散列进行比较。对于具有相似块大小的散列,签名字符串的相似性可以作为两者之间相似性的度量。由哈希表示的文件。

如果我们有:

  • file1.blk2 = 768
  • file1.sig2 = wemfOGxqCfOTPi0ND
  • file2.blk1 = 768
  • file2.sig1 = LsmfOGxqCfOTPi0ND

我们可以通过计算两个签名的一些加权编辑距离(如 Levenshtein 距离)来了解两个文件的相似程度。这两个文件看起来很相似。

leven_dist(file1.sig2, file2.sig1) = 2

还可以计算两个哈希之间的归一化相似度分数(请参阅详细信息here)。

我想根据这些哈希值找到任何两个相似度超过 70% 的文件,并且我非常喜欢使用可用的软件包(或 API/SDK),尽管我不害怕编写自己的代码解决问题。

我尝试使用 Lucene (4.7.0) 分解散列并对其进行索引,但搜索似乎缓慢而乏味。下面是我尝试过的 Lucene 查询示例(对于每个单一签名——每个哈希两次并使用区分大小写的 KeywordAnalyzer):

(blk1:768 AND sig1:wemfOGxqCfOTPi0ND~0.7) OR (blk2:768 AND sig2:wemfOGxqCfOTPi0ND~0.7)

Lucene 的incredibly fast Levenshtein automata 似乎不接受高于 2 的编辑距离限制(我需要它支持高达 0.7 x 64 ≃ 19),并且它的正常编辑距离算法没有针对长搜索词进行优化(the brute force method used does not cut off calculation once the distance limit is reached .) 也就是说,可能是我的查询没有针对我想做的事情进行优化,所以请不要犹豫,纠正我。

我想知道是否可以使用 Lucene 提供的任何算法来完成我需要的工作,而不是直接计算编辑距离。我听说 BK-trees 是索引此类搜索的最佳方式,但我不知道该算法的可用实现(Lucene 是否使用这些实现?)。我还听说一个可能的解决方案是使用 n-gram 方法缩小搜索列表,但我不确定在包容性和速度方面与编辑距离计算相比如何(我很确定 Lucene 支持那个)。顺便问一下,有没有办法让 Lucene 以并行模式运行术语搜索?

鉴于我仅使用 Lucene 来预匹配哈希值,并且我稍后会使用适当的算法计算真正的相似度得分,因此我只需要一种至少与相似度得分计算中使用的 Levenshtein 距离一样具有包容性的方法 - - 也就是说,我不希望预匹配方法排除会被评分算法标记为匹配的哈希。

感谢任何帮助/理论/参考/代码或线索。

【问题讨论】:

    标签: lucene levenshtein-distance fuzzy-search fuzzy-comparison


    【解决方案1】:

    这不是问题的明确答案,但从那以后我尝试了多种方法。我假设哈希值保存在数据库中,但这些建议对于内存数据结构仍然有效。

    1. 将所有签名(每个哈希 2 个)连同它们对应的块大小一起保存在单独的子表中。由于只能相互比较相同大小的签名,因此您可以在开始比较签名之前按块大小过滤表。
    2. 将所有超过三个字符的重复序列减少到三个字符('bbbbb' -> 'bbb')。 Spamsum 的比较算法会自动执行此操作。
    3. Spamsum 使用 7 的滚动窗口来比较签名,并且在消除过多重复后不会比较任何两个不具有 7 个字符重叠的签名。如果您使用的数据库支持列表/数组作为字段,请创建一个字段,其中包含从每个签名中提取的所有可能的 7 字符序列的列表。然后在此字段上创建您可以访问的最快的完全匹配索引。在尝试查找两个签名的距离之前,请先尝试对该字段进行完全匹配(任何 7 元共同点?)。
    4. 我正在尝试的最后一步是将签名及其 7-gram 保存为二分图的两种模式,将图投影为单一模式(仅由哈希组成),然后仅在相邻节点上计算 Levenshtein 距离具有相似的块大小。

    上述步骤进行了良好的预匹配,并大大减少了每个签名必须与之比较的签名数量。只有在这些之后,才需要计算修改后的 Levenshtein/Damreau 距离。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 2018-10-01
      • 2020-06-01
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 2015-04-02
      相关资源
      最近更新 更多