一、什么是SimHash

SimHash算法是Google在2007年发表的论文《Detecting Near-Duplicates for Web Crawling》中提到的一种指纹生成算法,被应用在Google搜索引擎网页去重的工作之中。

对于文本去重这个问题,常见的解决办法有余弦算法、欧式距离、Jaccard相似度、最长公共子串等方法。但是这些方法并不能对海量数据高效的处理。

比如说,在搜索引擎中,会有很多相似的关键词,用户所需要获取的内容是相似的,但是搜索的关键词却是不同的,如“北京好吃的火锅“和”哪家北京的火锅好吃“,是两个可以等价的关键词,然而通过普通的hash计算,会产生两个相差甚远的hash串。而通过SimHash计算得到的Hash串会非常的相近,从而可以判断两个文本的相似程度。

二、局部性敏感哈希

说到hash可能我们第一个想到的是md5这种信息摘要算法,可能两篇文本只有一个标点符号的差距,但是两篇文本A和B的md5值差异就非常大,感兴趣的可以试验一下看看。

有时候我们希望的是原本相同的文章做了微小改动之后的哈希值也是相似的,这种哈希算法称为局部敏感哈希LSH(Locality Sensitive Hashing),这样我们就能从哈希值来推断相似的文章。

局部敏感哈希算法使得在原来空间相似的样本集合,进行相关运算映射到特定范围空间时仍然是相似的,这样还不够,还需要保证原来不相似的哈希之后仍然极大概率不相似,这种双向保证才让LSH的应用成为可能。

三、simhash的基本过程

SimHash算法主要有五个过程:分词、Hash、加权、合并、降维。
借用一张网络上经典的图片来描述整个过程:

SimHash算法原理
1.分词(可以用一些分词工具来实现)

使用分词手段将文本分割成关键词的特征向量,分词方法有很多,我用了jieba分词来实现,你可以先去除停用词,当然也可以不去除,根据自己的需求选择,假设分割后的特征实词如下:

12306 服务器 故障 车次 加载失败 购买 候补订单 支付 官方 消费者 建议 卸载 重装 切换网络 耐心 等待

目前的词只是进行了分割,但是词与词含有的信息量是不一样的,比如12306 服务器 故障 这三个词就比 支付 卸载 重装更能表达文本的主旨含义,这也就是所谓信息熵的概念。

为此我们还需要设定特征词的权重,方法有很多,简单一点的可以使用TF-IDF来实现。

2.Hash

前面我们使用分词方法和权重分配将文本就分割成若干个带权重的实词,比如权重使用1-5的数字表示,1最低5最高,这样我们就把原文本处理成如下的样式:

12306(5) 服务器(4) 故障(4) 车次(4) 加载失败(3) 购买(2) 候补订单(4) 支付(2) 官方(2) 消费者(3) 建议(1) 卸载(3) 重装(3) 切换网络(2) 耐心(1) 等待(1)

然后,通过hash函数对每一个词向量进行映射,产生一个n位二进制串,一般常用的位数为32、64、128。

3.加权

前面的计算我们已经得到了每个词向量的Hash串和该词向量对应的权重,这一步我们计算权重向量W=hash*weight。

具体的计算过程如下:hash二进制串中为1的,w = 1 * weight,二进制串中为0的,w = weight * -1.

举个例子,12306的带权重哈希值为 [5 -5 -5 5 5 5 -5 -5],服务器的带权重哈希值为 [-4 4 4 4 -4 4 -4 4]

4.合并

对于一个文本,我们计算出了文本分词之后每一个特征词的权重向量,在合并这个阶段,我们把文本所有词向量的权重向量相累加,得到一个新的权重向量,假定最终结果为 [18 9 -6 -9 22 -35 12 -5]

5.降维

对于前面合并后得到的文本的权重向量,大于0的位置1,小于等于0的位置0,就可以得到该文本的SimHash值,以上面提到的 [18 9 -6 -9 22 -35 12 -5] 为例,我们得到 [1 1 0 0 1 0 1 0] 这个bit串,也就是论文中提及的该文本的指纹。
到此为止,我们已经计算出了一个文本的SimHash值。那么,如何判断两个文本是否相似呢?我们要用到海明距离。

四、相似度判断

对于两个文本的SimHash的相似度判断,我们使用海明距离来计算。

什么是海明距离呢?

简单的说,海明距离可以理解为,两个二进制串之间相同位置不同的个数。举个例子,[1,1,1,0,0,0]和[1,1,1,1,1,1]的海明距离就是3。

在处理大规模数据的时候,我们一般使用64位的SimHash,正好可以被一个long型存储。这种时候,海明距离在3以内就可以认为两个文本是相似的。

五、大规模数据下的海明距离计算

我们在存储时将64bit simhash值均分为4份每份16bit长,然后使用每一份作为key,value是每一份simhash值对应的二进制向量,如下图所示:

SimHash算法原理

当新来一个文本生成哈希值S'之后,按照相同的规则生成abcd四部分,之后逐个进行哈希对比,这个时间复杂度是O(1):

  • 如果abcd四个作为key都不存在,那么可以认为S'没有相似的文本;
  • 如果abcd四个key中有命中,那么就开始遍历对应key的value,查看是否满足<=3的海明距离确定相似性;(一般64位编码的simhash值对应的海明距离阈值设为3)
  • 如果上一个命中的key未找到相似文本,则继续遍历剩下的key,重复相同的过程,直至所有的key全部遍历完或者命中相似文本,则结束。

六、参考文献:

https://blog.csdn.net/Daverain/article/details/80919418

https://juejin.im/post/5e0421bc6fb9a0165d74f17f

项目:取Github搜一下就有,可以找来看看,还是比较容易懂的。

分类:

技术点:

相关文章: