simhash应用-文章去重

来源:互联网 发布:数据可视化实战 pdf 编辑:程序博客网 时间:2024/05/16 06:40

在抓取新闻时,经常碰见的一个问题是会遇到重复新闻,针对重复新闻如果人工来判断工作量可想而知,好在,google提出了simhash,我们可以用simhash来判断两篇文章是否相似。simhash的原理请看这里:http://www.cnblogs.com/linecong/archive/2010/08/28/simhash.html

1、分词

拿到两篇文章,直接计算hash值显然是不可能的,最简单的想法是对文章进行分词,然后计算每个词的hash值,最后累加。

关于分词,再次强烈推荐ANSJ这个开源分词工具,请看这里:http://blog.csdn.net/zhaoxinfan/article/details/10403917

2、计算simhash值

具体看代码,在计算完simhash值后再判断两篇文章相似度,比较容易想到的是海明距离

import java.math.BigInteger;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import org.ansj.domain.Term;import org.ansj.splitWord.analysis.ToAnalysis;public class NewsSimHash {    private String content;    private BigInteger intSimHash;       private String strSimHash;    private int hashbits = 64;/** *  * @param content      newsContent * @param intSimHash指纹大整型表示 * @param strSimHash指纹字符串表示 * @param hashbits    simhash位数,文档的特征向量维数 */    public NewsSimHash(String content) {        this.content = content;        this.intSimHash = this.simHash();    }    public NewsSimHash(String content, int hashbits) {        this.content = content;        this.hashbits = hashbits;        this.intSimHash = this.simHash();    }        public BigInteger getIntSimHash() {return intSimHash;}public void setIntSimHash(BigInteger intSimHash) {this.intSimHash = intSimHash;}public String getStrSimHash() {return strSimHash;}public void setStrSimHash(String strSimHash) {this.strSimHash = strSimHash;}//收集关键词,计算权重    private List<String> getWord(String content){   List<String> word=new ArrayList<String>();try {  List<Term> parse = ToAnalysis.parse(content);for (Term term : parse) {        String line=term.getNatrue().toString();        String[] outline=new String[5];        outline=line.split(":");        term.getName().replaceAll("[\\pP‘’“”]", "");        if(!("".equals(term.getName())) ){        word.add(term.getName());        }        }} catch (Exception e) {e.printStackTrace();}return word;    }    /**     * 文档指纹生成     * 默认权重为 1     * @return     */    public BigInteger simHash() {        int[] v = new int[this.hashbits];        List<String> wordList = this.getWord(this.content);                Iterator<String> it =wordList.iterator();        String keywords="";        //生成文档的和向量        while(it.hasNext()){        keywords = it.next();        System.out.print(keywords+" ");           BigInteger keywordsHashValue = this.hash(keywords);           for(int i = 0;i< this.hashbits;i++){           BigInteger bitMark =new BigInteger("1").shiftLeft(i);           if(keywordsHashValue.and(bitMark).signum() == 1){           v[i]+= 1;           }else{           v[i]-= 1;           }           }        }          System.out.print("\n");        //文档指纹生成        BigInteger fingerprint = new BigInteger("0");        StringBuffer simHashBuffer = new StringBuffer();        for (int i = 0; i < this.hashbits; i++) {            if (v[i] >= 0) {                fingerprint = fingerprint.add(new BigInteger("1").shiftLeft(i));                simHashBuffer.append("1");            }else{                simHashBuffer.append("0");            }        }        this.strSimHash = simHashBuffer.toString();        return fingerprint;    }    /**     * 生成特征词的的hash值     * @param source     * @return     */    private BigInteger hash(String keywords) {        if (keywords == null || keywords.length() == 0) {            return new BigInteger("0");        } else {            char[] sourceArray = keywords.toCharArray();            BigInteger x = BigInteger.valueOf(((long) sourceArray[0]) << 7);            BigInteger m = new BigInteger("1000003");            BigInteger mask = new BigInteger("2").pow(this.hashbits).subtract(                    new BigInteger("1"));            for (char item : sourceArray) {                BigInteger temp = BigInteger.valueOf((long) item);                x = x.multiply(m).xor(temp).and(mask);            }            x = x.xor(new BigInteger(String.valueOf(keywords.length())));            if (x.equals(new BigInteger("-1"))) {                x = new BigInteger("-2");            }            return x;        }    }        /**     * 指纹压缩     * 取两个二进制的异或,统计为1的个数,就是海明距离,确定两个文本的相似度,<3是近重复文本     * @param other     * @return     */    public int hammingDistance(NewsSimHash otherSimHash) {            BigInteger x = this.intSimHash.xor(otherSimHash.intSimHash);        int tot = 0;//x=0,海明距离为O;                //统计x中二进制位数为1的个数               while (x.signum() != 0) {            tot += 1;            x = x.and(x.subtract(new BigInteger("1")));        }        return tot;    }     public int hammingDistance(BigInteger simHash) {            BigInteger x = this.intSimHash.xor(simHash);        int tot = 0;//x=0,海明距离为O;                //统计x中二进制位数为1的个数               while (x.signum() != 0) {            tot += 1;            x = x.and(x.subtract(new BigInteger("1")));        }        return tot;    }    /**     * 获取索引列表     * 如果海明距离取3,则分成四块,并得到每一块的bigInteger值 ,作为索引值使用     * @param simHash     * @param distance     * @return     */    public List<BigInteger> genSimHashBlock(NewsSimHash simHash, int distance){    int eachBlockBitNum = this.hashbits/(distance+1);    List<BigInteger> simHashBlock = new ArrayList<BigInteger>();            StringBuffer buffer = new StringBuffer();    for( int i = 0; i < this.intSimHash.bitLength(); i++){        boolean sr = simHash.intSimHash.testBit(i);               if(sr){        buffer.append("1");        }        else{        buffer.append("0");//补齐        }                if( (i+1)%eachBlockBitNum == 0 ){//够十六位时            BigInteger eachValue = new BigInteger(buffer.toString(),2);            System.out.println("----" +eachValue );            buffer.delete(0, buffer.length());            simHashBlock.add(eachValue);        }        }    return simHashBlock;    }    //测试    public static void main(String[] args) {        NewsSimHash ns=new NewsSimHash("中新网11月4日电 台当局防务部门负责人严明今天(4日)证实台军采购的最新型阿帕契直升机(AH-64E)已抵高雄港。陆军表示,吊挂顺利,正进行组装、地面测试。"+"严明上午在台当局“立法院”答询时指出,首批6架阿帕契直升机(AH-64E)已抵台。"+"台湾陆军指出,6架直升机以海运方式运抵高雄港,上午吊挂上岸作业顺利,正在进行组装,组装完后,会做地面测试,包括开车、旋翼转动等测试,相关过程军方全程保密。"+"陆军说,测试结束后,阿帕契直升机将在6日或7日飞抵陆军航空特战指挥部台南归仁基地;陆军也预计邀媒体参访,最新型的AH-64E直升机最快6日就能在民众面前亮相。"+"台湾地区向美国购买30架长弓阿帕契攻击直升机(AH-64E)是前美国总统布什(George W. Bush)政府在2008年宣布售台,总金额达新台币593.1亿元;除了美国外,台湾是第2个拥有此机型的地区。");        NewsSimHash ns1=new NewsSimHash("中新网11月4日电 据台湾“中央社”报道,台当局防务部门负责人严明今天(4日)证实台军采购的最新型阿帕契直升机(AH-64E)已抵高雄港。陆军表示,吊挂顺利,正进行组装、地面测试。"+"严明上午在台当局“立法院”答询时指出,首批6架阿帕契直升机(AH-64E)已抵台。"+"台湾陆军指出,6架直升机以海运方式运抵高雄港,上午吊挂上岸作业顺利,正在进行组装,组装完后,会做地面测试,包括开车、旋翼转动等测试,相关过程军方全程保密。"+"陆军说,测试结束后,阿帕契直升机将在6日或7日飞抵陆军航空特战指挥部台南归仁基地;陆军也预计邀媒体参访,最新型的AH-64E直升机最快6日就能在民众面前亮相。"+"台湾地区向美国购买30架长弓阿帕契攻击直升机(AH-64E)是前美国总统布什(George W. Bush)政府在2008年宣布售台,总金额达新台币593.1亿元;");        //simhash的二进制表示        System.out.println("simhash的二进制表示:");        System.out.println(ns.getStrSimHash());        System.out.println(ns1.getStrSimHash());        //simhash的BigInteger表示        System.out.println("simhash的BigInteger表示:");        System.out.println(ns.getIntSimHash());        System.out.println(ns1.getIntSimHash());        //ns1与ns的汉明距离,        System.out.println("ns1与ns的汉明距离");        System.out.println(ns.hammingDistance(ns1));    }}


下面是程序的输出:

中新网 11月 4日 电   台当局 防务 部门 负责人 严明 今天 ( 4日 ) 证实 台军 采购 的 最新型 阿帕契 直升机 ( ah - 64 e ) 已 抵 高雄港 。 陆军 表示 , 吊挂 顺利 , 正 进行 组装 、 地面 测试 。 严明 上午 在 台当局 “ 立法院 ” 答询 时 指出 , 首批 6架 阿帕契 直升机 ( ah - 64 e ) 已 抵 台 。 台湾 陆军 指出 , 6架 直升机 以 海运 方式 运抵 高雄港 , 上午 吊挂 上岸 作业 顺利 , 正在 进行 组装 , 组装 完 后 , 会 做 地面 测试 , 包括 开车 、 旋翼 转动 等 测试 , 相关 过程 军方 全程 保密 。 陆军 说 , 测试 结束 后 , 阿帕契 直升机 将 在 6日 或 7日 飞抵 陆军 航空 特战 指挥部 台南 归仁 基地 ; 陆军 也 预计 邀 媒体 参访 , 最新型 的 ah - 64 e 直升机 最快 6日 就 能 在 民众 面前 亮相 。 台湾地区 向 美国 购买 30架 长 弓阿帕 契 攻击 直升机 ( ah - 64 e ) 是 前 美国总统 布什 ( george   w .   bush ) 政府 在 2008年 宣布 售 台 , 总金额 达 新台币 593.1亿元 ; 除了 美国 外 , 台湾 是 第2个 拥有 此 机型 的 地区 。 中新网 11月 4日 电   据 台湾 “ 中央社 ” 报道 , 台当局 防务 部门 负责人 严明 今天 ( 4日 ) 证实 台军 采购 的 最新型 阿帕契 直升机 ( ah - 64 e ) 已 抵 高雄港 。 陆军 表示 , 吊挂 顺利 , 正 进行 组装 、 地面 测试 。 严明 上午 在 台当局 “ 立法院 ” 答询 时 指出 , 首批 6架 阿帕契 直升机 ( ah - 64 e ) 已 抵 台 。 台湾 陆军 指出 , 6架 直升机 以 海运 方式 运抵 高雄港 , 上午 吊挂 上岸 作业 顺利 , 正在 进行 组装 , 组装 完 后 , 会 做 地面 测试 , 包括 开车 、 旋翼 转动 等 测试 , 相关 过程 军方 全程 保密 。 陆军 说 , 测试 结束 后 , 阿帕契 直升机 将 在 6日 或 7日 飞抵 陆军 航空 特战 指挥部 台南 归仁 基地 ; 陆军 也 预计 邀 媒体 参访 , 最新型 的 ah - 64 e 直升机 最快 6日 就 能 在 民众 面前 亮相 。 台湾地区 向 美国 购买 30架 长 弓阿帕 契 攻击 直升机 ( ah - 64 e ) 是 前 美国总统 布什 ( george   w .   bush ) 政府 在 2008年 宣布 售 台 , 总金额 达 新台币 593.1亿元 ; simhash的二进制表示:10110101100101110011011111001010100110000100000000000000000000001011000110010101001101111100101010011000010000000000000000000000simhash的BigInteger表示:23078054731972307805456781ns1与ns的汉明距离2

经验表明,在hash值为64位的情况下距离小于等于3表明这两篇文章相似。


原创粉丝点击