这个月一直在做文本匹配研究,大到一篇文章,现在小到一个字段。处于自由散漫的探索,而且时间较短,所以可能较为肤浅,感兴趣的可以一起交流。 1.查找一篇重复文本。前一段时间做过测试,Google的SimHash算法效果还是不错的,文本长度与一篇论文长度差不多。
步骤为: a. 给整篇文档分词 term ,分词用的是IKAnalyzer。
b.计算每个分词term的MD5 哈希值。由于比较的文本长度不大,所以采用的是32位哈希。原本的MD5是直 接生成32位哈希的,16位的就是截取中间32位。代码如下:
public String Md5(String plainText ) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(plainText.getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if(i<0) i+= 256;
if(i<16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
System.out.println("result(32位): " + buf.toString());//32位的加密
System.out.println("result(16位): " + buf.toString().substring(8,24));//16位的加密
return buf.toString().substring(8,24);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
c. SimHash计算的是全部MD5哈希的最后哈希值。算法思路是:
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作为签名
用一篇文档测试,Google SimHash用汉明距离度量。通常是汉明距离小于5即可认为两篇文档重复。我取为10的时候发现出现多篇文档,但是内容上却相差很大。具体的细节就不写了。
2.段落比较采用的是计算段落每个分词term的tfidf值,然后匹配。为了提高效率,我假设匹配之前已经清楚该文档所属分类。
用tfidf可以确定的找到测试文档的出处。十分准确。不像SimHash会出现不相干的文档。