15 | 最近邻检索(上):如何用局部敏感哈希快速过滤相似文章?

你好,我是陈东。

在搜索引擎和推荐引擎中,往往有很多文章的内容是非常相似的,它们可能只有一些修饰词不同。如果在搜索结果或者推荐结果中,我们将这些文章不加过滤就全部展现出来,那用户可能在第一页看到的都是几乎相同的内容。这样的话,用户的使用体验就会非常糟糕。因此,在搜索引擎和推荐引擎中,对相似文章去重是一个非常重要的环节。

对相似文章去重,本质上就是把相似的文章都检索出来。今天,我们就来聊聊如何快速检索相似的文章。

如何在向量空间中进行近邻检索?

既然是要讨论相似文章的检索,那我们就得知道,一篇文章是怎么用计算机能理解的形式表示出来的,以及怎么计算两篇文章的相似性。最常见的方式就是使用向量空间模型(Vector Space Model)。所谓向量空间模型,就是将所有文档中出现过的所有关键词都提取出来。如果一共有n个关键词,那每个关键词就是一个维度,这就组成了一个n维的向量空间。

那一篇文档具体该如何表示呢?我们可以假设,一篇文章中有k(0<k<=n)个关键词,如果第k个关键词在这个文档中的权重是w,那这个文档在第k维上的值就是w。一般来说,我们会以一个关键词在这篇文档中的TF-IDF值作为w的值。而如果文章不包含第k个关键词,那它在第k维上的值就是0,那我们也可以认为这个维度的权重就是0。这样,我们就可以用一个n维的向量来表示一个文档了,也就是<w1,w2,w3,……wn>。这样一来,每一个文档就都是n维向量空间中的一个点。

那接下来,计算两个文章相似度就变成了计算两个向量的相似度。计算向量相似度实际上就是计算两个向量的距离,距离越小,它们就越相似。具体在计算的时候,我们可以使用很多种距离度量方式。比如说,我们可以采用余弦距离,或者采用欧氏距离等。一般来说,我们会采用余弦距离来计算向量相似度。

拓展到搜索引擎和推荐引擎中,因为每个文档都是n维向量中的一个点,所以查询相似文章的问题,就变成了在n维空间中,查询离一个点距离最近的k个点的问题。如果把这些“点”想象成“人”,这不就和我们在二维空间中查询附近的人的问题非常类似了吗?这就给了我们一个启发,我们是不是也能用类似的检索技术来解决它呢?下面,我们一起来看一下。

首先,在十几维量级的低维空间中,我们可以使用k-d树进行k维空间的近邻检索,它的性能还是不错的。但随着维度的增加, 如果我们还要精准找到最邻近的k个点,k-d需要不停递归来探索邻接区域,检索效率就会急剧下降,甚至接近于遍历代价。当关键词是几万乃至百万级别时,文档的向量空间可能是一个上万维甚至是百万维的超高维空间,使用k-d树就更难以完成检索工作了。因此,我们需要寻找更简单、高效的方案。

这个时候,使用非精准Top K检索代替精准Top K检索的方案就又可以派上用场了。这是为什么呢?因为高维空间本身就很抽象,在用向量空间中的一个点表示一个对象的过程中,如果我们选择了不同的权重计算方式,那得到的向量就会不同,所以这种表示方法本身就已经损失了一定的精确性。

因此,对于高维空间的近邻检索问题,我们可以使用近似最近邻检索(Approximate Nearest Neighbor)来实现。你可以先想一想查询附近的人是怎么实现的,然后再和我一起来看高维空间的近似最近邻检索是怎么做的。

什么是局部敏感哈希?

借助非精准检索的思路,我们可以将高维空间的点也进行区域划分,然后为每个区域都生成一个简单的一维编码。这样,当我们要查找一个点最邻近的k个点的时候,直接计算出区域编码就能高效检索出同一个区域的所有对象了。

也因此,我们就能得出一个结论,那就是同一个区域中的不同的点,通过统一的计算过程,都能得到相同的区域编码。这种将复杂对象映射成简单编码的过程,是不是很像哈希的思路?

所以,我们可以利用哈希的思路,将高维空间中的点映射成低维空间中的一维编码。换句话说,我们通过计算不同文章的哈希值,就能得到一维哈希编码。如果两篇文章内容100%相同,那它们的哈希值就是相同的,也就相当于编码相同。

不过,如果我们用的是普通的哈希函数,只要文档中的关键词有一些轻微的变化(如改变了一个字),哈希值就会有很大的差异。但我们又希望,整体相似度高的两篇文档,通过哈希计算以后得到的值也是相近的。因此,工业界设计了一种哈希函数,它可以让相似的数据通过哈希计算后,生成的哈希值是相近的(甚至是相等的)。这种哈希函数就叫作局部敏感哈希(Locality-Sensitive Hashing)。

其实局部敏感哈希并不神秘。让我们以熟悉的二维空间为例来进一步解释一下。

在二维空间中,我们随意划一条直线就能将它一分为二,我们把直线上方的点的哈希值定为1,把直线下方的点的哈希值定为0。这样就完成一个简单的哈希映射。通过这样的随机划分,两个很接近的点被同时划入同一边的概率,就会远大于其他节点。也就是说,这两个节点的哈希值相同的概率会远大于其他节点。

当然,这样的划分有很大的随机性,不一定可靠。但是,如果我们连续做了n次这样的随机划分,这两个点每次都在同一边,那我们就可以认为它们在很大概率上是相近的。因此,我们只要在n次随机划分的过程中,记录下每一个点在每次划分后的值是0还是1,就能得到一个n位的包含0和1的序列了。这个序列就是我们得到的哈希值,也就是区域编码。

因此,对于高维空间,我们构造局部敏感哈希函数的方案是,随机地生成n个超平面,每个超平面都将高维空间划分为两部分。位于超平面上面的点的哈希值为1,位于超平面下方的点的哈希值为0。由于有n个超平面,因此一个点会被判断n次,生成一个n位的包含0和1的序列,它就是这个点的哈希值。这就是一个基于超平面划分的局部敏感哈希构造方法。(为了方便你直观理解,我简单说成了判断一个点位于超平面的上面还是下面。在更严谨的数学表示中,其实是求一个点的向量和超平面上法向量的余弦值,通过余弦值的正负判断是1还是0。这里,你理解原理就可以了,严谨的数学分析我就不展开了。)

如果有两个点的哈希值是完全一样的,就说明它们被n个超平面都划分到了同一边,它们有很大的概率是相近的。即使哈希值不完全一样,只要它们在n个比特位中有大部分是相同的,也能说明它们有很高的相近概率。

上面我们说的判断标准都比较笼统,实际上,在利用局部敏感哈希值来判断文章相似性的时候,我们会以表示比特位差异数的海明距离(Hamming Distance)为标准。我们可以认为如果两个对象的哈希值的海明距离低于k,它们就是相近的。举个例子,如果有两个哈希值,比特位分别为00000和10000。你可以看到,它们只有第一个比特位不一样,那它们的海明距离就是1。如果我们认为海明距离在2之内的哈希值都是相似的,那它们就是相似的。

SimHash是怎么构造的?

不过,这种构造局部敏感哈希函数的方式也有一些缺陷:在原来的空间中,不同维度本来是有着不同权重的,权重代表了不同关键词的重要性,是一个很重要的信息。但是空间被n个超平面随机划分以后,权重信息在某种程度上就被丢弃了。

那为了保留维度上的权重,并且简化整个函数的生成过程,Google提出了一种简单有效的局部敏感哈希函数,叫作SimHash。它其实是使用一个普通哈希函数代替了n次随机超平面划分,并且这个普通哈希函数的作用对象也不是文档,而是文档中的每一个关键词。这样一来,我们就能在计算的时候保留下关键词的权重了。这么说有些抽象,让我们一起来看看SimHash的实现细节。

方便起见,我们就以Google官方介绍的64位的SimHash为例,来说一说它构造过程。整个过程,我们可以总结为5步。

  1. 选择一个能将关键词映射到64位正整数的普通哈希函数。
  2. 使用该哈希函数给文档中的每个关键词生成一个64位的哈希值,并将该哈希值中的0修改为-1。比如说,关键词A的哈希值编码为<1,0,1,1,0>,那我们做完转换以后,编码就变成了<1,-1,1,1,-1>。
  3. 将关键词的编码乘上关键词自己的权重。如果关键词编码为<1,-1,1,1,-1>,关键词的权重为2,最后我们得到的关键词编码就变成了<2,-2,2,2,-2>。
  4. 将所有关键词的编码按位相加,合成一个编码。如果两个关键词的编码分别为<2,-2,2,2,-2>和<3,3,-3,3,3>,那它们相加以后就会得到<5,1,-1,5,1>。
  5. 将最终得到的编码中大于0的值变为1,小于等于0的变为0。这样,编码<5,1,-1,5, 1>就会被转换为<1,1,0,1,1>。

通过这样巧妙的构造,SimHash将每个关键词的权重保留并且叠加,一直留到最后,从而使得高权重的关键词的影响能被保留。从上图中你可以看到,整个文档的SimHash值和权重最大的关键词word 2的哈希值是一样的。这就体现了高权重的关键词对文档的最终哈希值的影响。此外,SimHash通过一个简单的普通哈希函数就能生成64位哈希值,这替代了随机划分64个超平面的复杂工作,也让整个函数的实现更简单。

如何对局部敏感哈希值进行相似检索?

和其他局部敏感哈希函数一样,如果两个文档的SimHash值的海明距离小于k,我们就认为它们是相似的。举个例子,在Google的实现中,k的取值为3。这个时候,检索相似文章的问题变成了要找出海明距离在3之内的所有文档。如果是一个个文档比对的话,这就是一个遍历过程,效率很低。有没有更高效的检索方案呢?

一个直观的想法是,我们可以针对每一个比特位做索引。由于每个比特位只有0和1这2个值,一共有64个比特位,也就一共有2*64共128个不同的Key。因此我们可以使用倒排索引,将所有的文档根据自己每个比特位的值,加入到对应的倒排索引的posting list中。这样,当要查询和一个文档相似的其他文档的时候,我们只需要通过3步就可以实现了,具体的步骤如下:

  1. 计算出待查询文档的SimHash值;
  2. 以该SimHash值中每个比特位的值作为Key,去倒排索引中查询,将相同位置具有相同值的文档都召回;
  3. 合并这些文档,并一一判断它们和要查询的文档之间的海明距离是否在3之内,留下满足条件的。

我们发现,在这个过程中,只要有一个比特位的值相同,文档就会被召回。也就是说,这个方案和遍历所有文档相比,其实只能排除掉“比特位完全不同的文档”。因此,这种方法的检索效率并不高。

这又该怎么优化呢?Google利用抽屉原理设计了一个更高效的检索方法。什么是抽屉原理呢?简单来说,如果我们有3个苹果要放入4个抽屉,就至少有一个抽屉会是空的。那应用到检索上,Google会将哈希值平均切为4段,如果两个哈希值的比特位差异不超过3个,那这三个差异的比特位最多出现在3个段中,也就是说至少有一个段的比特位是完全相同的!因此,我们可以将前面的查询优化为“有一段比特位完全相同的文档会被召回”。

根据这个思路,我们可以将每一个文档都根据比特位划分为4段,以每一段的16个比特位的值作为Key,建立4个倒排索引。检索的时候,我们会把要查询文档的SimHash值也分为4段,然后分别去对应的倒排索引中,查询和自己这一段比特位完全相同的文档。最后,将返回的四个posting list合并,并一一判断它们的的海明距离是否在3之内。

通过使用SimHash函数和分段检索(抽屉原理),使得Google能在百亿级别的网页中快速完成过滤相似网页的功能,从而保证了搜索结果的质量。

重点回顾

今天,我们重点学习了使用局部敏感哈希的方法过滤相似文章。

我们可以使用向量空间模型将文章表示为高维空间中的点,从而将相似文章过滤问题转为高维空间的最近邻检索问题。对于高维空间的最近邻检索问题,我们可以使用非精准的检索思路,使用局部敏感哈希为高维空间的点生成低维的哈希值。

局部敏感哈希有许多构造方法,我们主要讲了随机超平面划分和SimHash两种方法。相比于随机超平面划分,SimHash能保留每一个关键词的权重,并且它的函数实现也更简单。

那对于局部敏感哈希的相似检索,我们可以使用海明距离定义相似度,用抽屉原理进行分段划分,从而可以建立对应的倒排索引,完成高效检索。

实际上,不仅过滤相似文章可以使用局部敏感哈希,在拍照识图和摇一摇搜歌等应用场景中,我们都可以使用它来快速检索。以图像检索为例,我们可以对图像进行特征分析,用向量来表示一张图片,这样一张图片就是高维空间中的一个点了,图像检索就也抽象成了高维空间中的近邻检索问题,也就可以使用局部敏感哈希来完成了。

当然基于局部敏感哈希的检索也有它的局限性。以相似文章检索为例,局部敏感哈希更擅长处理字面上的相似而不是语义上的相似。比如,一篇文章介绍的是随机超平面划分,另一篇文章介绍的是SimHash,两篇文章可能在字面上差距很大,但内容领域其实是相似的。好的推荐系统在用户看完随机超平面划分的文章后,还可以推荐SimHash这篇文章,但局部敏感哈希在这种语义相似的推荐系统中就不适用了。

因此,对于更灵活的相似检索问题,工业界还有许多的解决方法,我们后面再详细介绍。

课堂讨论

1.对于SimHash,如果将海明距离在4之内的文章都定义为相似的,那我们应该将哈希值分为几段进行索引和查询呢?

2.SimHash的算法能否应用到文章以外的其他对象?你能举个例子吗?

欢迎在留言区畅所欲言,说出你的思考过程和最终答案。如果有收获,也欢迎把这一讲分享给你的朋友。

精选留言

  • paulhaoyi

    2020-04-30 08:10:05

    感觉局部敏感hash和深度学习中的embedding好相近啊,都是临近点的向量表示很相近。不知道应用中有没有相互替换的场景。
    作者回复

    你说的很对。其实局部敏感哈希和embedding,都是对高维空间的点进行降维,用更低维的向量来表示,但又要保留原来的核心特征。从这个角度来说,它们的思路是一致的。
    你可以认为局部敏感哈希是基于规则的embedding。因此在一些应用中,是有可能可以替换使用的。

    2020-04-30 10:51:07

  • 那时刻

    2020-04-29 08:13:48

    与simHash类似的还有个minHash,查了资料对比了下,貌似是minHash对于权重处理不是很好,而且处理时候因为要计算多个hash函数,占用更多CPU资源,而superminhash在处理速度上更胜一筹。不知理解是否正确?

    讨论问题:
    1. 最开始想法是对于4位不同,采用5段分割,但是对于64bit,5段不能整除。可以增大分割的段数,可采用8段分割来计算。
    2. 暂时没想到其它具体应用
    作者回复

    minhash的确也是另一种局部敏感哈希算法。它是基于Jaccard距离的一种算法。而不是基于余弦距离。因此它更适合做集合相似度这类的判断。
    包括计算过程的确比simhash更复杂。

    关于课后题:
    1.根据抽屉原理,的确使用五段以上的分割都可以。不能整除其实问题不大,不过考虑到代码简洁性和空间平衡划分,分成8段是不错的答案。
    2.其实我文中已经举了一个例子,就是判断图片相似度,我们可以将每个维度的特征取出,用Simhash的思路进行处理即可。因此simhash不仅仅可用于文章相似度判断,而是可以用于抽象的物品相似度判断。

    2020-04-29 18:23:51

  • 2020-05-03 22:46:37

    对于思考题:
    1:利用抽屉性原理,可以分为 5段保证,至少有一段是相等的,但是我看下面的老师评论说,最好分为 8段,但是这样的话相似度准确性是不是会降低很多? 因为分为 8段 的话至少要有 4个是相等的, 还是分为8段的时候进行了特殊处理?
    2: 还可以对其他东西,比如图片,歌曲进行特征向量提取,再利用局部敏感哈希函数,这里还不用考虑语义上的相似
    作者回复

    1.其实从抽屉原理来看,五段以上都可以。比如说五段的比特位个数分为13,13,13,13,12。但是从计算机的实现来看,读取和处理13个比特位的效率并不高。不如读取和处理8个比特位(一个字节)高效。因此可以以8个比特位为单位处理。
    然后,这个相似度判断的流程是分为召回和排序两阶段。分成八段只是方便召回,召回了候选集以后,我们还需要基于海明距离进行排序,海明距离小于k的元素才会被留下。因此,分段的多少只会影响检索效率,不会影响最后判断相似性的精准度。

    2020-05-04 10:56:16

  • 明翼

    2020-05-05 10:07:04

    这篇文章干货很多,这是很好的思路。说下我的理解,局部敏感hash关注点在于保持相似性的原文hash也相似,我一般用hash多是检验是否修改过了,或者判断是否存在比如布隆过滤器。谷歌的那个算法更是让我开了眼界,通过计算词的hash得到64bit序列,为叠加权重将0改成-1,我们如果不修改那和权重相乘的结果是0,叠加成文章权重的时候,权重很小的关键词和权重很大的关键词在这一位的影响是一样的了,然后将所有的关键词叠加保证了大权重关键词影响大,比如大关键词在一位中为-1,那最终结果很可能这一位为负数,最终为了方便比较可以说做了另外一个映射,映射成0和1这种64位比特流,因为这样和二进制对应。后面的海明距离的就更巧妙了,分割数据看成多个段,回答下问题吧:
    1. 海明距离4为区分度,那分割成五段的话,至少有一段是完全相同的,不过这样分割不太好分割,分割成8段,我理解的过程为0-7为一组8-15 16-23一次类推分成8个组后,每个组都有8位,那每组就有16个不同的key因为2*8,后面postlist为哪些文章的哪些位对应这组key,查询文章过来后,找到相同的key的所有文章,这样我们得到8组文章,然后既然距离为4,我们可以每两个组求交集,每求三次仍然保留的满足条件,抽出来作为结果集,这个求的过程好好设计。
    2. 这种算法可以用在推荐爱好相似的好友上,比如我们给用户打不同的标签,所有的标签组成一个文章,按照上述算法求相近的用户,推荐为好友;相似路径是不是可以,我们把一段距离之间的几个关键经过点标记出来作为词,然后比较相似性。图片音乐这种也适合;图书如果打上标签,或者用图书关键词也合适
    作者回复

    simhash的设计和检索的确都很巧妙。不得不说,Google的搜索引擎中的确有着许多亮点。这些技术可以说是Google帝国的地基。
    1.分组以后,每组并不是只有16个key,而是2^8共256个key。这样如果两篇文章有一段8个比特位是相同的,它们就会在这个key对应的posting list中。
    2.相似路径,图片,音乐,这些都是很好地使用局部敏感哈希的场景,因为它们都是字面相似的。好友推荐和文章推荐可能会更重视语意推荐一些。不过局部敏感哈希也是可以尝试的。

    2020-05-05 13:27:50

  • 2020-05-03 22:37:16

    每一个文档都根据比特位划分为 4 段,以每一段的 16 个比特位的值作为 Key,建立 4 个倒排索引
    -------------------------------
    这里是怎么 以 16 个比特位的值作为 Key 建立倒排索引的呢? 怎么把文档分配到这四个 posting list 中的? 这里没有理解

    还有下面的分段查询的图中,怎么每个倒排索引里面 还有以key建的倒排索引? 这里的key是每一段的 位取值吗?0- 2^16-1 个倒排索引?
    作者回复

    首先,“四个倒排索引”不是“只有四个posting list”。每个倒排索引中,都会有多个key和对应的posting list。
    然后分段查询的图,你的理解是对的。我再详细描述一下。
    我们将16个比特位看着是一个值。这样,就可以用这个值作为key来建立倒排索引。
    比如说,我们有100个元素,我们先看它们哈希值的前16个比特位,如果这100个元素的前16个比特位几乎都是相同的,比如说只有两种情况,那么倒排索引就只有两个key,然后这100个元素就会根据自己的值,加入到对应的key的posting list中。
    同理,再看下一个16个比特位,如果这100个元素在这一段上,一共有k种值的话,那么就会生成k个key,然后将这100个元素加入对应的key后面的posting list中。依此类推。

    希望这样的分析能解答你的疑惑。

    2020-05-04 10:46:58

  • 范闲

    2020-04-29 07:16:53

    1.距离相近的点比距离相远的点更容易发生Hash碰撞,这是局部敏感哈希的理论根据
    2. LSH family有hyperplane和crosspoltye的,同样SimHash也是一种方法
    3.文章中的例子都是关键词的,实际上现在可以做成embedding的比较吧,这样关键信息的丢失会更少
    4.所有的ANN相关算法,都是建立在对全空间的不断划分上,将全空间划分为若干子空间,然后在子空间里搜索最近邻.

    思考题目:
    1.如果4位以内的不同,都可以认为比较相似,那么划分的时候64位应该划分成8段比较合适。

    2.除了文章,其他的embedding的相似性求解也可以。
    作者回复

    你对局部敏感哈希归纳得挺好。包括ann(近似最近邻)的算法,本质都是建立在对全空间的不断划分上,在子空间进行检索。你会发现,这其实和我们在第一讲就提到过的二分查找的核心思想是一致的。
    关于思考题:
    1.根据抽屉原理,五段以上其实都可以。当然从代码简洁程度和空间均匀划分角度来看,八段是比较简洁的。
    2.的确是这样的。有这么一句话“万物皆可embedding”。其实许多事物都可以抽象成高维向量空间的点,都可以使用局部敏感哈希的思路检索。只要把每个维度的特征拿出来,用Simhash的方法处理即可。

    2020-04-29 18:08:46

  • innocent

    2020-05-14 00:27:44

    请问老师,业界主流的文本相似度计算就是采用局部哈希么
    作者回复

    并不是哦。我在文章结尾也说了局部敏感哈希更多的是用来判断字面上是否有大范围重复,但是对于语义上的相似处理得并不好。

    业界主流的文本相似度计算是这样的:
    1.最基础的是基于tf-idf的向量空间,用余弦距离来求相似度。
    2.但原始的向量空间维度太高,效果也不好,因此之前业界会采用分析潜在语义的PLSA和LDA主题模型进行文本分析,得到降维的向量,从而更好地计算向量相似度。
    3.而现在,随着深度学习的普及,业界会使用dssm-lstm,还有doc2vec来将文本学习成低维的向量,从而可以计算向量相似度。

    2020-05-14 20:37:56

  • wangkx

    2020-05-12 07:17:25

    通过学习这一讲,我联想到了虚拟内存到物理内存的页表映射方法。在映射时,虚拟内存的高位用于从映射到物理内存,低位作为偏移量,然后得到真实的物理地址。

    老师,我联想的对吗?
    作者回复

    哈哈,既然是联想,那怎么想都可以。你这个联想的关键词是映射,的确计算机的世界中,会有许多映射关系。
    你举的这个例子,是一一映射的关系,一个虚拟地址对应一个物理地址。
    而文章中的例子,就不是一一映射了,这种高维到低维的映射,会将多个高维的地址映射到低维的同一个地址中。这样会起到降维和压缩的作用。

    2020-05-12 11:37:40

  • ifelse

    2023-04-15 15:33:39

    学习打卡,干货满满
  • Ignite

    2021-10-12 14:50:07

    由于每个比特位只有 0 和 1 这 2 个值,一共有 64 个比特位,也就一共有 2*64 共 128 个不同的 Key。为啥是2*64而不是2^64
    作者回复

    因为我们现在是在构造倒排索引,因此每个比特位上值相同的数都在一个posting list中。每个比特位会产生2个posting list(0和1各有一个posting list),因此一共有128个

    2021-11-13 22:35:14

  • benny

    2020-06-11 22:03:25

    分八段后,要找至少四段相同的吧?这块处理有啥特殊技巧?
    作者回复

    这是一个好问题,分成八段以后,是否有啥特殊的处理技巧?其实是可以有的。
    我们先看看不做特殊处理是怎么做的。常规情况下,我们只需要将这八段作为八个key去检索倒排表,然后将倒排表中的结果取并集,并对集合中的每个结果和查询的值进行比较,计算海明距离。
    但如果考虑到,如果有一个文档有至少四段都是相同的才是符合条件的,而只有三段相同或者两段相同的都应该被过滤掉,那么我们可以做这么一个优化:在合并集合的时候,对每个结果进行计数,看看它在这八段中有几段是相同的。然后,我们根据这个计数,将少于四段相同的都快速过滤掉。对于剩下的结果,再来精确计算海明距离。这就是一个“粗排+精排”的两阶段排序过程了。

    2020-06-12 12:53:10

  • 时隐时现

    2020-05-09 11:20:51

    多谢老师的精彩分享,有2个小问题:
    1、SimHash的前4步都可以理解,但是最后一步 “将最终得到的编码中大于 0 的值变为 1,小于等于 0 的变为 0。这样,编码 <5,1,-1,5, 1> 就会被转换为 <1,1,0,1,1>。”
    似懂非懂,多少还是不太能理解,这样当真不会让最高权重的关键词影响受损吗?那么2和9,最后都变成1,感觉9"吃亏了",^—^...
    2、还有1个小问题,SimHash表示的hash编码,在计算过程中,<3,3,-3,3,3>,会不会出现单个数值变成2位甚至是3位数的情况,如果会,在算法具体实现时,每个数值用1bit还是1byte来表示?
    作者回复

    1. 如果是你这个case,的确是9比2吃亏。但整体来看,一篇文章中是有多个关键词的,各个位都有正有负,因此会相互抵消,最终权重大的关键词对相应的位的贡献会更大。你可以想象成拔河比赛,最终只看标志被拉到左边还是右边,两队人数均等,但是在拉扯的过程中,出力大的一方会获胜。
    2.代码实现的话,每个位是一个数值,那当然不能用一个bit来表示,其实就是一个int的数组。因此,当然可以累加值是两位数

    2020-05-09 16:16:37

  • LDxy

    2020-04-30 23:14:39

    当关键词是几万乃至百万级别时,文档的向量空间可能是一个上万维甚至是百万维的超高维空间,使用 k-d 树就更难以完成检索工作了。
    ——这是不是就是万维网这个名称的由来?
    作者回复

    哈哈哈哈,上万维的神经网络,还真可以简称为万维网。

    ps:万维网是www(world wide web)的翻译,这是我觉得非常符合“信达雅”标准的翻译。不过没想到还能被你赋予了新含义~

    2020-05-01 00:38:44

  • armatrix

    2021-10-11 20:17:38

    “由于每个比特位只有 0 和 1 这 2 个值,一共有 64 个比特位,也就一共有 2*64 共 128 个不同的 Key”这个应该是2^64个?
    作者回复

    不是。的确就是2*64共128个。因为我们现在是在构造倒排索引,因此每个比特位上值相同的数都在一个posting list中。每个比特位会产生2个posting list(0和1各有一个posting list),因此一共有128个

    2021-11-13 22:34:33

  • anker

    2021-08-09 14:05:50

    1. 对于 SimHash,如果将海明距离在 4 之内的文章都定义为相似的,那我们应该将哈希值分为几段进行索引和查询呢?
    答:k = 4时,可以采取分割为八份,为啥不选择5呢,CPU计算对于2的倍数计算天然友好。
    分割为八份的时候,posting list 可以采取B+树存储,进行多路归并,把N路中,相同的key才需要进行海明距离的计算,可以减少很多计算量

    2.SimHash 的算法能否应用到文章以外的其他对象?你能举个例子吗?
    答:可以处理人的声音识别用于刑侦技术
  • Bachue Zhou

    2020-12-24 08:57:42

    我对局部敏感哈希还是抱有怀疑,这个和二分搜索不同,二分搜索每次比较都能排除掉一半的数据,但是随机划分超平面却不一定,可能一开始 n 较小的时候,每次划分都能排除近一半的可能,但随着 n 的提高,排除的概率越来越低,我无法计算当 n 要达到什么程度的时候,两点哈希相同距离确实较近的概率能高于百分之九十九。
    作者回复

    其实你可以参考一下前面介绍过的跳表,跳表也是通过随机来完成近似二分查找的效果,并且维护代价很低。
    局部敏感哈希也是类似的思路,通过简单的随机划分,来从概率上完成快速划分查找空间的效果。
    当然,局部敏感哈希的确不够精确,因此我们才会有更多的更复杂,但是也更精准的高维检索技术。

    2020-12-27 21:54:31

  • 时隐时现

    2020-05-09 11:33:15


    刚刚发了2个小问题,系统还没放出来,再追加第3个小问题,希望老师有空解答一下。
    3、这种依靠关键词过滤查找相似文章的算法,能不能用到论文放抄袭上?但是一篇论文有太多的字和关键字,就算用SimHash和抽屉优化,也要对每个字或者关键字挨个比对一遍吗?有没有更优化的算法?
    作者回复

    直接使用Simhash对论文进行判重并不是太合适。
    因为论文其实整体相似度有30%就算是抄袭了。甚至有连续20个字都相同就算抄袭。这个重复率对simhash而言太低。
    不过,对于那种把句子重写,关键词换汤不换药的改写论文而言,说不定simhash会有意想不到的效果。它能将关键词词提炼出来(或者我们可以扩大范围,提炼关键句子),然后加权求和。这样其实是能有一定效果的。

    2020-05-09 16:35:30