#研究背景
近期工作需要优化公司的分词器,需要改写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()释放资源
1 2 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>
|