我所理解的simhash

摘要:

   最近在看关于搜索引擎方面的书籍,常见的去重算法有余弦夹角算法、欧式距离、Jaccard相似度、最长公共子串、编辑距离 今天我所记录的是关于网页去重的另一个一个算法----simhash,刚好工作有需要就试着用上了。

首先需要了解的知识有:

   1、位运算值适合整数,如果浮点数想要进行位运算就先Float.floatToIntBits 进行运算,然后再 Float.intBitsToFloat转换回去,java中默认的float、double的hashcode就是对应的floatToIntBits的int hash值

   2、对字符串进行分词,有的是用StringTokenizer进行分词(不再建议),也用到split结合正则表达式进行(推荐);如果要处理的文档是中文,仅需要先进行中文分词,需要用到的org.apache.lucene  、 IkAnalyzer 等jar包。

   3、BigInteger大数据类型


simhash算法:局部敏感hash算法

   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_第1张图片

simHash值的海明距离计算:XOR

   对两个文档simhash值进行海明距离求值,小于3,则可认为两者相似。


计算二进制序列中1的个数:

bool isEqual(uint64_t lhs, uint64_t rhs, unsigned short n = 3)
{
    unsigned short cnt = 0;
    lhs ^= rhs;
    while(lhs && cnt <= n)
    {
        lhs &= lhs - 1;
        cnt++;
    }
    if(cnt <= n)
    {
        return true;
    }
    return false;
}

问题:

一、 新增数据的simhash和不断海量数据simhash计算海明距离的时间

··在一定范围内查找数据库中的simhash,如一个月内的数据等

··simhash分组,利用号称查找速度最快的额数据结构hashmap,通过键值对的方式减少顺序比较的次数

存储:

1、将一个64位的simhash code拆分成4个16位的二进制码。(图上红色的16位)

2、分别拿着4个16位二进制码查找当前对应位置上是否有元素。(放大后的16位)
3、对应位置没有元素,直接追加到链表上;对应位置有则直接追加到链表尾端。(图上的 S1 — SN)

查找:

1、将需要比较的simhash code拆分成4个16位的二进制码。

2、分别拿着4个16位二进制码每一个去查找simhash集合对应位置上是否有元素。

3、如果有元素,则把链表拿出来顺序查找比较,直到simhash小于一定大小的值,整个过程完成。

原理:

   借鉴hashmap算法找出可以hash的key值,因为我们使用的simhash是局部敏感哈希,这个算法的特点是只要相似的字符串只有个别的位数是有差别变化。那这样我们可以推断两个相似的文本,至少有16位的simhash是一样的。具体选择16位、8位、4位,大家根据自己的数据测试选择,虽然比较的位数越小越精准,但是空间会变大。分为4个16位段的存储空间是单独simhash存储空间的4倍


二、 当文本内容较长时,使用SimHash准确率很高,SimHash处理短文本内容准确率往往不能得到保证;

三、 文本内容中每个term对应的权重如何确定要根据实际的项目需求,一般是可以使用IDF权重来进行计算,或者个人认为IK分词中可以将一些组词、虚词等列入StopWord.dic中;

附录:
参考:http://www.cnblogs.com/hxsyl/p/4518506.html
http://www.lanceyan.com/tech/arch/simhash_hamming_distance_similarity2-html.html





你可能感兴趣的:(java)