数据库中的汉明距离/相似性搜索

Posted

技术标签:

【中文标题】数据库中的汉明距离/相似性搜索【英文标题】:Hamming Distance / Similarity searches in a database 【发布时间】:2012-03-25 06:38:37 【问题描述】:

我有一个过程,类似于生成感知哈希的 tineye,这些是 32 位整数。

我打算将来将这些存储在 sql 数据库(可能是 nosql db)中

但是,我对如何根据哈希的相似性检索记录感到困惑。

有什么想法吗?

【问题讨论】:

可能需要更多信息:您是在考虑二进制表示的汉明距离还是其他什么? 我将考虑从图像到存储在数据库中的哈希的汉明距离 我的意思是:除非我有误解,否则汉明距离是一对字符串的属性,而你有ints .你是如何对你的整数进行字符串化的 - 32 个 1 和 0,或者其他方式? 您将数学术语与字符串类型混淆了。整数可以看作是“0”和“1”元素的列表。 'string' 类型只是一个字节列表(让我们不要进入 DBCS 和 unicode)。 【参考方案1】:

一种常见的方法(至少对我来说很常见)是将您的哈希位字符串分成几个块,并在这些块上查询精确匹配。这是一个“预过滤”步骤。然后,您可以对返回的结果执行按位汉明距离计算,这应该只是整个数据集的一小部分。这可以使用数据文件或 SQL 表来完成。

简单来说:假设您在数据库中有一堆 32 位散列,并且您想要找到与“查询”散列的 4 位汉明距离内的每个散列:

    创建一个包含四列的表:每列将包含 32 位哈希的 8 位(作为字符串或 int)切片,即切片 1 到 4。

    以相同的方式在 qslice 1 到 4 中对查询散列进行切片。

    查询此表,以便 qslice1=islice1 or qslice2=islice2 or qslice3=islice3 or qslice4=islice4 中的任何一个。这将为您提供查询哈希的 3 位 (4 - 1) 内的每个数据库哈希。

    对于每个返回的哈希,计算精确的汉明距离与查询哈希(从四个切片重建索引侧哈希)

第 4 步中的操作数应该比整个表的完整成对汉明计算少得多。

Moses Charikar 在其“simhash”开创性 paper 和相应的 Google patent 中首次描述了这种方法:

    汉明空间中的近似最近邻搜索

[...]

给定由 d 位组成的位向量,我们选择 N = O(n 1/(1+ ) ) 位的随机排列。对于每个 随机排列 σ,我们维持一个有序的 O σ 位向量,按置换位的字典顺序 由 σ。给定一个查询位向量 q,我们找到近似的 通过执行以下操作来最近的邻居:

对于每个排列 σ,我们对 O σ 执行二分查找以定位 最接近 q 的两个位向量(按照由 σ 置换的位获得的字典顺序)。我们现在搜索每个 排序的顺序 O σ 检查上方和下方的元素 二分查找返回的位置 匹配 q 的最长前缀的长度。

Monika Henziger 在她的论文"Finding near-duplicate web pages: a large-scale evaluation of algorithms" 中对此进行了扩展:

3.3 算法C的结果

我们将每一页的位串分成 12 个非 重叠 4 字节片段,创建 20B 片段,并计算所有页面的 C 相似度,其中至少有一个 一块共同点。这种方法保证能找到所有 差异高达 11 的页面对,即 C 相似度 373, 但可能会因为较大的差异而遗漏一些。

Gurmeet Singh Manku、Arvind Jain 和 Anish Das Sarma 的论文 Detecting Near-Duplicates for Web Crawling 也解释了这一点:

    汉明距离问题

定义:给定一组 f 位指纹和一个 查询指纹F,识别是否已有指纹 与 F 的差异最多为 k 位。 (在批处理模式版本中 对于上述问题,我们有一组查询指纹 而不是单个查询指纹)

[...]

直觉:考虑一个 2 d f 位真正随机指纹的排序表。只关注最重要的 d 位 在表中。这些 d 位数字的列表相当于 “几乎是一个计数器”,因为 (a) 相当多的 2 d 位- 存在组合,并且 (b) 很少有 d 位组合 重复。另一方面,最不显着的 f - d 位“几乎是随机的”。

现在选择 d 使得 |d − d|是一个小整数。自从 对表进行排序,单个探针足以识别在 d 个最高有效位位置中与 F 匹配的所有指纹。 由于|d - d|小,这样的比赛次数也少 预计很小。对于每个匹配的指纹,我们可以 很容易弄清楚它是否在最多 k 个位位置上与 F 不同 与否(这些差异自然会限于 f - d 个最低有效位位置)。

上述过程可以帮助我们找到现有的 在 k 位位置上与 F 不同的指纹,所有这些 被限制在最低有效 f - d 位之间 F. 这处理了相当多的案例。覆盖所有 在这种情况下,构建少量额外的就足够了 排序表,如下一节中正式概述的那样。

PS:FWIW,这些优秀的大脑中的大多数都/曾经在某种程度上与 Google 相关联。

【讨论】:

这对这个问题进行了很好的讨论,我将不得不从@David Manheim 的原始答案重新分配已接受的答案 @oPless 谢谢!我在这里描述的方法被认为是最先进的 AFAIK,除了 cse.unsw.edu.au/~weiw/files/SSDBM13-HmSearch-Final.pdf 在某些情况下可以击败它 @PhilippeOmbredanne 您的链接是 404。请改用存档链接:web.archive.org/web/20170309155017/http://www.cse.unsw.edu.au/… 我认为这不应该是公认的答案。可能论文/专利没问题,但解决方案行不通。现在让我展示它如何产生具有 24 位 汉明距离的哈希: StoredHash=[0xFF],[0xFF],[0xFF],[0xFF], QueryHash= [0xFF],[0x00] ,[0x00],[0x00]。 q_slice1=i_slice1 满足条件,因此我们得到选择了 24 位距离的散列。 我继续并实现了这个 - 它非常工作得很好。我使用 64 位 phash 将大约 3000 张照片添加到索引中,在 SQLite 中使用四个 16 位 INT 列和 covering index。约 98% 的返回结果具有所需的距离,不到 2% 的结果需要进一步过滤。在我 7 岁的系统上,在所有文件中重复搜索大约需要 2 秒。这种技术太快了!【参考方案2】:

要找到汉明距离,您可以使用按位加法和减法(整数上的 & 和 ~)来计算这些距离。

SQL 不适用于此类处理。对大型数据集的比较变得非常混乱,并且不会具有利用系统强度的查询速度。也就是说,我做过类似的事情。

这会给你带来个体差异,这需要在完整的数据集上运行并排序,这充其量是混乱的。如果您希望它运行得更快,您将需要使用按“区域”索引或在数据中查找自然分组等策略。有伞形聚类策略,和类似的——有很多文献。但是,在大多数传统的数据库系统中,它会很混乱。

【讨论】:

从相关问答中可以看出,几乎所有的建议都没有使用数据库。 @DavidManheim 恕我直言,SQL 中没有任何内容禁止此类处理。请参阅我的答案,了解在数据库内外工作的实用方法。 FWIW,你所说的这种“聪明的黑客”被许多人认为是有界汉明距离查询的最先进技术;)....我同意 SQL 不是灵丹妙药(而且如果不是更好地排序文件和二进制搜索,这个黑客同样有效) 聪明的 hack 是在 SQL 中实现它,而不是方法本身! @David Manheim - 我不确定谁对你投了反对票,但 Phillipe 的回答对我遇到的问题进行了更深入的讨论。【参考方案3】:

大卫的讨论是正确的,但是如果你没有很多数据,请查看Hamming distance on binary strings in SQL

【讨论】:

以上是关于数据库中的汉明距离/相似性搜索的主要内容,如果未能解决你的问题,请参考以下文章

Atitti knn实现的具体四个距离算法 欧氏距离余弦距离汉明距离曼哈顿距离

PHP实现图片的汉明码提取与降维

算法 - 计算汉明距离

最小汉明距离

汉明距离

感知哈希算法