首页 > 技术文章 > 初识IKAnalyzer

freezone 2016-03-03 16:19 原文

package com.sunmap.analyzer;

import java.io.IOException;
import java.io.StringReader;

import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

/**
 *IK分词器核心
 *
 *大体流程:
 *
 *1.待分词的字符串
 *2.创建分词器对象进行分词(在分词之前先加载词库)
 *3.分词完成以后会得到分词后的流,然后一一遍历出来
 */
public class IKSegmenterTest {

    public static void main(String[] args) {
        String text = "黑河:边防官兵零下20余度严寒“摆兵布阵” 如猛虎下山血性十足";
        //执行这段代码时,会去加载词库
        //true 代表是否使用只能分词;false 代表细粒度分词
        IKSegmenter iKSegmenter = new IKSegmenter(new StringReader(text), true);
        Lexeme lexeme = null;
        try {
            //分词,获取下一个词元
            while((lexeme = iKSegmenter.next()) != null){
                System.out.println(lexeme.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

输出结果:

加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
0-2 : 黑河 : CN_WORD
3-5 : 边防 : CN_WORD
5-7 : 官兵 : CN_WORD
7-9 : 零下 : CN_WORD
9-11 : 20 : ARABIC
11-12 : 余 : CN_CHAR
12-13 : 度 : CN_CHAR
13-15 : 严寒 : CN_WORD
16-17 : 摆 : CN_CHAR
17-18 : 兵 : CN_CHAR
18-20 : 布阵 : CN_WORD
22-23 : 如 : CN_CHAR
23-27 : 猛虎下山 : CN_WORD
27-29 : 血性 : CN_WORD
29-31 : 十足 : CN_WORD

下面说一下加载词库:

package com.sunmap.analyzer;

import org.wltea.analyzer.cfg.Configuration;
import org.wltea.analyzer.cfg.DefaultConfig;

public class DefaultConfigTest {

    /**
     * Configuration词库的配置管理类
     * 
     * IKAnalyzer分词器有自己的词库,在org/wltea/analyzer/dic/main2012.dic
     * 量词词库:org/wltea/analyzer/dic/quantifier.dic
     * 
     * 获取扩展字典配置路径:[ext.dic]   如果提供的词库没有我们想要的可以加在这个文件里
     * 获取扩展停止词典配置路径:[stopword.dic]     同理~
     * 
     * 
     * */
    
    
    
    public static void main(String[] args) {
        Configuration defaultConfig = DefaultConfig.getInstance();
        System.out.println(" 获取主词典路径:"+defaultConfig.getMainDictionary());
        System.out.println("获取量词词典路径:"+defaultConfig.getQuantifierDicionary());
        System.out.println("获取扩展字典配置路径:"+defaultConfig.getExtDictionarys());
        System.out.println("获取扩展停止词典配置路径:"+defaultConfig.getExtStopWordDictionarys());
    }
}

接下来说一下如何自己写一个分词器类:


package com.sunmap.analyzer;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.wltea.analyzer.lucene.IKTokenizer;

/**
 *        自己实现IK分词器
 *    
 *        分词器的核心类Analyzer,TokenStream,Tokenizer,TokenFilter.
 *        Analyzer:Lucene中的分词器有StandardAnalyzer, StopAnalyzer,SimpleAnalyzer,WhitespaceAnalyzer
 *        TokenStream:分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息.可以通过TokenStream有效的获取到分词单元
 *        Tokenizer:主要负责接收字符流Reader,将Reader进行分词操作.
 *        TokenFilter:将分好词的语汇单元进行各种各样的过滤. 
 *
 */
public class MyAnalyzer extends Analyzer{

    /*
     * 分词类的大体流程:
     * 1.首先要写一个继承自Analyzerde的类,即:MyAnalyzer
     * 2.MyAnalyzer对象调用tokenStream(String str,Reader reader)方法时该方法会调用createComponents(String arg0, Reader arg1)方法,
     *     createComponentsfan方法是继承Analyzer类必须要重写的方法,也就是你要创建什么样类型的分词类;
     * 
     *     tokenStream(String str,Reader reader)在调用时,里面有将分好词的语汇单元进行各种各样的过滤.
     * 
     * */
    
    
    @Override
    protected TokenStreamComponents createComponents(String arg0, Reader arg1) {
        System.out.println("----------createComponents------------");
        //这块我们采用的还是IK分词机制,如果想写别的分词,就创建别的对象
        return new TokenStreamComponents(new IKTokenizer(arg1, true));
    }
    
    public static void main(String[] args) {
        MyAnalyzer myAnalyzer = new MyAnalyzer();
        String text = "2016年是小米的关键年,处于势能与舆论是否转向的关键时期,是持续调整还是能扭转态势,乐观的认为触底反弹,悲观的认为大势已去,属于小米的时代已经过去。小米还有招吗,还能迎来第二春吗?14";
        try {
            //
            // 将一个字符串创建成Token流,第一个参数没啥用处
            TokenStream tokenStream = myAnalyzer.tokenStream("1111",
                    new StringReader(text));
            // 获取词与词之间的位置增量
            PositionIncrementAttribute postiona = tokenStream.addAttribute(PositionIncrementAttribute.class);
            // 获取各个单词之间的偏移量
            OffsetAttribute offseta = tokenStream.addAttribute(OffsetAttribute.class);
            // 获取每个单词信息(保存相应词汇)
            CharTermAttribute chara = tokenStream.addAttribute(CharTermAttribute.class);
            // 获取当前分词的类型
            TypeAttribute typea = tokenStream.addAttribute(TypeAttribute.class);
            
            tokenStream.reset();
            while (tokenStream.incrementToken()) {
                 System.out.print("位置增量" +postiona.getPositionIncrement()+":\t");
                 System.out.println(chara+"\t[" + offseta.startOffset()+" - " + offseta.endOffset() + "]\t<" + typea.type() +">");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

 

 

输出结果:

----------createComponents------------
加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
位置增量1: 2016年 [0 - 5] <TYPE_CQUAN>
位置增量1: 小米 [6 - 8] <CN_WORD>
位置增量1: 关键 [9 - 11] <CN_WORD>
位置增量1: 处于 [13 - 15] <CN_WORD>
位置增量1: 势 [15 - 16] <CN_CHAR>
位置增量1: 能与 [16 - 18] <CN_WORD>
位置增量1: 舆论 [18 - 20] <CN_WORD>
位置增量1: 是否 [20 - 22] <CN_WORD>
位置增量1: 转向 [22 - 24] <CN_WORD>
位置增量1: 关键时期 [25 - 29] <CN_WORD>
位置增量1: 持续 [31 - 33] <CN_WORD>
位置增量1: 调整 [33 - 35] <CN_WORD>
位置增量1: 还是 [35 - 37] <CN_WORD>
位置增量1: 能 [37 - 38] <CN_CHAR>
位置增量1: 扭转 [38 - 40] <CN_WORD>
位置增量1: 态势 [40 - 42] <CN_WORD>
位置增量1: 乐观 [43 - 45] <CN_WORD>
位置增量1: 认为 [46 - 48] <CN_WORD>
位置增量1: 触底 [48 - 50] <CN_WORD>
位置增量1: 反弹 [50 - 52] <CN_WORD>
位置增量1: 悲观 [53 - 55] <CN_WORD>
位置增量1: 认为 [56 - 58] <CN_WORD>
位置增量1: 大势已去 [58 - 62] <CN_WORD>
位置增量1: 属于 [63 - 65] <CN_WORD>
位置增量1: 小米 [65 - 67] <CN_WORD>
位置增量1: 时代 [68 - 70] <CN_WORD>
位置增量1: 已经 [70 - 72] <CN_WORD>
位置增量1: 过去 [72 - 74] <CN_WORD>
位置增量1: 小米 [75 - 77] <CN_WORD>
位置增量1: 还有 [77 - 79] <CN_WORD>
位置增量1: 招 [79 - 80] <CN_CHAR>
位置增量1: 还能 [82 - 84] <CN_WORD>
位置增量1: 迎来 [84 - 86] <CN_WORD>
位置增量1: 第二 [86 - 88] <CN_WORD>
位置增量1: 春 [88 - 89] <CN_CHAR>
位置增量1: 14 [91 - 93] <ARABIC>

 

推荐阅读