# 实验环境
- 操作系统:Ubuntu 18.0.4
- ElasticSearch版本:7.13.2
- 中文分词分词器IK:elasticsearch-analysis-ik-7.13.2
# ik分词器的下载、安装、测试
## 安装方法一:使用elasticsearch-plugin 安装
该方法只支持v5.5.1 之后的版本:
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.13.2/elasticsearch-analysis-ik-7.13.2.zip
## 安装方法二:下载编译好的包进行安装
1、下载
下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
下载和ES相同版本的IK:
2、安装
因为elasticsearch-analysis-ik-7.13.2.zip
是编译好的包,所以只需将elasticsearch-analysis-ik-7.13.2.zip
解压到es的安装目录的/plugins/ik
下面即可:
unzip -o elasticsearch-analysis-ik-7.13.2.zip -d /usr/share/elasticsearch/plugins/ik
3、重启ElasticSearch
查找es进程
ps -ef | grep elastic
杀掉es进程
kill -9 10713
重启es
进入es
的安装目录的bin
下,执行:
./elasticsearch -d
注意
:如果遇到can not run elasticsearch as root
报错,请查看这篇文章:
https://blog.csdn.net/willingtolove/article/details/118398026
4、测试
未使用ik分词器,使用默认分词器效果
POST 127.0.0.1:9200/_analyze
{
"analyzer":"standard",
"text":"中国人"
}
结果:
{
"tokens": [
{
"token": "中",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "国",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "人",
"start_offset": 2,
"end_offset": 3,
"type": "<IDEOGRAPHIC>",
"position": 2
}
]
}
使用IK分词器之后
POST 127.0.0.1:9200/_analyze
{
"analyzer":"ik_max_word",
"text":"中国人"
}
结果:
{
"tokens": [
{
"token": "中国人",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "中国",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 1
},
{
"token": "国人",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 2
}
]
}
# ik分词器使用说明
## ik的分词模式
ik有两种分词模式:ik_smart
, ik_max_word
ik_smart
:会将文本做最粗粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、国歌」ik_max_word
:k_max_word:会将文本做最细粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、共和、国、国歌」,会穷尽各种可能的组合
## 创建索引时设置ik分词
创建users
索引:
PUT 127.0.0.1:9200/users
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "integer"
},
"describe": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}
从上面的例子中可以看到:
- 索引
users
的describe
字段的analyzer
属性设置为了ik_max_word
,表示插入文档时,将describe
字段按照ik_max_word
做分词,然后插入倒排索引; - 索引
users
的describe
字段的search_analyzer
属性设置为了ik_smart
,表示在查询时,先对要查询的text类型的输入做按照ik_smart
分词,再去倒排索引搜索;
# 自定义词库扩展
## 问题
有时候,我们搜索一些词库中没有的词,那应该是没有结果的;
比如:"达文西"这个text,想通过搜索"文西"搜索出来。
首先看下:"达文西"这个会被分成哪些词?
POST 127.0.0.1:9200/_analyze
{
"analyzer":"ik_max_word",
"text":"达文西"
}
{
"tokens": [
{
"token": "达文西",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
}
]
}
从结果中可以看出,只能解析出一个词来,这样的话,搜索"文西"是搜索出来。
## 方法
通过自定义分词词典,来解决该问题。
1、首先进入es根目录中的plugins文件夹下的ik文件夹,进入config目录,创建mydic.dic文件
cd elasticsearch/plugins/ik/config
vi custom.dic
将自定义的词写进去:
达文
文西
2、打开IKAnalyzer.cfg.xml文件,将新建的mydic.dic配置其中
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">mydic.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
如果有多个自定义字典,可以这样配置:
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/mydict1.dic</entry>
3、重启ES
重启后测试:
POST 127.0.0.1:9200/_analyze
{
"analyzer":"ik_max_word",
"text":"达文西"
}
{
"tokens": [
{
"token": "达文西",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "达文",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 1
},
{
"token": "文西",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 2
}
]
}
从结果中可以看到,"达文西"的被分词为:「达文西、达文、文西」三个词。说明自定义分词词典生效。
# 热更新 IK 分词
目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中的如下配置:
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">location</entry>
其中 location
是指一个 url
,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。
该 http
请求需要返回两个头部(header)
,一个是 Last-Modified
,一个是 ETag
,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。
该 http 请求返回的内容格式是一行一个分词,换行符用 \n
即可。
满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。
es-ik
插件源码关于热更新的逻辑:
# 示例接口
[HttpHead("HotUpdate"), HttpPost("HotUpdate"), HttpGet("HotUpdate")]
public IActionResult GetHotUpdateDic()
{
Response.Headers.Add("Last-Modified", DateTime.Now.Ticks.ToString());
Response.Headers.Add("ETag", DateTime.Now.Ticks.ToString());
return Content("达尔\r\n尔文\r\n丽莎");
}
# 测试
在没有配置热更新ik
词库时:
POST 127.0.0.1:9200/_analyze
{
"analyzer":"ik_max_word",
"text":"娜丽莎"
}
{
"tokens": [
{
"token": "娜丽莎",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
}
]
}
配置热更新ik
分词词库:
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">http://192.168.2.95:1660/api/fulltextsearch/HotUpdate</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://192.168.2.95:1660/api/fulltextsearch/HotUpdateEnd</entry>
配置热更新ik
分词词库一分钟后,测试:
POST 127.0.0.1:9200/_analyze
{
"analyzer":"ik_max_word",
"text":"娜丽莎"
}
{
"tokens": [
{
"token": "娜丽莎",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "丽莎",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 1
}
]
}
从测试结果中可以看出,「娜丽莎」的分词结果「娜丽莎、丽莎」,说明热更新已生效。