在工作学习中,我往往感叹数学奇迹般的解决一些貌似不可能完成的任务,并且十分希望将这种喜悦分享给大家,就好比说:“老婆,出来看上帝”……
随着信息爆炸时代的来临,互联网上充斥着着大量的近重复信息,有效地识别它们是一个很有意义的课题。例如,对于搜索引擎的爬虫系统来说,收录重复的网页是毫无意义的,只会造成存储和计算资源的浪费;同时,展示重复的信息对于用户来说也并不是最好的体验。造成网页近重复的可能原因主要包括:

  • 镜像网站
  • 内容复制
  • 嵌入广告
  • 计数改变
  • 少量修改

一个简化的爬虫系统架构如下图所示:

事实上,传统比较两个文本相似性的方法,大多是将文本分词之后,转化为特征向量距离的度量,比如常见的欧氏距离、海明距离或者余弦角度等等。两两比较固然能很好地适应,但这种方法的一个最大的缺点就是,无法将其扩展到海量数据。例如,试想像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算法呢?以上述三个文本为例,整个过程可以分为以下六步:
1、选择simhash的位数,请综合考虑存储成本以及数据集的大小,比如说32位 2、将simhash的各位初始化为0
3、提取原始文本中的特征,一般采用各种分词的方式。比如对于"the cat sat on the mat",采用两两分词的方式得到如下结果:{"th", "he", "e ", " c", "ca", "at", "t ", " s", "sa", " o", "on", "n ", " t", " m", "ma"} 4、使用传统的32位hash函数计算各个word的hashcode,比如:"th".hash = -502157718
,"he".hash = -369049682,……
5、对各word的hashcode的每一位,如果该位为1,则simhash相应位的值加1;否则减1
6、对最后得到的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位相同的记录作为候选记录,如下图所示:

让我们来总结一下上述算法的实质: 1、将64位的二进制串等分成四块
2、调整上述64位二进制,将任意一块作为前16位,总共有四种组合,生成四份table 3、采用精确匹配的方式查找前16位
4、如果样本库中存有2^34(差不多10亿)的哈希指纹,则每个table返回2^(34-16)=262144个候选结果,大大减少了海明距离的计算成本
我们可以将这种方法拓展成多种配置,不过,请记住,table的数量与每个table返回的结果呈此消彼长的关系,也就是说,时间效率与空间效率不可兼得,参看下图:

事实上,这就是Google每天所做的,用来识别获取的网页是否与它庞大的、数以十亿计的网页库是否重复。另外,simhash还可以用于信息聚类、文件压缩等。
也许,读到这里,你已经感受到数学的魅力了。

simhash与重复信息识别的更多相关文章

  1. 转simhash与重复信息识别

    simhash与重复信息识别 在工作学习中,我往往感叹数学奇迹般的解决一些貌似不可能完成的任务,并且十分希望将这种喜悦分享给大家,就好比说:“老婆,出来看上帝”…… 随着信息爆炸时代的来临,互联网上充 ...

  2. TListView列表拒绝添加重复信息

      //TListView列表拒绝添加重复信息 procedure TForm1.Button1Click(Sender: TObject);var  i: Integer;begin  if (Tr ...

  3. extract_by_one 根据二维数组中某字段来提取数组信息,查看有无重复信息

    public function tt(){ $param = array( array ( 'hykno' => '2222222-CB', 'tcdk_fid' => '458B6D70 ...

  4. sql server去除重复信息,

    SELECT st_id FROM ( SELECT *,ROW_NUMBER() OVER( PARTITION BY st_code ORDER BY st_code ) AS num FROM ...

  5. sql2008百万级数据排除重复信息

    --高性能排除重复select userid from table where userid in ( select userid from ( select userid, row_number() ...

  6. 删除重复信息且要保留一条的(roacle的rowid另类用法)

    由于表的主键失效了(disable),导致导入了一些主键重复的数据,想保留唯一的一条, 最后发现其实可以用rowid来实现,不知道算不算是rowid的另类用法. delete /*+ parallel ...

  7. Treeview1列表拒绝添加重复信息

    function ItemExist(Text:string;TreeView:TTreeView):Boolean; var   i: Integer; begin   Result:=False; ...

  8. 海量数据相似度计算之simhash短文本查找

    在前一篇文章 <海量数据相似度计算之simhash和海明距离> 介绍了simhash的原理,大家应该感觉到了算法的魅力.但是随着业务的增长 simhash的数据也会暴增,如果一天100w, ...

  9. simHash 简介以及 java 实现

    传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上相当于伪随机数产生算法.产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的:如果不相等,除了说明原始内容不相等外 ...

随机推荐

  1. Android Dalvik虚拟机

    虽然Android平台使用Java来开发应用程序,但Android程序却不是运行在标准Java虚拟机上的. 可能是出于效率和版权的考虑,Google为Android专门设计了一套虚拟机Dalvik V ...

  2. HihoCoder1470 : 公平的游戏

    描述 有一些人在玩一个游戏.游戏的舞台发生在一个 n 个点的树上. 这个游戏分为很多轮,每一轮都有一些玩家参与,每个玩家都会降落在一条给定的边上(不同玩家的边不同).之后这 n 个点上都会随机出现一个 ...

  3. No java virtual machine ....

    运行Eclipse提示No java virtual machine   版权声明:本文原创作者:一叶飘舟 作者博客地址:http://blog.csdn.net/jdsjlzx http://blo ...

  4. zookeeper分布式安装

    1.先把zookeeper-3.5.2-alpha.tar上传解压到/usr/local/下重命名为zookeeper ############# zookeeper env ############ ...

  5. Qt5.7不能加载MySql驱动问题.(需要重新编译驱动)

    转自:http://blog.csdn.net/qq_28851503/article/details/52422302 首先贴上我遇到的问题,如下: QSqlDatabase: QMYSQL dri ...

  6. spark学习之IDEA配置spark并wordcount提交集群

    这篇文章包括以下内容 (1)IDEA中scala的安装 (2)hdfs简单的使用,没有写它的部署 (3) 使用scala编写简单的wordcount,输入文件和输出文件使用参数传递 (4)IDEA打包 ...

  7. maven:mirrors和repository的关系区别

    原文地址:http://my.oschina.NET/sunchp/blog/100634 1 Repository(仓库) 1.1 Maven仓库主要有2种: remote repository:相 ...

  8. UVa 10214 Trees in a Wood. (数论-欧拉函数)

    题意:给定一个abs(x) <= a, abs(y) <= b,除了原点之外的整点各有一棵树,可以相互阻挡,求从原点可以看到多少棵树. 析:由于a < b,所以我们可以一列一列的统计 ...

  9. E20180715-hm

    grapefruit n. 葡萄柚,西柚; 葡萄柚树;

  10. Android布局中的layout_weight和weightSum属性的详解及使用

    由于Android设备的尺寸大小不一,种类繁多,当我们在开发应用的时候就要考虑屏幕的适配型了,尽可能让我们的应用适用于主流机型的尺寸,这样我们的应用不会因为尺寸不同而不美观,解决屏幕适配问题的方法有很 ...