转simhash与重复信息识别

simhash与重复信息识别html

在工做学习中,我每每感叹数学奇迹般的解决一些貌似不可能完成的任务,而且十分但愿将这种喜悦分享给你们,就比如说:“老婆,出来看上帝”…… 随着信息爆炸时代的来临,互联网上充斥着着大量的近重复信息,有效地识别它们是一个颇有意义的课题。例如,对于搜索引擎的爬虫系统来讲,收录重复的网页是毫无心义的,只会形成存储和计算资源的浪费;同时,展现重复的信息对于用户来讲也并非最好的体验。形成网页近重复的可能缘由主要包括:
  • 镜像网站
  • 内容复制
  • 嵌入广告
  • 计数改变
  • 少许修改
一个简化的爬虫系统架构以下图所示:
事实上,传统比较两个文本类似性的方法,大可能是将文本分词以后,转化为特征向量距离的度量,好比常见的欧氏距离、海明距离或者余弦角度等等。两两比较当然能很好地适应,但这种方法的一个最大的缺点就是,没法将其扩展到海量数据。例如,试想像Google那种收录了数以几十亿互联网信息的大型搜索引擎,天天都会经过爬虫的方式为本身的索引库新增的数百万网页,若是待收录每一条数据都去和网页库里面的每条记录算一下余弦角度,其计算量是至关恐怖的。 咱们考虑采用为每个web文档经过hash的方式生成一个指纹(fingerprint)。传统的加密式hash,好比md5,其设计的目的是为了让整个分布尽量地均匀,输入内容哪怕只有轻微变化,hash就会发生很大地变化。咱们理想当中的哈希函数,须要对几乎相同的输入内容,产生相同或者相近的hashcode,换句话说,hashcode的类似程度要能直接反映输入内容的类似程度。很明显,前面所说的md5等传统hash没法知足咱们的需求。 simhash是locality sensitive hash(局部敏感哈希)的一种,最先由Moses Charikar在《similarity  estimation techniques from rounding  algorithms》一文中提出。Google就是基于此算法实现网页文件查重的。咱们假设有如下三段文本:
  • the cat sat on the mat
  • the cat sat on a mat
  • we all scream for ice cream
使用传统hash可能会产生以下的结果:
引用
irb(main):006:0> p1 = 'the cat sat on the mat' irb(main):005:0> p2 = 'the cat sat on a mat'  irb(main):007:0> p3 =  'we all scream for ice cream'  irb(main):007:0> p1.hash  =>  415542861  irb(main):007:0> p2.hash  => 668720516 irb(main):007:0> p3.hash  =>  767429688
使用simhash会应该产生相似以下的结果:
引用
irb(main):003:0> p1.simhash  => 851459198 00110010110000000011110001111110 irb(main):004:0> p2.simhash => 847263864  00110010100000000011100001111000 irb(main):002:0> p3.simhash  => 984968088 00111010101101010110101110011000
海明距离的定义,为两个二进制串中不一样位的数量。上述三个文本的simhash结果,其两两之间的海明距离为(p1,p2)=4,(p1,p3)=16以及(p2,p3)=12。事实上,这正好符合文本之间的类似度,p1和p2间的类似度要远大于与p3的。 如何实现这种hash算法呢?以上述三个文本为例,整个过程能够分为如下六步: 一、选择simhash的位数,请综合考虑存储成本以及数据集的大小,好比说32位  二、将simhash的各位初始化为0 三、提取原始文本中的特征,通常采用各类分词的方式。好比对于"the cat sat on the mat",采用两两分词的方式获得以下结果:{"th",  "he", "e ", " c", "ca", "at", "t ", " s", "sa", " o", "on", "n ", " t", " m",  "ma"}  四、使用传统的32位hash函数计算各个word的hashcode,好比:"th".hash = -502157718 ,"he".hash = -369049682,…… 五、对各word的hashcode的每一位,若是该位为1,则simhash相应位的值加1;不然减1 六、对最后获得的32位的simhash,若是该位大于1,则设为1;不然设为0 整个过程能够参考下图: 按照Charikar在论文中阐述的,64位simhash,海明距离在3之内的文本均可以认为是近重复文本。固然,具体数值须要结合具体业务以及经验值来肯定。   使用上述方法产生的simhash能够用来比较两个文本之间的类似度。问题是,如何将其扩展到海量数据的近重复检测中去呢?譬如说对于64位的待查询文本的simhash  code来讲,如何在海量的样本库(>1M)中查询与其海明距离在3之内的记录呢?下面在引入simhash的索引结构以前,先提供两种常规的思路。第一种是方案是查找待查询文本的64位simhash  code的全部3位之内变化的组合,大约须要四万屡次的查询,参考下图: 另外一种方案是预生成库中全部样本simhash  code的3位变化之内的组合,大约须要占据4万多倍的原始空间,参考下图: 显然,上述两种方法,或者时间复杂度,或者空间复杂度,其一没法知足实际的需求。咱们须要一种方法,其时间复杂度优于前者,空间复杂度优于后者。 假设咱们要寻找海明距离3之内的数值,根据抽屉原理,只要咱们将整个64位的二进制串划分为4块,不管如何,匹配的两个simhash  code之间至少有一块区域是彻底相同的,以下图所示: 因为咱们没法事先得知彻底相同的是哪一块区域,所以咱们必须采用存储多份table的方式。在本例的状况下,咱们须要存储4份table,并将64位的simhash  code等分红4份;对于每个输入的code,咱们经过精确匹配的方式,查找前16位相同的记录做为候选记录,以下图所示: 让咱们来总结一下上述算法的实质:  一、将64位的二进制串等分红四块 二、调整上述64位二进制,将任意一块做为前16位,总共有四种组合,生成四份table  三、采用精确匹配的方式查找前16位 四、若是样本库中存有2^34(差很少10亿)的哈希指纹,则每一个table返回2^(34-16)=262144个候选结果,大大减小了海明距离的计算成本 咱们能够将这种方法拓展成多种配置,不过,请记住,table的数量与每一个table返回的结果呈此消彼长的关系,也就是说,时间效率与空间效率不可兼得,参看下图: 事实上,这就是Google天天所作的,用来识别获取的网页是否与它庞大的、数以十亿计的网页库是否重复。另外,simhash还能够用于信息聚类、文件压缩等。 也许,读到这里,你已经感觉到数学的魅力了。
相关文章
相关标签/搜索