一种海量文章排重的算法

       传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上相当于伪随机数产生算法。产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别极大。从这个意义 上来 说,要设计一个 hash 算法,对相似的内容产生的签名也相近,是更为艰难的任务,因为它的签名值除了提供原始内容是否相等的信息外,还能额外提供不相等的 原始内容的差异程度的信息。
而 Google 的 simhash 算法产生的签名,可以满足上述要求。出人意料,这个算法并不深奥,其思想是非常清澈美妙的。

算法简介

       simhash算法的输入是一个向量,输出是一个 f 位的签名值。为了陈述方便,假设输入的是一个文档的特征集合,每个特征有一定的权重。比如特征可以是文档中的词,其权重可以是这个词出现的次数。 simhash 算法如下:  
1,将一个 f 维的向量 V 初始化为 0 ; f 位的二进制数 S 初始化为 0 ;  
2,对每一个特征:用传统的 hash 算法对该特征产生一个 f 位的签名 b 。对 i=1 到 f :  
如果b 的第 i 位为 1 ,则 V 的第 i 个元素加上该特征的权重;  
否则,V 的第 i 个元素减去该特征的权重。   
3,如果 V 的第 i 个元素大于 0 ,则 S 的第 i 位为 1 ,否则为 0 ;  
4,输出 S 作为签名。

算法几何意义

        这个算法的几何意义非常明了。它首先将每一个特征映射为f维空间的一个向量,这个映射规则具体是怎样并不重要,只要对很多不同的特征来说,它们对所对应的向量是均匀随机分布的,并且对相同的特征来说对应的向量是唯一的就行。比如一个特征的4位hash签名的二进制表示为1010,那么这个特征对应的 4维向量就是(1, -1, 1, -1)T,即hash签名的某一位为1,映射到的向量的对应位就为1,否则为-1。然后,将一个文档中所包含的各个特征对应的向量加权求和,加权的系数等于该特征的权重。得到的和向量即表征了这个文档,我们可以用向量之间的夹角来衡量对应文档之间的相似度。最后,为了得到一个f位的签名,需要进一步将其压缩,如果和向量的某一维大于0,则最终签名的对应位为1,否则为0。这样的压缩相当于只留下了和向量所在的象限这个信息,而64位的签名可以表示多达264个象限,因此只保存所在象限的信息也足够表征一个文档了。

相似度比较

海明距离: 两个码字的对应比特取值不同的比特数称为这两个码字的海明距离。一个有效编码集中, 任意两个码字的海明距离的最小值称为该编码集的海明距离。举例如下: 10101 和 00110 从第一位开始依次有第一位、第四、第五位不同,则海明距离为 3.  

异或: 只有在两个比较的位不同时其结果是1 ,否则结果为 0 

对每篇文档根据SimHash 算出签名后,再计算两个签名的海明距离(两个二进制异或后 1 的个数)即可。根据经验值,对 64 位的 SimHash ,海明距离在 3 以内的可以认为相似度比较高。  
假设对64 位的 SimHash ,我们要找海明距离在 3 以内的所有签名。我们可以把 64 位的二进制签名均分成 4块,每块 16 位。根据鸽巢原理(也成抽屉原理,见组合数学),如果两个签名的海明距离在 3 以内,它们必有一块完全相同。  
我们把上面分成的4 块中的每一个块分别作为前 16 位来进行查找。 建立倒排索引。

simhash-py

要更准确的对文章进行排重,需要找到好的simhash算法。目前我知道的有python-hashes,simhash-py。两个库通过简单的修改,再加上中文分词库,可以比较好的对中文文章计算hash。simhash-py可使用我fork的版本以支持中文文章的simhash (通过里面的hash_token或hash_tokenpy两个函数实现对切词之后的中文文章进行simhash计算)。

simhash算法

simhash算法最简单实现的库应该是python-hashes库了。使用过程当中发现,对于排重的使用目的来说,这个库的simhash算法有缺点是:只考虑到文章存在哪些词,没有考虑到词的顺序。不过相应的优点是,可以实现海量文章相似度计算。文章相似度计算忽略词的顺序之后效果更好。

simhash-py内部实现了simhash算法。它里面的simhash使用了cyclic hash算法,这个算法考虑到N(可以在3~5)个词之间的顺序。考虑到词的顺序的hash算法在排重过程当中会更准确,不过这个我也没有特别好的测试:)

simhash加快搜索

若看过本文推荐的simhash的原理讲解那篇文章,发现可以通过“shard”方式加快simhash值的搜索,从而能快速的知道是否存在重复的文章。而simhash-py库通过C++的Judy库实现了这一点。

simhash集群处理

既然可以通过“shard”方式,那么很容易把这个思路拓展到集群上。所以相应的,simhashpy的作者实现了simhash-cluster。

总结:

     simhash算法可以进行海量文档的排重,同时也可用于文档检索

猜你喜欢

转载自blog.csdn.net/junjie20082008/article/details/53390854