在局部敏感散列中搜索

Posted

技术标签:

【中文标题】在局部敏感散列中搜索【英文标题】:Search in locality sensitive hashing 【发布时间】:2016-09-19 12:15:22 【问题描述】:

我正在尝试理解this paper 的第 5 部分关于 LSH 的内容,特别是如何存储生成的哈希值。引用链接的论文:

给定每个由 d 位组成的位向量,我们选择 N = O(n 1/(1+epsilon) ) 位的随机排列。对于每个随机排列 σ,我们 按字典顺序保持位向量的排序顺序 O σ 由 σ 置换的位。给定一个查询位向量 q,我们发现 通过执行以下操作来近似最近邻:对于每个 permu- tation σ,我们对 O σ 执行二分查找来定位这两个位 最接近 q 的向量(按位获得的字典顺序) 由 σ 置换)。我们现在搜索每个排序的顺序 O σ 检查二进制返回的位置上方和下方的元素 按匹配 q 的最长前缀的长度顺序搜索。 这可以通过为每个排序顺序 O σ 维护两个指针来完成 (一个向上移动,另一个向下移动)。在每一步,我们移动一个 与最长元素对应的向上或向下指针 匹配前缀。 (这里是O中最长匹配前缀的长度 σ 是相对于 q 计算的,其位由 σ 置换)。我们检查 2N = O(n 1/(1+epsilon) ) 位向量以这种方式。在所有位向量中 检查后,我们返回具有最小汉明距离的那个 问。

我对这个算法感到困惑,我认为我不明白它是如何工作的。

我已经在该主题上找到了this question,但我不明白 cmets 中的答案。同样在第 2 点的this 问题中描述了相同的算法,但我还是不明白它是如何工作的。

您能否尝试逐步向我解释它是如何工作的,并尽可能简单?

我什至试着把我看不懂的东西列个清单,但实际上写得太糟糕了,以至于我看不懂大部分句子

在 gsamaras 回答后编辑:

答案我基本看懂了,但还是有些疑惑:

    说执行N 排列的总成本是O(Nnlogn) 是否正确,因为我们必须对它们中的每一个进行排序?

    上述排列+排序过程在预处理期间或每个查询中只执行一次q?即使在预处理中,O(Nnlogn) 似乎已经相当昂贵了,如果我们必须在查询时这样做,那将是一场灾难:D

    在最后一点,我们将v0v4q 进行比较,我们比较它们的置换版本还是原始版本(置换之前)?

【问题讨论】:

【参考方案1】:

这个问题有点宽泛,所以我在这里只举一个最小(抽象)的例子:

我们的数据集中有 6 个 (= n) 向量,每个向量都有 d 位。假设我们做了 2 (= N) 随机排列。

让第一次随机排列开始!请记住,我们置换不是向量的顺序。排列后,它们保持顺序,例如:

v1
v5
v0
v3
v2
v4

现在查询向量 q 到达,但它(几乎)不太可能与我们数据集中的向量(在排列之后)相同,因此我们赢了不通过二分查找找到它。

但是,我们最终会出现在两个向量之间。所以现在我们可以想象场景是这样的(例如q位于v0和v3之间:

v1
v5
v0 <-- up pointer
   <-- q lies here
v3 <-- down pointer
v2
v4

现在我们向上或向下移动指针,寻找与q 匹配最多位的vi 向量。假设它是 v0。

类似地,我们进行第二次置换,我们找到了向量 vi,比如说 v4。我们现在比较第一个排列的 v0 和 v4,看看哪个最接近q,即哪个与q 相等的位数最多。


编辑

说执行 N 个排列的总成本是 O(Nnlogn) 是否正确,因为我们必须对它们中的每一个进行排序?

如果他们真的从头开始对每个排列进行排序,那么是的,但我不清楚他们是如何做到的。

上述的排列+排序过程在预处理过程中只执行一次,或者对于每个查询q?

一次

在最后一点,我们将v0v4q 进行比较,我们比较它们的置换版本还是原始版本(置换之前)?

认为他们使用置换版本来做到这一点(请参阅论文中2N 之前的括号)。但这不会有任何区别,因为它们也用相同的置换 (σ) 置换 q


这个quora answer 也可能会有所启发。

【讨论】:

完成@justHelloWorld!现在答案似乎完全完成了,谢谢! 在这里找到了代码的实现here 太棒了@justHelloWorld。顺便说一句,好问题。 你是对的 :) 如果你仍然对这个话题感兴趣,check this out Hello @justHelloWorld :) 检查我的编辑,基本上可以归结为 this!

以上是关于在局部敏感散列中搜索的主要内容,如果未能解决你的问题,请参考以下文章

在滚动散列中,散列函数的除法方法中使用的素数与为数字选择的基数之间的关系是啥?

如何根据散列中的键/值查找键/值数据并将其添加到 Redis 中的散列?

将值推入散列中的数组

有没有办法在oracle sql developer中对列的每个字段执行md5散列,并将结果散列存储在相应的列中(md5)

如何避免嵌套散列中缺少元素的 NoMethodError,而无需重复的 nil 检查?

如何交换散列中的键和值