Elasticsearch 7.X 中文分词器 ik 词库的动态扩展

流氓凡 技术分享 2023-03-29 575 0

ik是基于java开发的轻量级的中文分词工具包。它是以开源项目Luence为主体的,结合词典分词和文法分析算法的中文分词组件,下面是ik的Github地址:

下面是官方提供的ik和es版本对照关系:

image.png

ik 的分词粒度:

ik_max_word:会将文本做最细粒度(拆到不能再拆)的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、中华人民、中华、华人、人民共和国、人民、人、民、共和国、共和、和、国国、国歌」,会穷尽各种可能的组合

ik_smart:会将文本做最粗粒度(能一次拆分就不两次拆分)的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、国歌」

ik分词器的安装:

在安装好的es目录下有个plugins,在这个目录下新建ik目录,将解压后的ik分词器文件放在ik目录下:

image.png

然后重启es,观察启动日志发现ik是否被加载进去

image.png

测试中文分词:

ik_max_word 细粒度分词

使用PostMan 向ES服务器 发送Get请求:

http://localhost:9200/_analyze

{
  "text": "人民共和国",
  "analyzer":"ik_max_word"
}

ik 扩展词汇:

上面已经使用了ik分词器,已经有了分词效果,但是再对一些名词进行分词时,会怎么样的,如果测试下:德玛西亚 这个词,我们希望作为一个整体分词

首先进入es安装目录,进入plugins\ik\config 目录下,创建 custom.dic 文件,内容我们写入:德玛西亚,如果你有多个词每个词一行即可

image.png

下面修改plugins\ik\config\IKAnalyzer.cfg.xml文件:

image.png

然后重启es观察启动日志:

image.png

可以看到已经加载我们自定义的词汇。然后我们继续上一步使用postman发送分词请求查看结果即可。

远程动态词库:

上面已经实现对词库的扩展,但是会发现一个弊端,就是一旦扩展后就需要重启es使扩展词汇生效,如果使生产环境怎么能随便对es进行重启呢,对此es提供了远程词汇的方式,我们对远程词汇文件进行修改,es每次都以http请求的方式获取分词,但要符合两个条件:

  • 该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。

  • 该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。

满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。


对此,官方也给出了方案,就是将分词文件放在nginx中,当文件被修改nginx自动返回相应的 Last-Modified 和 ETag:

image.png

下面我们根据官方的方案进行实现下,首先新建一个 ik_dict.txt ,写入以下内容:

德玛西亚
弗雷尔卓德
小毕超

然后将该文件放在nginx的静态资源目录下:

image.png

然后启动nginx,访问http://192.168.40.167:8080/ik_dict.txt,注意修改为自己的ip:

然后修改es安装目录下 /plugins/ik/config/IKAnalyzer.cfg.xml文件:

image.png

然后重启es,继续使用postman测试效果即可。

扩展 - 更新历史索引:

上面已经实现了动态词库的效果,上面使用的都是直接使用分词器进行测试的,在实际使用中不可能这样做的,都是去查询数据的,所以这里就会出现一个问题。

在我们自定义拓展词库更改后,在原先的索引文档中,由于不是新插入的数据,所以其倒排索引列表还是原先的分词列表数据,导致就算拓展了词库,新增的分词也没有生效。在不重新导入数据的前提下,处理办法如下:

通过_update_by_query去更新匹配的文档,如果没有指定查询,那么就会在每个文档上执行更新:


向es服务器发送POST请求:

http://127.0.0.1:9200/user/_update_by_query?conflicts=proceed

其中user为索引名称,conflicts表示如果更新过程中发生异常冲突时如何处理,有两种方案:


  • abort:中止(默认)

  • proceed:继续执行

注意更新索引,会影响线上的es的 qps,尽量选择夜深人静的时候进行更新。

另外,postman可能有自带的超时限制,所以最好使用curl进行更新请求:

curl -XPOST http://127.0.0.1:9200/user/_update_by_query?conflicts=proceed



评论