美文网首页
05_Lucene中文分词器

05_Lucene中文分词器

作者: 对方不想理你并向你抛出一个异常 | 来源:发表于2018-01-07 23:39 被阅读0次

    分析器(Analyzer)的执行过程

    如下图是语汇单元的生成过程:


    lucene分词器执行流程.png

    从一个Reader字符流开始,创建一个基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Token。
    要看分析器的分析效果,只需要看Tokenstream中的内容就可以了。每个分析器都有一个方法tokenStream,返回一个tokenStream对象。

    Lucene自带中文分析器

    • StandardAnalyzer:
        单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
        效果:“我”、“爱”、“中”、“国”。
    • CJKAnalyzer
        二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。

    上边两个分词器无法满足需求。

    • SmartChineseAnalyzer
        对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理

    第三方中文分词器

    • paoding: 庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代码在 2008-06-03,在svn中最新也是2010年提交,已经过时,不予考虑。

    • mmseg4j:最新版已从https://code.google.com/p/mmseg4j/ 移至https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。

    • IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 但是也就是2012年12月后没有在更新。

    • ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg , tags仅有1.1版本,从2012年到2014年更新了大小6次,但是作者本人在2014年10月10日说明:“可能我以后没有精力来维护ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所做的分词算法。

    • imdict-chinese-analyzer:最新版在 https://code.google.com/p/imdict-chinese-analyzer/, 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。

    • Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。

    使用IK

    使用方法:

    • 第一步:把jar包添加到工程中


    • 第二步:把配置文件和扩展词典和停用词词典添加到classpath下


    config为src目录

    • IKAnalyzer.cfg.xml如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
    <properties>  
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict">ext.dic;</entry> 
    
        <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords">stopword.dic;</entry> 
        
    </properties>
    

    注意:mydict.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8 编码。

    • 将生成索引的分词器修改为IKAnalyzer()
    package cn.huahcao.lucene;
    
    import org.apache.commons.io.FileUtils;
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    import org.apache.lucene.document.LongField;
    import org.apache.lucene.document.TextField;
    import org.apache.lucene.index.IndexWriter;
    import org.apache.lucene.index.IndexWriterConfig;
    import org.apache.lucene.store.FSDirectory;
    import org.apache.lucene.util.Version;
    import org.junit.Test;
    import org.wltea.analyzer.lucene.IKAnalyzer;
    
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    
    public class IndexManagerTest {
        @Test
        public void testCreateIndex() throws Exception{
            //采集文件系统中的文档数据,放入lucene中
            //文档列表,保存Document
            List<Document> docList = new ArrayList<Document>();
    
            //指定文件所在的目录
            File dir = new File("G:\\Java\\JavaEE\\09_SSM\\lucene_day01\\参考资料\\searchsource");
    
            //循环取出文件
            for (File file:dir.listFiles()){
                //文件名称
                String fileName = file.getName();
                //文件内容
                String fileContext = FileUtils.readFileToString(file);
                //文件大小
                Long fileSize = FileUtils.sizeOf(file);
                //文档对象。文件系统中的一个文件就是一个Document对象
                Document doc = new Document();
                /**
                 * 第一个参数:域名
                 * 第二个参数:域值
                 * 第三个参数:是否存储,是为Yes,不存储为No
                 */
    //            TextField nameFiled = new TextField("fileName",fileName, Field.Store.YES);
    //            TextField contextFiled = new TextField("fileContent",fileContent, Field.Store.YES);
    //            TextField sizeFiled = new TextField("fileSize",fileSize.toString(), Field.Store.YES);
    
                //是否分词:要,因为它要索引,并且它不是一个整体,分词有意义
                //是否索引:要,因为要通过它来进行搜索
                //是否存储:要,因为要直接在页面上显示
                TextField nameFiled = new TextField("fileName", fileName, Field.Store.YES);
    
                //是否分词: 要,因为要根据内容进行搜索,并且它分词有意义
                //是否索引: 要,因为要根据它进行搜索
                //是否存储: 可以要也可以不要,不存储搜索完内容就提取不出来
                TextField contextFiled = new TextField("fileContext", fileContext, Field.Store.NO);
    
                //是否分词: 要, 因为数字要对比,搜索文档的时候可以搜大小, lunene内部对数字进行了分词算法
                //是否索引: 要, 因为要根据大小进行搜索
                //是否存储: 要, 因为要显示文档大小
                LongField sizeFiled = new LongField("fileSize", fileSize, Field.Store.YES);
    
                //将所有的域存入文档中
                doc.add(nameFiled);
                doc.add(contextFiled);
                doc.add(sizeFiled);
    
                //将文档存入文档集合中
                docList.add(doc);
            }
    
            //创建分词器,StandardAnalyzer标准分词器,标准分词器对英文分词效果很好,对中文是单字分词
            Analyzer analyzer = new IKAnalyzer();
            //指定索引和文档存储的目录
            FSDirectory directory = FSDirectory.open(new File("G:\\Java\\JavaEE\\09_SSM\\lucene_day01\\tmp"));
            //创建写对象的初始化对象
            IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);
            //创建索引和文档写对象
            IndexWriter indexWriter = new IndexWriter(directory , config);
    
            //将文档加入到索引和文档的写对象中
            for (Document doc:docList){
                indexWriter.addDocument(doc);
            }
            //提交
            indexWriter.commit();
            //关闭流
            indexWriter.close();
        }
    }
    
    • 执行上面的testCreateIndex()


    • 用luke查看


    从上面可以看出中文是按词义分的,而不是之前的一个字一个字的分

    相关文章

      网友评论

          本文标题:05_Lucene中文分词器

          本文链接:https://www.haomeiwen.com/subject/rfnmnxtx.html