天天看点

基于 IKAnalyzer 实现 Elasticsearch 中文分词插件

虽然elasticsearch有原生的中文插件elasticsearch-analysis-smartcn(实际上是lucence的org.apache.lucene.analysis.cn.smart.smartchineseanalyzer),但它似乎没能满足我的要求。比如我希望对文档中的“林夕”不分词(就是不要把它当成“林”,“夕”两个字索引),smartcn没法做到。

然后我找到了ik,以及elasticsearch-analysis-ik。elasticsearch-analysis-ik已经有些时候没人维护了。而且它使用的httpclient来获取分词词典。总之各种纠结。

最后,我决定还是自己写一个吧。

原来ikanalyzer的目录结构

加入构建脚本

我发现没有使用任何的构建工具。我不是说不使用构建工具就是不好,而是我已经习惯了使用构建工具,不用就没有安全感。所以,我第一步是给它加构建脚本。

同时,我把原来的ikanalyzerdemo.java改成两个测试类。最后运行测试,确保我的修改没有破坏原有逻辑

将项目拆成core和lucence两个子项目

我发现ik实际上由两部分组成:真正的分词逻辑和扩展lucence分析器的逻辑。可以想象得到

我们需要支持不同版本的lucence

我们可以把ik的分词逻辑应用到其它的搜索引擎上

基于这两点,我决定把原有的项目分成两个子项目。并加上测试:

创建elasticsearch插件

一开始,我还想让elasticsearch插件只依赖core子项目就好了。谁知道要实现elasticsearch的插件还需要依赖lucence。所以elasticsearch插件需要依赖lucence子项目。

实现的过程发现elasticsearch的版本之间有些不同,你可以对比下: analysisikplugin.java和ikanalyzerplugin.java

目前,elasticsearch文档中,关于它的插件的概念和原理说的都非常少!

重构core子项目

目前ik还有一个问题没有解决:灵活扩展现有的词典。比如我希望将“林夕”加入词典,从而使其不分被索引成“林”,“夕”。这样的应用场景非常多的。以至于elasticsearch-analysis-ik自己实现从远程读取词典的功能:dictionary.java:338

但是我觉得这样还是够好。比如,我期望从本地的sqlite中读取词典呢?所以,我将ik原有的关于配置的读取的逻辑抽取出来:

其中cfg.getmaindictionary(),cfg是一个接口configuration的实例,但是dictionary假设getmaindictionary返回的一个文件的路径。所以,我认为这个接口的设计是没有意义的。

我们为什么不让cfg.getmaindictionary()直接返回dictionary要求的词典内容呢,像这样:

这样,我们就可以实现像fileconfiguration,httpconfiguraion,sqliteconfiguration,redisconfiguration等任何你期望的扩展词典方式了。

但是,目前,我还没有实现任何的一种 :p

小结

实际上的重构和本文写的相差无几。还算比较顺利,要感谢原作者。这里,我还有一个问题没想通,就是如何打包才能让大家都方便用,比如方便在elasticsearch中安装。希望大家能多给建议。