安徽省高等级公路工程建设指挥部网站网络营销核心要素
文章目录
- 背景
- 创建索引指定 _all 分词为空格
- 创建索引
- 插入索引数据
- 全字段的模糊检索
- 创建索引指定 _all 分词为 keyword
- 索引创建
- 插入数据
- 模糊检索
- 创建索引不配置 _all
- 不同分词的结果
- 启示录
背景
2018年参与使用 ES 和 Kafka 项目的开发,当时主要是做前端开发,虽然主要工作领域是后端,但是一直很排斥 ES 和 Kafka 这两个组件,后来前后台开发任务交替,断断续续补了一下这两个组件的基础原理,总是记不住,碰到的一些小问题解决后就忘记了,这俩组件的技术债一直欠着。
这周避不开 ES 的一个模糊检索问题,索引创建的时候没有指定 _all 的分词方式,对模糊检索中包含中文的请求的影响是什么?
- query_string 全字段检索时,使用的分词方式是什么?_all 指定的,默认是
standard
。 - query_string 指定字段检索时,使用的分词方式是什么?
whitespace
。 - 索引 mapping 设置了_all 的分词对全字段检索的影响?使用指定的分词方式。
- 创建字段的 mapping 里面没有设置 analyzer 的话,默认的分词方式是什么?
whitespace
。
本文以三个不同索引的全字段模糊检索,ES版本5.4.0 环境,验证结果如下:
- mytest 索引,设置 _all 分词为
whitespace
:有空格走分词,中文词组正常分词,能查到结果。 - article-01 索引,设置 _all 分词为
keyword
:期待输入检索参数即使包含空格,也能直接检出符合条件的数据,实际什么都查不出来。 - article-02 索引,没有设置 _all 分词:有空格正常分词检索,中文单个词能查到,词语查不到。
创建索引指定 _all 分词为空格
创建索引
执行 PUT http://IP:9200/mytest
请求,指定 _all 分词为空格:
{"index_patterns": ["log*","product*"],"settings": {"number_of_shards": 2,"number_of_replicas": 1},"mappings": {"article": {"_all": {"analyzer": "whitespace"},"properties": {"ip": {"type": "keyword"},"method": {"type": "keyword"}}}}
}
执行结果:创建一个索引名称是 mytest
类型 doc
的索引。
插入索引数据
发送 PUT mytest/doc/1 ...5
次请求,插入5条数据:
全字段的模糊检索
验证全字段上模糊检索包含空格和不包含空格的检索结果:
索引指定了 _all 的分词为空格分词,所以检索字符串进行空格分词后查询结果同时查出来分词之前的 239 和 001 的内容。其实我希望得到的是精确的模糊匹配的结果的,空格分词方式不行,那么改成 keyword
分词呢?
创建索引指定 _all 分词为 keyword
索引创建
按相同方法新建一个索引 _all 的分词类型为 keyword
:
"mappings": {"article": {"_all": {"analyzer": "keyword"},"properties": {"method": {"type": "keyword"},"ip": {"type": "keyword"}}}
}
插入数据
相同操作插入数据:
模糊检索
1、输入包含空格的关键字:输入一个带空格的检索,出的结果也不符合预期,无数据。
2、输入不含空格包含在数据中、任意一部分的关键字,能查到数据:
创建索引不配置 _all
相同操作创建索引 article-02,不配置 _all 属性的时候,插入几条数据:
模糊检索使用的中文词组:
单个中文汉字输入时能检索到:
不同分词的结果
1、standard 分词,中文字符串拆成一个个的,英文字符串以空格为单位进行拆分:
2、whitespace 分词,按空格切分:
3、keyword 分词: 直接作为一个整体,不拆分。
启示录
首先,有一个知识点是确定的,在使用 _all 进行全字段检索的时候,分词方式与 _all 设定的分词方式有关,如果索引没有设置,则就是默认的 standard
分词方式。
其次,使用空格的分词方式,那对模糊检索包含空格的内容作分词,结果跟我们常规理解的 SQL 形式的 Like 语法还是不一样的,我们希望的是空格被作为一个整体内容进行检索的。
第三点,网络上说的 query_string 的关键字使用 (*目标字符串*)
包裹后就不会分词,这点无效。
第四点,未指定 _all 的分词方式时,对 ES6.8 以上的高版本的中文词组检索没有影响。
最后一个问题,为什么设置全文检索的分词为 keyword
后,什么输入包含空格的关键字后,检索不到了呢?
ES _all、_source的使用:_all字段连接所有字段的值构成一个用空格(space)分隔的大 string 而被 analyzed 和 index,document 主体保存在_source中。
按这个解释,当 _all 分词方式是 keyword
的时候,目标检索关键字没有被分词,而作为一个整体了。由于 _all 字段存储的值是按空格进行分词,索引后的内容是不含空格,所以目标检索关键字中有空格,就查不到数据。