使用solr+ansj(nlpcn)实现文本相关性分析

一个项目需求是要从N个目标网站上采集相关的文章,然后做文本分析提炼关键词以及文章之间的关联,当然还要实现全文检索。采集使用的是scrapy,文章关联的标准做法一般是通过聚类算法或者去重算法,这两种方案的问题是在处理大数据时,性能完全跟不上。权衡之后,我的大致的方案是先计算每篇文章的词频和关键词权重,最后利用关键词权重作为参数去solrcloud里查找评分相对较高的文章作为关联文章。

首先自然语言处理这块是很难的,自己没有高数基础,很多基础的算法只知道概念,就不去从造轮子开始了,找找成熟方案。文本分析首先最基本的是分词,分词做的不好的其它都无从开始,选型过程中参考了mmseg、ansj(nlpcn.org)和IKAnalyzer,试了下分词效果感觉ansj更好一些,而且ansj功能比较全,最终就选了ansj。不过ansj没有相应的solr支持,这块需要自己简单的封装一下。

软件版本:solr-5.2.0, ansj_seg-3.5, nlp-lang-1.1

先解决ansj对solr支持的问题:solr分词需要实现两个抽象类,Tokenizer和TokenizerFactory,分别是用于构建分词器和管理分词器的调用。ansj官方有个项目ansj_seg(https://github.com/NLPchina/ansj_seg),里面提供了一个lucene的plugin,有分词器的实现,可以直接使用,这里只需要构建TokenizerFactory。

package org.ansj.solr;

import org.apache.lucene.analysis.util.TokenizerFactory;
import org.apache.lucene.util.AttributeFactory;

import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import org.apache.lucene.util.*;
import org.apache.lucene.analysis.*;
import org.ansj.lucene.util.*;
import org.ansj.splitWord.analysis.*;
import org.nlpcn.commons.lang.tire.domain.Forest;

public class AnsjTokenizerFactory extends TokenizerFactory
{
    public AnsjTokenizerFactory(Map<String, String> args)
    {
        super(args);
    }

    @Override
    public Tokenizer create(AttributeFactory factory)
    {
        return new AnsjTokenizer(new NlpAnalysis());
    }
}

源码使用maven部署的,在该plugin目录中执行:mvn install -Dmaven.test.skip=true,得到target/ansj_lucene5_plug-3.0.jar,将对应的jar包复制到solr-webapp/WEB-INF/lib/下,开始配置solr schema的分词器:

    <!-- ansj_seg -->
    <fieldType name="text_cn" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
         <tokenizer class="org.ansj.solr.AnsjTokenizerFactory" />
      </analyzer>
      <analyzer type="query">
        <tokenizer class="org.ansj.solr.AnsjTokenizerFactory" />
      </analyzer>
    </fieldType>

重启solr,测试分词效果还是很不错的,不是纯粹的基于词库的,还有基于规则的判断,例如“250美元”:

再来看看ansj_seg的关键词提取的效果:

package org.ansj.demo;

import java.util.Collection;

import org.ansj.app.keyword.KeyWordComputer;
import org.ansj.app.keyword.Keyword;

/**
 * 关键词提取的例子
 * @author ansj
 *
 */
public class KeyWordCompuerDemo {
    public static void main(String[] args) {
        KeyWordComputer kwc = new KeyWordComputer(20);
//        String title = "专家:公务员工资改革就是切掉部分鼻子补脸上";
        String content = "一个黑客想要使其与SimpliSafe基站相通,需要的只是约合250美元(175英镑)价值的硬件来打造一个微控制器,然后再打上几百行代码。";
//        Collection<Keyword> result = kwc.computeArticleTfidf(title, content);
        Collection<Keyword> result = kwc.computeArticleTfidf(content);
        
        System.out.println(result);
       
        for(Object obj : result.toArray()) {
            Keyword keyword = (Keyword) obj;
            System.out.println(keyword.getName() + "\t" + keyword.getFreq() + "\t" + keyword.getScore());
        }
    }
}

结果:
关键词,词频, 关键词权重
一个    2    19.806975105072254
黑客    1    9.616429942317689
基站    1    7.176440255460962
微控制器    1    6.889382645242523
相通    1    6.889382645242523
只是    1    6.028209814587208
价值    1    3.7317489328397
硬件    1    3.3011625175120423
然后    1    1.5788168562014115
需要    1    1.291759245982973
打造    1    0.5741152204368769
代码    1    0.4305864153276577

 

meiking   2016-02-24 15:53:44 评论:0   阅读:367   引用:0

发表评论>>

署名发表(评论可管理,不必输入下面的姓名)

姓名:

主题:

内容: 最少15个,最长1000个字符

验证码: (如不清楚,请刷新)

Copyright@2004-2010 powered by YuLog