elasticsearch7.Xterm查询中文即IK分词器的相关解决办法
- 问题的产生
- 问题的原因
- 回到最初的问题
- 解决办法
问题的产生
学习elasticsearch时,当进行精确查询时候,我们发现无法对中文词汇进行有效的检索。但是对单个字进行查询却能检索得到。
查询好人没有结果,查询如果换成“好”,“李白是个大好人”就被查到了。
问题的原因
要弄清怎么回事,首先要知道什么是分词器,以及elasticsearch怎么实现的索引。elasticsearch除了存储数据,还为他们建立了一个索引表,类似书籍的目录。
举个栗子:
存储的数据
地址 | 内容 |
地址1 | good boy |
地址2 | boy friend |
elasticsearch默认的“Standard Analyzer”分词器会将“good boy”分成“good”和“boy”,“boy friend”分成“boy”和“friend”放入索引表
索引表
关键词 | 地址 |
good | 地址1 |
boy | 地址1 地址2 |
friend | 地址2 |
当我们查询时,这里我们先说match查询,查询的内容也会被分词
{
"query":{
"match":{
"name":"good friend"
}
}
}
它会被分成“good”和“friend”用于查询,只要满足其一都会被返回,所以地址1和地址2的都被返回了,这也是我们百度时明明输入个大概就能检索到许多内容。
那么我们换成精确查询呢,会怎么样?
{
"query":{
"term":{
"name":"good friend"
}
}
}
结果就是查不到,因为“good friend”不会被分词,反而作为一个整体去查询,可是索引中并不存在“good friend”这个关键词。
那么怎样实现我想要的查询结果呢?
很简单,使用短语查询的方式。即:phrase query。默认短语中间不能有间隔,但是可使用slop=1来表示中间可以间隔一个term(单词),这个比我们想要的还要灵活,甚至可以决定中间间隔几个单词。
POST /movies/_search
{
"query": {
"match_phrase": {
"title":{
"query": "one love",
"slop": 1
}
}
}
}
说了那么多term的意义何在?
事实上term主要是针对“时间”、“数字”等重要不可分割的查询词。他压根就不是用在这的,我也说了这里应该用phrase query。
回到最初的问题
中文查询,默认分词器分割英文是空格为基准分开的,英文恰好是一个一个的单词。但中文却是被分成了一个个字,“苹果”被分成“苹”和“果”
我们match查询“苹果”时能查出“我爱吃苹果”但也会查到“小朋友苹苹喜欢吃果子”,后面那个并不是我们想要的。
解决办法
引入ik分词器,他能将中文正确分词,还可以自定义词库使得他能识别一些新出现的词汇如“奥利给”
操作如下
1.下载地址: https://github.com/medcl/elasticsearch-analysis-ik/releases
注意: es-ik分词插件版本一定要和es安装的版本对应
2.将文件 解压再改名ik上传到linux根目录下。
(1)因为我是smatty远程操控的linux主机,我先将压缩文件改名ik 。
(2)建立一个plugins目录,进入目录并将ik压缩包拖(直接拖进去就能上传,很方便)进去。
(3)解压压缩包,这里可能没有解压缩的工具,安装方法:
(4)解压缩
(5)把解压的ik文件拷贝到elasticsearch安装包下的plugins下
根据自己的情况可以上网查询ik分词器的导入方法。
ik分词器有两种模式“ik_max_word”和“ik_smart”可以试验下他们的效果,你自己就能看出区别
下面还有一大堆,截不下啦
你以为现在就结束了吗?
当然没有,你还得设置当前索引的mapping和setting,来决定他建立索引表所使用的分词器analyzer(就是分“李白是个大好人”的),以及查询时的查询数据所用的分词器search_analyzer(分“好人”的,用了ik分词器,“好人”不会再分成“好”和“人”了)
setting中还可以设置分片和副本,这里我就不细说了
这里就可以用term查询到好人了,但是意义不大,因为我们知道phrase query就可以办到并且因为引入ik查询器,也避免了“苹果”时能查出“我爱吃苹果”但也会查到“小朋友苹苹喜欢吃果子”的问题。
书写不易,一键三连。