#研究背景
    近期工作需要优化公司的分词器,需要改写IK源码,故而知其然知其所以然,Lucene分词相关的原理和实现研究透彻之后,可以研究ES IK分词器的源码了。以下源码的研究,是基于Lucene 6.6.0版本,Lucene源码中文档很规范,结合文档和源码学习效率很高。本文的所有内容,均来自于Lucene的文档和代码示例。
#类图
    如类图所示,Lucene中和分词相关的最核心的几个类。Analyzer用于构建TokenStream(用于分析文本),提供了用于提取文本生成词项(term)的策略。为了定义哪些Analyzer就绪,子类必须实现createComponents方法,组件分词时,调用tokenStream方法。
    TokenStream枚举了一系列tokens,它们来自documents.field或者query text。TokenStream是一个抽象类,具体的实现分为Tokenizer和TokenFilter。Tokennizer的输入是Reader,TokenFilter的输入是另一个tokenFilter。

TokenStream API工作流程
1、初始化TokenStream时添加对应的属性
2、客户端调用TokenStream.reset()
3、客户端获取需要访问的属性的本地引用
4、客户端调用incrementToken()直到返回false,每次调用就可以获取对应的token的属性
5、客户端调用end()方法让TokenStream执行扫尾操作
6、客户端使用完TokenStream后调用close()释放资源
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | public static void main(String[] args) throws Exception {Analyzer analyzer = new StandardAnalyzer();
 String str = "中华人民";
 TokenStream stream = analyzer.tokenStream("content", new StringReader(str));
 CharTermAttribute attr = stream.addAttribute(CharTermAttribute.class);
 PositionIncrementAttribute posIncr = stream.addAttribute(PositionIncrementAttribute.class);
 OffsetAttribute offset = stream.addAttribute(OffsetAttribute.class);
 TypeAttribute type = stream.addAttribute(TypeAttribute.class);
 stream.reset();
 int position = 0;
 while (stream.incrementToken()) {
 int increment = posIncr.getPositionIncrement();
 if (increment > 0) {
 position = position + increment;
 System.out.print(position + ": ");
 }
 
 System.out.println(attr.toString() + "," + offset.startOffset() + "->" + offset.endOffset() + "," + type.type());
 }
 stream.end();
 stream.close();
 analyzer.close();
 }
 
 
 执行结果:
 1: 中,0->1,<IDEOGRAPHIC>
 2: 华,1->2,<IDEOGRAPHIC>
 3: 人,2->3,<IDEOGRAPHIC>
 4: 民,3->4,<IDEOGRAPHIC>
 
 |