`

海量数据相似度计算之simhash和海明距离

阅读更多

通过 采集系统 我们采集了大量文本数据,但是文本中有很多重复数据影响我们对于结果的分析。分析前我们需要对这些数据去除重复,如何选择和设计文本的去重算法?常见的有余弦夹角算法、欧式距离、Jaccard相似度、最长公共子串、编辑距离等。这些算法对于待比较的文本数据不多时还比较好用,如果我们的爬虫每天采集的数据以千万计算,我们如何对于这些海量千万级的数据进行高效的合并去重。最简单的做法是拿着待比较的文本和数据库中所有的文本比较一遍如果是重复的数据就标示为重复。看起来很简单,我们来做个测试,就拿最简单的两个数据使用Apache提供的 Levenshtein for 循环100w次计算这两个数据的相似度。代码结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
            String s1 = "你妈妈喊你回家吃饭哦,回家罗回家罗" ;
            String s2 = "你妈妈叫你回家吃饭啦,回家罗回家罗" ;

            long t1 = System.currentTimeMillis();

            for (int i = 0; i < 1000000; i++) {
                   int dis = StringUtils .getLevenshteinDistance(s1, s2);
            }

            long t2 = System.currentTimeMillis();

            Systemout .println(" 耗费时间: " + (t2 - t1) + "  ms ");

耗费时间: 4266 ms

大跌眼镜,居然计算耗费4秒。假设我们一天需要比较100w次,光是比较100w次的数据是否重复就需要4s,就算4s一个文档,单线程一分钟才处理15个文档,一个小时才900个,一天也才21600个文档,这个数字和一天100w相差甚远,需要多少机器和资源才能解决。

为此我们需要一种应对于海量数据场景的去重方案,经过研究发现有种叫 local sensitive hash 局部敏感哈希 的东西,据说这玩意可以把文档降维到hash数字,数字两两计算运算量要小很多。查找很多文档后看到google对于网页去重使用的是simhash,他们每天需要处理的文档在亿级别,大大超过了我们现在文档的水平。既然老大哥也有类似的应用,我们也赶紧尝试下。simhash是由 Charikar 在2002年提出来的,参考 《Similarity estimation techniques from rounding algorithms》 。 介绍下这个算法主要原理,为了便于理解尽量不使用数学公式,分为这几步:

  • 1、分词,把需要判断文本分词形成这个文章的特征单词。最后形成去掉噪音词的单词序列并为每个词加上权重,我们假设权重分为5个级别(1~5)。比如:“ 美国“51区”雇员称内部有9架飞碟,曾看见灰色外星人 ” ==> 分词后为 “ 美国(4) 51区(5) 雇员(3) 称(1) 内部(2) 有(1) 9架(3) 飞碟(5) 曾(1) 看见(3) 灰色(4) 外星人(5)”,括号里是代表单词在整个句子里重要程度,数字越大越重要。

  • 2、hash,通过hash算法把每个词变成hash值,比如“美国”通过hash算法计算为 100101,“51区”通过hash算法计算为 101011。这样我们的字符串就变成了一串串数字,还记得文章开头说过的吗,要把文章变为数字计算才能提高相似度计算性能,现在是降维过程进行时。

  • 3、加权,通过 2步骤的hash生成结果,需要按照单词的权重形成加权数字串,比如“美国”的hash值为“100101”,通过加权计算为“4 -4 -4 4 -4 4”;“51区”的hash值为“101011”,通过加权计算为 “ 5 -5 5 -5 5 5”。

  • 4、合并,把上面各个单词算出来的序列值累加,变成只有一个序列串。比如 “美国”的 “4 -4 -4 4 -4 4”,“51区”的 “ 5 -5 5 -5 5 5”, 把每一位进行累加, “4+5 -4+-5 -4+5 4+-5 -4+5 4+5” ==》 “9 -9 1 -1 1 9”。这里作为示例只算了两个单词的,真实计算需要把所有单词的序列串累加。

  • 5、降维,把4步算出来的 “9 -9 1 -1 1 9” 变成 0 1 串,形成我们最终的simhash签名。 如果每一位大于0 记为 1,小于0 记为 0。最后算出结果为:“1 0 1 0 1 1”。

整个过程图为:

simhash计算过程图

大家可能会有疑问,经过这么多步骤搞这么麻烦,不就是为了得到个 0 1 字符串吗?我直接把这个文本作为字符串输入,用hash函数生成 0 1 值更简单。其实不是这样的,传统hash函数解决的是生成唯一值,比如 md5、hashmap等。md5是用于生成唯一签名串,只要稍微多加一个字符md5的两个数字看起来相差甚远;hashmap也是用于键值对查找,便于快速插入和查找的数据结构。不过我们主要解决的是文本相似度计算,要比较的是两个文章是否相识,当然我们降维生成了hashcode也是用于这个目的。看到这里估计大家就明白了,我们使用的simhash就算把文章中的字符串变成 01 串也还是可以用于计算相似度的,而传统的hashcode却不行。我们可以来做个测试,两个相差只有一个字符的文本串,“你妈妈喊你回家吃饭哦,回家罗回家罗” 和 “你妈妈叫你回家吃饭啦,回家罗回家罗”。

通过simhash计算结果为:

1000010010101101111111100000101011010001001111100001001011001011

1000010010101101011111100000101011010001001111100001101010001011

通过 hashcode计算为:

1111111111111111111111111111111110001000001100110100111011011110

1010010001111111110010110011101

大家可以看得出来,相似的文本只有部分 01 串变化了,而普通的hashcode却不能做到,这个就是局部敏感哈希的魅力。目前Broder提出的shingling算法和Charikar的simhash算法应该算是业界公认比较好的算法。在simhash的发明人Charikar的论文中并没有给出具体的simhash算法和证明,“量子图灵”得出的证明simhash是由随机超平面hash算法演变而来的

现在通过这样的转换,我们把库里的文本都转换为simhash 代码,并转换为long类型存储,空间大大减少。现在我们虽然解决了空间,但是如何计算两个simhash的相似度呢?难道是比较两个simhash的01有多少个不同吗?对的,其实也就是这样,我们通过海明距离(Hamming distance)就可以计算出两个simhash到底相似不相似。两个simhash对应二进制(01串)取值不同的数量称为这两个simhash的海明距离。举例如下: 10101 和 00110 从第一位开始依次有第一位、第四、第五位不同,则海明距离为3。对于二进制字符串的a和b,海明距离为等于在a XOR b运算结果中1的个数(普遍算法)。

为了高效比较,我们预先加载了库里存在文本并转换为simhash code 存储在内存空间。来一条文本先转换为 simhash code,然后和内存里的simhash code 进行比较,测试100w次计算在100ms。速度大大提升。

未完待续:

1、目前速度提升了但是数据是不断增量的,如果未来数据发展到一个小时100w,按现在一次100ms,一个线程处理一秒钟 10次,一分钟 60 * 10 次,一个小时 60*10 *60 次 = 36000次,一天 60*10*60*24 = 864000次。 我们目标是一天100w次,通过增加两个线程就可以完成。但是如果要一个小时100w次呢?则需要增加30个线程和相应的硬件资源保证速度能够达到,这样成本也上去了。能否有更好的办法,提高我们比较的效率?

2、通过大量测试,simhash用于比较大文本,比如500字以上效果都还蛮好,距离小于3的基本都是相似,误判率也比较低。但是如果我们处理的是微博信息,最多也就140个字,使用simhash的效果并不那么理想。看如下图,在距离为3时是一个比较折中的点,在距离为10时效果已经很差了,不过我们测试短文本很多看起来相似的距离确实为10。如果使用距离为3,短文本大量重复信息不会被过滤,如果使用距离为10,长文本的错误率也非常高,如何解决?

simhash_hammingdistance

参考:
Detecting near-duplicates for web crawling.

Similarity estimation techniques from rounding algorithms.

http://en.wikipedia.org/wiki/Locality_sensitive_hashing

http://en.wikipedia.org/wiki/Hamming_distance

simHash 简介以及 java 实现

simhash原理推导

原创文章,转载请注明: 转载自LANCEYAN.COM

本文链接地址: 海量数据相似度计算之simhash和海明距离

4
4
分享到:
评论
5 楼 lanceyan 2013-08-27  
sawadari_k 写道
楼主,可以把你的文章分享到我的微博上吗?

可以,大家共同探讨
4 楼 sawadari_k 2013-08-26  
楼主,可以把你的文章分享到我的微博上吗?
3 楼 bitray 2013-08-26  
长见识.是个做数据抽取的好办法
2 楼 steafler 2013-08-26  
值得探讨,楼主加油
1 楼 pangpang514 2013-08-26  
  长见识!

相关推荐

    中文文本相似度匹配算法 simHash 海明距离 IK分词

    中文文本相似度匹配算法 simHash 海明距离 IK分词 完整的可运行的示例代码 包含simHash 算法,使用IK 对中文文本进行分词处理

    论文计算相似度——基于SimHash算法和海明距离

    命令行输入两个txt文件的绝对路径,计算相似度,写进txt文件

    海量数据相似度计算

    针对海量的文本资源,可以有效的进行快速计算。满足动态计算需求

    SimHash-java实现及海明距离

    计算两个文本的相似度,使用到了Simhash、分词、海明距离等技术

    simhash文本相似度

    文本相似度判断 simhash 海明距离判断为相似

    中文文本相似度匹配算法

    中文文本相似度匹配算法 simHash 海明距离 IK分词 完整的可运行的示例代码 包含simHash 算法,使用IK 对中文文本进行分词处理

    基于海明距离法的煤岩冲击倾向性评价

    该模型选用动态破坏时间、冲击能量指数、弹性能量指数和煤岩单轴抗压强度作为综合评价指标,应用线性内插公式构造评价对象的隶属函数,采用海明距离法获得评价对象与评价标准的相似程度,并用最小海明距离进行类别评判,...

    余弦相似度算法文本相似度算法的对比及python实现

    余弦相似度算法文本相似度算法的对比及python实现五种常见的相似度算法:余弦相似度(cosine_similarity)、jaccard相似度、编辑距离(Levenshtein)、MinHash、SimHash + 海明距离。

    simhash算法库simhash.zip

    此项目用来对中文文档计算出对应的 simhash 值。 simhash 是谷歌用来进行文本去重的算法,现在广泛应用在文本处理中。 详见SimhashBlog 特性 使用 CppJieba 作为分词器和关键词抽取器 使用 jenkins 作为 hash...

    MySimHash.java

    使用simhash进行文本查重,计算海明距离,海明距离越小说明越相似,例子: 文本一:使用simhash进行文本查重,计算海明距离,海明距离越小说明越相似 文本二:一个查重算法,计算海明距离,海明距离越小说明越相似 ...

    simhash算法

    用flask写了一个简单的web程序,前端页面有两个输入框,输入两段文字后,点击提交按钮,服务端收到两段文字后,调用simhash算法来计算两段文字的海明距离,注意,simhash计算短文本时效果不好

    海明码算法实现(c语言)

    海明码算法实现包括数据结构设计,算法效率比较高!功能实现:可以查出出错位,并且可以改正!

    海明码计算解析案例

    海明码计算解析案例 海明码计算解析案例 海明码计算解析案例 海明码计算解析案例

    华中科技大学-计算机组成原理-educoder Logisim-计算机数据表示实验(HUST) 答案代码

    华中科技大学-计算机组成原理-educoder Logisim-计算机数据表示实验(HUST) 第1关:汉字国标码转区位码实验 第2关:汉字机内码获取实验 第3关:偶校验编码设计 第4关:偶校验解码电路设计 第5关:16位海明编码电路...

    计算机数据表示实验(HUST) 头歌 通关全码

    通过设计 16 位数据的海明编解码电路,16 位数据的 CRC 并行编解码电路,帮助同学们理解校验码传输过程。通过校验码流水传输实验帮助大家提前建立流水线的基本概念。 第1关汉字国标码转区位码实验 第2关汉字机内码...

    计算机课程设计-海明码的实现

    因此,当传送端与接收端的比特样式的汉明距离 (Hamming distance) 小于或等于1时(仅有 1 bit 发生错误),可实现可靠的通信。相对的,简单的奇偶检验码除了不能纠正错误之外,也只能侦测出奇数个的错误。

    论文研究-一种快速而准确的虹膜识别方法.pdf

    提出了一种快速而准确的虹膜识别算法,基本思想是:通过图像预处理,确定虹膜的位置和大小,并将直角坐标系下的环形虹膜展开成极坐标系下的矩形虹膜;...计算两个虹膜编码之间的海明距离,根据海明距离给出识别结果。

    基于CRC编码译码和海明编码译码+GUI操作界面的Matlab仿真源码+数据(课程设计).zip

    基于CRC编码译码和海明编码译码+GUI操作界面的Matlab仿真源码+数据(课程设计).zip 已获导师指导并通过的97分的高分课程设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。...

    海明码详解(如何计算海明码)

    显然,其中一个值表示数据是正确的,而剩下的2^k –1个值意味着数据中存在错误,如果能够满足: 2^k–1&gt;=m + k (m + k为编码后的总长度),在理论上k个校验码就可以判断是哪一位(包括信息码和校验码)出现问题。

    数据表示实验 logisim 华中科大 circ

    观看慕课第三章数据表示实验的 1、汉字编码实验(用 HXD.EXE 将 ROM 内容换成自我简介,姓名,籍贯,年 龄) 2、奇偶检验码应用实验 3、海明码编码设计实验(22,16) 5、编码流水传输实验 完成国标转区位码、汉字显示...

Global site tag (gtag.js) - Google Analytics