Elasticsearch2.X与5.X中文分词插件IK配置详解
1.IK的安装与配置
首先是安装,ES安装此处不再赘述,ES对应的版本号大致对比如下
IK version | ES version |
---|---|
master | 6.x -> master |
6.3.0 | 6.3.0 |
6.2.4 | 6.2.4 |
6.1.3 | 6.1.3 |
5.6.8 | 5.6.8 |
5.5.3 | 5.5.3 |
5.4.3 | 5.4.3 |
5.3.3 | 5.3.3 |
5.2.2 | 5.2.2 |
5.1.2 | 5.1.2 |
1.10.6 | 2.4.6 |
1.9.5 | 2.3.5 |
1.8.1 | 2.2.1 |
1.7.0 | 2.1.1 |
1.5.0 | 2.0.0 |
1.2.6 | 1.0.0 |
1.2.5 | 0.90.x |
1.1.3 | 0.20.x |
1.0.0 | 0.16.2 -> 0.19.0 |
根据你的ES的具体版本寻找对应的IK版本
IK的github地址 https://github.com/medcl/elasticsearch-analysis-ik
IK的编译后压缩包地址 https://github.com/medcl/elasticsearch-analysis-ik/releases
注:如果你用的是源码需要手动用maven编译打包一下
获取到压缩包后,扔到Elasticsearch/plugins/ik中进行解压(有的压缩包可能会自带一个父文件夹,那么就需要提取文件夹里面的东西扔到ik里),如果ES版本是2.X的,需要在conf/elasticsearch.yml加入index.analysis.analyzer.ik.type: ik
即可,如果是5.X版本的不需要进行任何的配置,直接启动elasticsearch,可以看到后台log里有写读取ik即为成功。
[2018-10-11 15:13:19,285][INFO ][ik-analyzer ] try load config from /home/es/es/elasticsearch-2.4.4/config/analysis-ik/IKAnalyzer.cfg.xml
[2018-10-11 15:13:19,285][INFO ][ik-analyzer ] try load config from /home/es/es/elasticsearch-2.4.4/plugins/ik/config/IKAnalyzer.cfg.xml
2.IK分词的原理与测试
分词的测试使用curl或者postman都可以,我个人倾向于postman,主要是能保存,要方便一些。下面给出测试代码
首先是分词情况的测试
POST: 127.0.0.1:9100/_analyze
JSON:{
"text":"今天也在摸鱼中度过",
"analyzer":"ik_max_word"
}
其中analyzer里默认是standard,也可以指定其他的自带的分词器如english。ik的分词器有ik_max_word和ik_smart,二者区别前者为最细粒度的拆分,后者最粗粒度。
原本es对于中文的分词会把每一个字单独分开,在使用ik后会分成多个词,如果以最细粒度的ik_max_word拆分的话,结果如下
{
"tokens": [
{
"token": "今天",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "也",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 1
},
{
"token": "摸鱼",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 2
},
{
"token": "摸",
"start_offset": 4,
"end_offset": 5,
"type": "CN_WORD",
"position": 3
},
{
"token": "鱼",
"start_offset": 5,
"end_offset": 6,
"type": "CN_CHAR",
"position": 4
},
{
"token": "中度",
"start_offset": 6,
"end_offset": 8,
"type": "CN_WORD",
"position": 5
},
{
"token": "度过",
"start_offset": 7,
"end_offset": 9,
"type": "CN_WORD",
"position": 6
}
]
}
可以看到除了拆分出常用词外,还删除了介词,以及拆分出单字也有意义的词,比如“摸”,”鱼“这类单独的动词或者名词。对于采用这类分词器的索引,在查询时如果输入”今“或者”天“这样的词是无法查询出对应的索引的,因为分词里没有包含这两个单字。如果输入”摸鱼“,”度过“这样分词的则可以查询出来。
值得一提的是,对于查询时的字符串也会进行一次分词,然后对这个分词与索引里的对应的字符串分词进行匹配,比如对于刚才的查询语句,输入“天”查不到任何东西,输入“也摸鱼”则可以查询出对应的索引。那么输入“天也摸鱼”时实际上也可以查询出对应的索引,原因就是对查询时的字符串分词后出现了”天“、”也“、”摸鱼“这三个词,进行匹配后返回了对应的索引。
3.对索引指定分词器
以上分区器就已经可以完全使用了,然而对于索引而言其默认分词器依然为standard,如果想让新的索引使用ik的话则必须要进行单独的配置。对此有两种方法,一种是只改对应的某几个索引的字段采取分词器,这种情况适用于多语言的索引,对每种语言单独配置分词器。另一种直接设置默认分词器,在设置之后,新加入的所有索引都会默认采用ik作为分词器,下面分别介绍两种的配置。
1)字段单独指定分词器
在建立索引时,比如
PUT 127.0.0.1/testIndex/myType/_mapping
JSON
{
"myType":{
"properties":{
"tag":{
"type":"string",
"analyzer":"ik_max_word"
}
}
}
}
其中testIndex是索引名,myType是该索引的一个type名,tag是其中一个属性,执行该命令后tag这个属性的分词就会采用ik分词
不过要注意一点,对于已建好的属性是无法修改的,要想修改以前的属性只能重新建立索引导入原来的数据。
2)设置默认分词为ik
对于2.X版本中可以直接在对应的elasticsearch.yml里进行如下配置
index.analysis.analyzer.default.type: ik
#如果修改后启动报错请检查ik名是否跟你之前配置的ik名称一致
之后所有新的索引都会自动配置为ik作为分词器,然而跟上面的方法一样,都无法让之前的数据使用ik分词,依然只能重新导入。
对于5.X版本不支持yml配置,启动时会直接告诉你请采用curl修改setting配置来实现默认ik的分词(这种方式对2.X版本依然有效)
PUT http://10.88.2.119:9200/indexName/
{
"settings": {
"analysis": {
"analyzer": {
"default":{
"type":"ik_max_word"
}
}
}
}
}
顺带一提对于setting的配置可以随时更改,无需新建新的索引,代码如下:
PUT 127.0.0.1:9200/indexName/_settings
{
"settings": {
"analysis": {
"analyzer": {
"default":{
"type":"standard"
}
}
}
}
}
如果报错提示index已存在,需要在修改settings之前,执行POST 127.0.0.1:9200/indexName/_close
关闭索引,然后执行完修改settings之后,再执行POST 127.0.0.1:9200/indexName/_open
打开索引即可。
4.配置英文词过滤
以上已经完成了所需的中文分词功能,这里单独提到的英文词过滤是因为ik对于英文分词仅限于根据空格等分隔符来区分出单词来,然后转化为小写,而没有进行进一步的筛选,比如对于english分词器,对于“He likes she",会拆分成"he",“like”,“she”,注意这里拆分出来的是”like“而不是”likes"。然而使用ik分词,则会出现"he",“likes”,“she”,这就意味着查询时输入like是查询不出这条语句的,必须查询likes。为了解决这个问题,我采用的是
http://www.360doc.com/content/16/1017/14/29098895_599094191.shtml
提到的将中文分词与英文过滤混合的方式,配置时如下配置:
index:
analysis:
analyzer:
default:
type: custom
tokenizer: ik_max_word
filter: ["stemmer"]
当然写成
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: ik_max_word
index.analysis.analyzer.default.filter: ["stemmer"]
也是没问题的,不过我喜欢前一种方法,看起来更直观一些。
如果使用settings
"settings": {
"analysis": {
"analyzer": {
"default":{
"type":"custom",
"tokenizer":"ik_max_word",
"filter":["stemmer"]
}
}
}
}
在进行这样的配置之后ik的分词对于加了s之类的单词也能正确分词了~
5.补充:以模板方式自动配置索引分词器
在采用5.X版本的时候,如果不想每次都提前建立索引再存数据的话,可以使用ES的template模板来实现自动配置,代码如下:
PUT 127.0.0.1:9200/_template/myTemplate
{
"template":"my-log-*",
"settings": {
"index": {
"number_of_shards": "3",
"analysis": {
"analyzer": {
"default":{
"type":"custom",
"tokenizer":"ik_max_word",
"filter":["stemmer"]
}
}
}
}
}
}
其作用时在每次加入新索引的时候,检测索引的名字是否匹配"template"属性里的名字,这里的时my-log-*
,那么像my-log-2018-10-12
这样的带有my-log-
前缀的就会自动采用这个模板里的设置。顺带一提的是,这个模板除了配置setting也可以配置mapping,具体内容实际上和新建index的时候一样,可以说是很方便了。
总结
以上就是ES的中文分词的配置,其实弄懂了还是很简单的,只不过2.X版本跳到5.X版本是真的坑,总会出现一些莫名其妙的错误,顺带吐槽一下5.X不支持yml配置默认分词器好坑啊……