查询与过滤
Elasticsearch 使用的查询语言(DSL)拥有一套查询组件,这些组件可以以无限组合的方式进行搭配。这套组件可以在以下两种情况下使用:
过滤情况(filtering context)和查询情况(query context)。
当使用于 过滤情况 时,查询被设置成一个“不评分”或者“过滤”查询。即,这个查询只是简单的问一个问题:“这篇文档是否匹配?”。回答也是非常的简单,yes 或者 no ,二者必居其一。
- created 时间是否在 2013 与 2014 这个区间?
- status 字段是否包含 published 这个单词?
- lat_lon 字段表示的位置是否在指定点的 10km 范围内?
当使用于 查询情况 时,查询就变成了一个“评分”的查询。和不评分的查询类似,也要去判断这个文档是否匹配,同时它还需要判断这个文档匹配的有 多好(匹配程度如何)。 此查询的典型用法是用于查找以下文档:
- 查找与 full text search 这个词语最佳匹配的文档
- 包含 run 这个词,也能匹配 runs 、 running 、 jog 或者 sprint
- 包含 quick 、 brown 和 fox 这几个词 — 词之间离的越近,文档相关性越高
- 标有 lucene 、 search 或者 java 标签 — 标签越多,相关性越高
一个评分查询计算每一个文档与此查询的 相关程度,同时将这个相关程度分配给表示相关性的字段 _score,并且按照相关性对匹配到的文档进行排序。这种相关性的概念是非常适合全文搜索的情况,因为全文搜索几乎没有完全 “正确” 的答案。
举例:
以下是在搜索API的查询和过滤器中使用的查询子句的示例。 此查询将匹配满足以下所有条件的文档:
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
-
query
参数指示查询内容 -
bool
和两个
match
子句在查询内容中使用,这意味着它们用于对每个文档的匹配程度进行评分。 -
filter
参数指示过滤器内容。 它的
term
和
range
子句用于过滤器上下文。 它们将过滤出不匹配的文档,但不会影响匹配文档的分数。
性能差异
过滤查询(Filtering queries)只是简单的检查包含或者排除,这就使得计算起来非常快。考虑到至少有一个过滤查询(filtering query)的结果是 “稀少的”(很少匹配的文档),并且经常使用不评分查询(non-scoring queries),
结果会被缓存到内存中以便快速读取
,所以有各种各样的手段来优化查询结果。
相反,评分查询(scoring queries)不仅仅要找出匹配的文档,还要计算每个匹配文档的相关性,计算相关性使得它们比不评分查询费力的多。同时,查询结果并不缓存。
多亏倒排索引(inverted index),一个简单的评分查询在匹配少量文档时可能与一个涵盖百万文档的filter表现的一样好,甚至会更好。
但是在一般情况下,一个filter 会比一个评分的query性能更优异,并且每次都表现的很稳定
。
过滤(filtering)的目标是减少那些需要通过评分查询(scoring queries)进行检查的文档。
如何选择查询与过滤
通常的规则是,使用查询(query)语句来进行 全文 搜索或者其它任何需要影响 相关性得分 的搜索。除此以外的情况都使用过滤(filters)
。