概述
本系列主要从从源码的角度介绍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分词算法实现的核心逻辑,也是我们下一部分关注的重点。