Query String
Query String Query是Elasticsearch中的一种查询方式,它允许你使用特定的搜索语法来进行复杂的、灵活的查询。
Query String Query是基于Lucene Query Parser解析器的,因此支持丰富的搜索语法,包括但不限于:
- 基本文本查询: "quick brown fox"
- 逻辑操作符 (AND, OR, NOT): "quick AND brown"
- 范围查询: "age:[18 TO 30]"
- 通配符查询: "qu?ck br*wn"
- 分组: "(quick OR brown) AND fox"
- 字段指定查询: "title:quick"
下面是几个例子:
查询所有
GET /product/_search
分页
GET /product/_search?from=0&size=2&sort=price:asc
精准匹配 exact value
GET /product/_search?q=date:2021-06-01
_all搜索 相当于在所有有索引的字段中检索
all搜索与精准匹配就是带不带字段参数的区别,如果把index索引禁用,则all搜索不会去该字段上查询。
GET /product/_search?q=2021-06-01
精准查询-Term query
精确查询用于查找包含指定精确值的文档,而不是执行全文搜索。
term:匹配和搜索词项完全相等的结果
举个例子:
GET /_search { "query": { "term": { "user": "kimchy" } } }
这个查询会找到"user"字段精确匹配"kimchy"的所有文档。
需要注意的是,term
查询对大小写敏感,并且不会进行分词处理。也就是说,如果你在使用 term
查询时输入了一个完整的句子,它将尝试查找与这个完整句子精确匹配的文档,而不是把句子拆分成单词进行匹配。
term和match_phrase的区别
term
查询和 match_phrase
查询是 Elasticsearch 提供的两种查询方式,它们都用于查找文档,但主要的区别在于如何解析查询字符串以及匹配的精确度。
term
查询:这种查询对待查询字符串为一个完整的单位,不进行分词处理,并且大小写敏感。它可以在文本、数值或布尔类型字段上使用,通常用于精确匹配某个字段的确切值。match_phrase
查询:这种查询把查询字符串当作一种短语来匹配。查询字符串会被分词器拆分成单独的词项,然后按照词项在查询字符串中的顺序去匹配文档。只有当文档中的词项顺序与查询字符串中的顺序完全一致时才能匹配成功,match_phrase 查询通常对大小写不敏感,除非你的字段映射或索引设置更改了这个行为。
简单来说,term
查询更多的是做精确的、字面的匹配,而 match_phrase
则是做短语匹配,在搜索结果的精确度上,term
查询比 match_phrase
更高。
terms:匹配和搜索词项列表中任意项匹配的结果
terms
查询用于匹配指定字段中包含一个或多个值的文档。这是一个精确匹配查询,不会像全文查询那样对查询字符串进行分析。
假设你有一个 "user" 的字段,并且你想找到该字段值为 "John" 或者 "Jane" 的所有文档,你可以使用 terms
查询:
GET /_search { "query": { "terms" : { "user" : ["John", "Jane"], "boost" : 1.0 } } }
上面的查询将返回所有"user" 字段等于 "John" 或者 "Jane" 的文档。
其中boost
参数用于增加或减少特定查询的相对权重。它将改变查询结果的相关性分数(_score),以影响最终结果的排名。
例如,在上述 terms
查询中,boost
参数被设置为 1.0。这意味着如果字段 "user" 的值包含 "John" 或 "Jane",那么其相关性分数(_score)就会乘以 1.0。因此,这个设置实际上并没有改变任何东西,因为乘以 1 不会改变原始分数。但是,如果你将 boost
参数设置为大于 1 的数,那么匹配的文档的 _score 将会提高,反之则会降低。
range:范围查找
range 查询允许你查找位于特定范围内的值。这对于日期、数字或其他可排序类型的字段非常有用。
下面的语句会查询出age字段大于等于10,小于等于20的文档。
例子1:假设你有一些表示博客文章的文档,每个文档都有一个发表日期,并且你想找出在特定日期范围内发布的所有文章,你可以使用 range
查询来实现这一目标
GET /_search { "query": { "range" : { "date" : { "gte" : "2020-01-01", "lte" : "2020-12-31", "format": "yyyy-MM-dd" } } } }
在上面的查询中,range
查询被用来查找字段 "date" 的值在 "2020-01-01" 和 "2020-12-31"(包含)之间的所有文档。
range
查询支持以下运算符:
gt
:大于 (greater than)gte
:大于等于 (greater than or equal to)lt
:小于 (less than)lte
:小于等于 (less than or equal to)
例子2:下面的语句会查询出date字段1天前的文档,其中now表示当前时间。
GET product/_search { "query": { "range": { "date": { "gte": "now-1d/d", "lt": "now/d" } } } }
例子3:下面的语句会查询出date字段小于当前时间,大于2021-04-15T08:00:00的文档。time_zone表示时区,意思就是原文档中的数据会被+8小时再去搜索,例如原文档有条数据是:2021-04-15。则该数据能被查询出来。
GET product/_search { "query": { "range": { "date": { "time_zone": "+08:00", "gte": "2021-04-15T08:00:00", "lt": "now" } } } }
过滤器-Filter
过滤器(Filter)是一种特殊类型的查询,它不关心评分 (_score),只关心是否匹配。基于这个原因,过滤器比标准的全文查询更快并且能被缓存。
一个典型的使用场景是布尔查询 (bool
), 它有两个重要的部分:must
和 filter
。must
部分用于全文搜索,filter
部分用于过滤结果。看一个例子:
GET /_search { "query": { "bool": { "must": [ { "match": { "title": "quick" }} ], "filter": [ { "term": { "published": true }} ] } } }
在这个查询中,bool
查询包含了一个 must
子句和一个 filter
子句。must
子句会执行全文搜索并对结果进行评分。在这个例子中,它会找出所有标题包含"quick"的文章。
filter
子句则会在 must
子句的基础上进一步过滤结果。在这个例子中,它会筛选出那些已经发布的文章。这个过滤操作不会影响到评分,因为它只关心是否匹配。
总的来说,过滤器非常适合用于分类、范围查询或者确认某个字段是否存在等场景。过滤器的效率高并且可以被缓存,所以在大型数据集上性能表现良好。
Filter缓存机制
在 Elasticsearch 中,过滤查询结果的缓存机制是非常重要的一个性能优化手段。由于过滤器(filter)只关心是否匹配,而不关心评分 (_score),因此它们的结果可以被缓存以提高性能。
每次 filter 查询执行时,Elasticsearch 都会生成一个名为 "bitset" 的数据结构,其中每个文档都对应一个位(0 或 1),表示这个文档是否与 filter 匹配。这个 bitset 就是被存储在缓存中的部分。
如果相同的 filter 查询再次执行,Elasticsearch 可以直接从缓存中获取这个 bitset,而不需要再次遍历所有的文档来找出哪些文档符合这个 filter。这大大提高了查询速度,并减少了 CPU 使用。
这种缓存策略特别适合那些重复查询的场景,例如用户界面的过滤器和类似的功能,因为他们通常会产生很多相同的 filter 查询。
然而,值得注意的是,虽然这种缓存可以显著改善查询性能,但也会占用内存空间。如果你有很多唯一的过滤条件,那么过滤器缓存可能会变得很大,从而导致内存问题。这就需要你对使用的过滤器进行适当的管理和限制。
另外,Elasticsearch 默认情况下会自动选择哪些过滤器进行缓存,考虑到查询频率和成本等因素。你也可以手动配置某个特定的 filter 是否需要进行缓存。
组合查询-Bool query
组合查询可以组合多个查询条件,bool查询也是采用more_matches_is_better的机制,因此满足must和should子句的文档将会合并起来计算分值。
boot和minumum_should_match是参数,其他四个都是查询子句。
- must:必须满足子句(查询)必须出现在匹配的文档中,并将有助于得分。
- filter:过滤器不计算相关度分数。
- should:满足 or子句(查询)应出现在匹配的文档中。
- must_not:必须不满足,不计算相关度分数 ,not子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被视为用于缓存。
例子1:下面的语句表示:包含"xiaomi"或"phone" 并且包含"shouji"的文档例子:
GET product/_search { "query": { "bool": { "must": [ { "match": { "name": "xiaomi phone" } }, { "match_phrase": { "desc": "shouji" } } ] } } }
should与must或filter一起使用
当 should
子句与 must
或 filter
子句一起使用时,这时候需要注意了!只要满足了 must
或 filter
的条件,should
子句就不再是必须的。换句话说,如果存在一个或者多个 must
或 filter
子句,那么 should
子句的条件会被视为可选。
然而,如果 should
子句与 must_not
子句单独使用(也就是没有 must
或 filter
),则至少需要满足一个 should
子句的条件。
这里有一个例子来说明:
GET /_search { "query": { "bool": { "must": [ { "term": { "user": "kimchy" }} ], "filter": [ { "term": { "tag": "tech" }} ], "should": [ { "term": { "tag": "wow" }}, { "term": { "tag": "elasticsearch" }} ] } } }
在这个查询中,must
和 filter
子句的条件是必须满足的,而 should
子句的条件则是可选的。如果匹配的文档同时满足 should
子句的条件,那么它们的得分将会更高。
那如果我们一起使用的时候想让should满足该怎么办?这时候minimum_should_match
参数就派上用场了。
minimum_should_match
minimum_should_match参数定义了在 should
子句中至少需要满足多少条件。
例如,如果你有5个 should
子句并且设置了 "minimum_should_match": 3
,那么任何匹配至少三个 should
子句的文档都会被返回。
这个参数可以接收绝对数值(如 2
)、百分比(如 30%
)、和组合(如 3<90%
表示至少匹配3个或者90%,取其中较大的那个)等不同类型的值。
注意:如果 bool
查询中只有 should
子句(没有 must
或 filter
),那么默认情况下至少需要匹配一个 should
条件,也就是minimum_should_match
默认值是1,除非 minimum_should_match
明确设定为其他值。如果包含 must
或 filter
的情况下minimum_should_match
默认值 0。
所以我们可以在包含must
或 filter
的情况下,设置minimum_should_match
值来满足should
子句中的条件。
本篇文章就到这里,感谢阅读,如果本篇博客有任何错误和建议,欢迎给我留言指正。
有收获?希望老铁来个三连,给更多的同学看到这篇文章,顺便激励下我,嘻嘻。