您的位置:首页 >聚焦 >

干货 | Elasticsearch 检索类型选型指南

2022-04-19 09:10:37    来源:程序员客栈

之前在 DSL 中一次问卷调查中,收集到如下几个和搜索类型相关的问题。

Q1:麻烦讲一下es常用的查询关键词,及使用场景,比如term、match、should、filter等等,谢谢老大......Q2:讲下查询term,match,match_pharse,operator,mget,multi_match等的用法和区别?Q3:term、match、phrase、bool query等常用语法,及对不同类型数据字段的支持。在分词场景下的区别?Q4:fuzzy查询的fuzziness参数不同取值,minimumshouldmatch不同取值负数,百分比等…...Q5:希望可以通俗一点。可以有视频和文档~~

这些问题经常会被问到,今天我们从如下几个方面详细解读一下。

宏观俯瞰 Elasticsearch 检索分类;分类解读各个搜索类型特点及应用场景;各个检索类型的区别。1、宏观俯瞰 Elasticsearch 检索分类以 Elasticsearch 8.1 官方文档为例,检索分类不会也不可能超出这个范围。

这么看,貌似不够清晰,来张脑图梳理一下。

常用的部分下文会详细解读,不常用的建议大家使用前优先阅读一遍官方文档,做到“知己知彼、有的放矢”。

貌似清晰了很多。

说一下,我在初学 Elasticsearch 犯过的“错误”或者遇到的问题,看看大家有没有“中招”。

第一:一把梭用法

Match 检索很好用,召回数据又多。业务凡是涉及检索都是 Match query。

用星爷的话非常应景:“曾经有一堆检索类型放在我面前,我没有珍惜。我挑出 use 最多最爽的 Match query 用的乐此不疲。当召回了一大批不相关的数据才后悔莫及!如果老天再给我一次选型的机会的话,我会优先考虑 Match_phrase"。

图片来自网络

这么说,大家可能没有感觉,后文会有详细示例说明。

第二:自己代码实现“与或非”检索。

由于对于检索类型了解不全,只知道有限的几种类型:term、match、terms等。

不知道 query string 检索类型已经实现了:“AND OR NOT” 与或非检索。

自己实现花了时间不说,也不如 query string 自身实现考虑的全面。

第三:数百个 wildcard 模糊匹配组合导致演示现场集群宕机

这个我在这篇文章有过详细说明,不再赘述。

如上,回头看,出现问题体现在:

检索类型了解不全,拿来就用;

不能分辨不同检索类型的应用场景和可能的副作用;

项目着急只关注了能用,没有关注“用好”、“好用”。

2、精准匹配检索和全文检索的本质区别

本文继续缩小范围,把重心缩小为最常用的:精准匹配检索、全文检索、组合检索三种类型。

精准匹配检索和全文检索的本质区别:

精准匹配把检索的整个文本不做分词处理,当前一个串整体处理。

而全文检索需要分词处理,对分词后的每个词单独检索然后大bool组合检索。

文章后续内容以如下数据示例展开讨论:

PUTtest-0415{"mappings":{"properties":{"title":{"type":"text","analyzer":"ik_max_word","fields":{"keyword":{"type":"keyword"}}}}}}POSTtest-0415/_bulk{"index":{"_id":1}}{"title":"乌兰图雅经典歌曲30首连播标清_手机乐视视频"}{"index":{"_id":2}}{"title":"乌兰县地区生产总值22.9亿元"}{"index":{"_id":3}}{"title":"乌兰新闻网欢迎您!"}{"index":{"_id":4}}{"title":"乌兰:你说急什么呢,我30岁了"}{"index":{"_id":5}}{"title":"千城胜景丨胜境美誉多彩乌兰"}

精准匹配和全文检索的区别,如下一例说得清楚:

POSTtest-0415/_search{"query":{"match":{"title":"乌兰新闻网欢迎您!"}}}

召回数据(只截取了title)如下:

也就是说:检索“乌兰新闻网欢迎您!”召回了全部数据!

为啥?

检索语句加上“profile:true”,一探究竟:

一句话:match_query 在检索的时候将待检索字符串做了分词处理。

如上所示:检索的时候“乌兰新闻网欢迎您”切词后变成 [ “乌兰”, "新闻网", "新闻”,“网”,“欢迎您”, “欢迎”, “您”]。

有同学会问,咋分的呢?通过 analyzer API 可以看出。

然后,我们再看一下精准匹配的检索实现。

POSTtest-0415/_search{"profile":true,"query":{"term":{"title.keyword":"乌兰新闻网欢迎您!"}}}

profile:true 看到结果如下:

也就是说,精准匹配是拿整个文本串一起 term query检索的,不做分词处理。

有了这个大前提,后面才好理解一些。

接下来,分类解读各个搜索特点及应用场景。

3 精准匹配检索3.1 Term 单字段精准匹配、

Term query 应用场景:单值精准匹配。

注意点:避免将 term query 应用到 text 类型的检索。

再延伸一些,Term 检索针对的是非 text 类型,term 针对 text 类型并不会报错,但结果会达不到预期。

有同学说:我非要将 text 类型应用 term query会怎么样?来吧,看一下效果:

DELETEmy-index-000001#不指定分词器就使用默认:standard 分词器。PUTmy-index-000001{"mappings":{"properties":{"full_text":{"type":"text"}}}}#写入数据PUTmy-index-000001/_doc/1{"full_text":"QuickBrownFoxes!"}#执行检索,并不会召回数据GETmy-index-000001/_search?pretty{"profile":true,"query":{"term":{"full_text":"QuickBrownFoxes!"}}}

检索结果如上图所示,为啥没有召回结果数据?

原因在于:写入的时候,Quick Brown Foxes! 经过默认分词器 standard 处理后,转化为:quick、brown、foxes 存储。

而检索的时候,咱们检索的是:“Quick Brown Foxes”,如下所示。所以:没有数据召回。

3.2 Terms 多字段精准匹配

Terms query 应用场景:多值精准匹配。

注意点:同 term query核心区别:terms query 支持多个值,而 term query 仅支持单个值。

3.3 Range 范围检索

Range query 应用场景:区间范围检索。

注意点1:当“search.allow_expensive_queries”设置为 false 时,range query 在 text 和 keyword 类型的检索不能被执行。

注意点2:range query 对 text、keyword 类型的区间检索实际意义不大。

3.4 Exists 是否存在检索Exists query 应用场景:判定字段是否有值。

特例很多,建议参考官方文档,这里仅强调一个:

DELETEtest-0001PUTtest-0001{"mappings":{"properties":{"title":{"type":"text","index":false}}}}POSTtest-0001/_bulk{"index":{"_id":1}}{"title":"1"}POSTtest-0001/_search{"profile":true,"query":{"exists":{"field":"title"}}}

如上的 exists query 本质上走的是:“ConstantScore(NormsFieldExistsQuery [field=title])“ 检索,由于 title 字段没有被索引,所以没有结果召回。

3.5 Wildcard 类Mysql like 检索

Wildcard 应用场景:通配符检索,类似 MySQL like 查询。

注意:非必要,不使用。看下面截图就知道原因。

关键词: 全文检索 也就是说

相关阅读