概述
本系列主要从从源码的角度介绍es-IK插件,本文主要介绍ik是如何成为es分词插件的,核心是再复习一下es插件开发的一般流程。
plugin-descriptor.properties
首先我们先从es插件的角度来看一下ik分词器的实现。根据之前文章 的介绍,我们知道es插件最终呈现给我们的都是一个zip包,这个包中有插件运行需要的jar包,资源文件以及plugin-descriptor.properties。这个配置文件是es官方要求必带的插件描述信息。ik插件的描述内容如下:
1 | # 介绍 |
从该文件可以看出,IK要求es加载的主类是org.elasticsearch.plugin.analysis.ik.AnalysisIkPlugin。
AnalysisIkPlugin
源码如下:
1 | // 继承Plugin类,实现AnalysisPlugin接口,说明该插件时解析器插件 |
从源码中可以看出ik分词继承官方Plugin类实现AnalysisPlugin接口,确定了自己是解析器插件。从重写了getTokenizers方法可以看出ik插件主要提供了2个名为ik_smart和ik_max_word。
从返回的参数来看,es需要的是AnalysisProvider——解析器提供者接口的实现类。接口主要需要 实现的方法如下:
1 | public interface AnalysisProvider<T> { |
AnalysisProvider提供了1个get方法用于创建一个TokenizerFactory,传入了各种配置参数,这些参数具体对应哪一块的配置,后续再补充。以ik_max_word分词器来看,这个get方法的实现对应的是IkTokenizerFactory::getIkTokenizerFactory下面我们看下这个方法,十分简单:
1 | public class IkTokenizerFactory extends AbstractTokenizerFactory { |
可以看出来官方其实已经提供了AbstractTokenizerFactory,抽象的分词工厂,这个分词工厂实现了TokenizerFactory接口,这个接口就1个方法Tokenizer create()创建分词器,这里我们可以看见,我们用Configuration创建了IK分词器。而AbstractTokenizerFactory主要做的通用工作是提供了以下几个方法:version()获取版本,Index index()返回index对象,IndexSettings getIndexSettings()返回index配置信息,这些方法可以在TokenizerFactory直接使用,但是IK分词器并没有用到,主要就用IndexSettings和Environment构造了自己用的配置对象Configuration
IKTokenizer
下面我们看看IKTokenizer的代码,这就是分词器逻辑的实现,代码如下:
1 | public final class IKTokenizer extends Tokenizer { |
这里重点注意incrementToken()方法,在具体分词1个属性时,会重复调用该方法,直到方法返回false表示这个属性分词完毕,至于分词的结果有:词元文本(charTermAttribute)、词元位置(OffsetAttribute)、词元分类(TypeAttribute)等直接设置即可,因为使用了addAttribute(XXXXAttribute.class);所有es会自动消费这些值。注意这里从感觉是就是用新分词属性覆盖老的数据,es设计就是这样。分出来的元素放到这些属性里,你不能管消费者(IndexWriter)如何使用。
官方对incrementToken方法的注释放在这,如果要写分词插件,深入理解这个方法是如何被es使用的十分重要。
1 | Consumers (i.e., IndexWriter) use this method to advance the stream to the next token. |
整体看下来,分1个属性,主要是连续调用incrementToken()方法,在调用前会先调用rest()设置输入流,调用后(返回false 表示结束)则会调用end()方法。在ik分词器中生成token属性的主要是IKSegmenter,他是ik分词算法实现的核心逻辑,也是我们下一部分关注的重点。