Chinaunix首页 | 论坛 | 博客
  • 博客访问: 101120
  • 博文数量: 20
  • 博客积分: 648
  • 博客等级: 上士
  • 技术积分: 222
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-02 11:43
文章分类

全部博文(20)

文章存档

2013年(3)

2012年(8)

2011年(7)

2010年(2)

我的朋友

分类: 大数据

2013-09-07 18:12:37

在工作学习中,我往往感叹数学奇迹般的解决一些貌似不可能完成的任务,并且十分希望将这种喜悦分享给大家,就好比说:“老婆,出来看上帝”…… 

随着信息爆炸时代的来临,互联网上充斥着着大量的近重复信息,有效地识别它们是一个很有意义的课题。例如,对于搜索引擎的爬虫系统来说,收录重复的网页是毫无意义的,只会造成存储和计算资源的浪费;同时,展示重复的信息对于用户来说也并不是最好的体验。造成网页近重复的可能原因主要包括: 
  • 镜像网站
  • 内容复制
  • 嵌入广告
  • 计数改变
  • 少量修改


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




事实上,传统比较两个文本相似性的方法,大多是将文本分词之后,转化为特征向量距离的度量,比如常见的欧氏距离、海明距离或者余弦角度等等。两两比较固然能很好地适应,但这种方法的一个最大的缺点就是,无法将其扩展到海量数据。例如,试想像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还可以用于信息聚类、文件压缩等。 

也许,读到这里,你已经感受到数学的魅力了。


自:http://grunt1223.iteye.com/blog/964564
附simhash为什么能够表示相似的解释: 自:http://www.cnblogs.com/linecong/archive/2010/08/28/simhash.html

Simhash是由随机超平面hash算法演变而来的,随机超平面hash算法非常简单,对于一个n维向量v,要得到一个f位的签名(f<

?
1
2
1,随机产生f个n维的向量r1,…rf;
2,对每一个向量ri,如果v与ri的点积大于0,则最终签名的第i位为1,否则为0.

这个算法相当于随机产生了f个n维超平面,每个超平面将向量v所在的空间一分为二,v在这个超平面上方则得到一个1,否则得到一个0,然后将得到的f个0或1组合起来成为一个f维的签名。如果两个向量u, v的夹角为θ,则一个随机超平面将它们分开的概率为θ/π,因此u, v的签名的对应位不同的概率等于θ/π。所以,我们可以用两个向量的签名的不同的对应位的数量,即汉明距离,来衡量这两个向量的差异程度。

Simhash算法与随机超平面hash是怎么联系起来的呢?在simhash算法中,并没有直接产生用于分割空间的随机向量,而是间接产生的:第k个特征的hash签名的第i位拿出来,如果为0,则改为-1,如果为1则不变,作为第i个随机向量的第k维。由于hash签名是f位的,因此这样能产生f个随机向量,对应f个随机超平面。下面举个例子:

假设用5个特征w1,…,w5来表示所有文档,现要得到任意文档的一个3维签名。假设这5个特征对应的3维向量分别为:

h(w1) = (1, -1, 1)T

h(w2) = (-1, 1, 1)T

h(w3) = (1, -1, -1)T

h(w4) = (-1, -1, 1)T

h(w5) = (1, 1, -1)T

按simhash算法,要得到一个文档向量d=(w1=1, w2=2, w3=0, w4=3, w5=0) T的签名,

先要计算向量m = 1*h(w1) + 2*h(w2) + 0*h(w3) + 3*h(w4) + 0*h(w5) = (-4, -2, 6) T

然后根据simhash算法的步骤3,得到最终的签名s=001。

上面的计算步骤其实相当于,先得到3个5维的向量,第1个向量由h(w1),…,h(w5)的第1维组成:

r1=(1,-1,1,-1,1) T

第2个5维向量由h(w1),…,h(w5)的第2维组成:

r2=(-1,1,-1,-1,1) T

同理,第3个5维向量为:

r3=(1,1,-1,1,-1) T.

按随机超平面算法的步骤2,分别求向量d与r1,r2,r3的点积:

d T r1=-4 < 0,所以s1=0;

d T r2=-2 < 0,所以s2=0;

d T r3=6 > 0,所以s3=1.

故最终的签名s=001,与simhash算法产生的结果是一致的。

从上面的计算过程可以看出,simhash算法其实与随机超平面hash算法是相同的,simhash算法得到的两个签名的汉明距离,可以用来衡量原始向量的夹角。这其实是一种降维技术,将高维的向量用较低维度的签名来表征。衡量两个内容相似度,需要计算汉明距离,这对给定签名查找相似内容的应用来说带来了一些计算上的困难;我想,是否存在更为理想的simhash算法,原始内容的差异度,可以直接由签名值的代数差来表示呢?



阅读(2166) | 评论(0) | 转发(0) |
0

上一篇:hive udaf开发入门和运行过程详解

下一篇:没有了

给主人留下些什么吧!~~