如何通过 Elasticsearch 实现复杂的查询过滤条件?

Sherwin.Wei Lv8

如何通过 Elasticsearch 实现复杂的查询过滤条件?

回答重点

通过 Elasticsearch 实现复杂的查询过滤条件,通常需要使用其强大的搜索查询 DSL(Domain Specific Language)。具体来说,可以借助 Bool Query 来结合多个查询条件(must、should、must_not、filter)实现复杂的逻辑筛选。下面是一个实际例子,通过 Bool Query 实现复杂的查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"query": {
"bool": {
"must": [
{"match": {"status": "active"}},
{"range": {"age": {"gte": 30}}}
],
"filter": [
{"term": {"gender": "male"}}
],
"should": [
{"term": {"subscription": "premium"}}
],
"must_not": [
{"term": {"country": "USA"}}
]
}
}
}

这里的查询条件实现了这样一种逻辑:必须满足 status 为 active 和 age 大于等于 30,同时性别是 male,优先推荐 subscription 为 premium,不包括 country 为 USA 的记录。

扩展知识

1)查询子句解读

  • must:必须匹配的查询条件,相当于逻辑“AND”。在上面的例子中,仅查找 status 为 active 而且 age 大于等于 30 的文档。
  • filter:用于过滤文档,但它不影响评分计算。这个在性能上会更高效,适用于那些不需要评分计算的条件。在这里,我们过滤性别为 male 的文档。
  • should:可选的查询条件,相当于逻辑“OR”。匹配 should 子句中的任意一个条件将提升文档的相关性评分。在这个例子中,是为了找到 subscription 为 premium 的文档。
  • must_not:必须排除的查询条件,即不符合这些条件的文档。这个例子中,我们排除 country 为 USA 的文档。

2)评分和优化
在实际应用中,经常会遇到需要评分(scoring)和排序的情况。Elasticsearch 的 scoring 会根据查询条件的权重(boost)以及文档的相关性评分返回查询结果。对于时间敏感和性能敏感的查询,可以使用 filter 子句,因为它不会计算相关性评分,从而提升查询性能。

3)嵌套查询和子查询
对于更为复杂的条件,可以使用 nested query 来处理嵌套对象,使用子查询可以更灵活地组合多个查询逻辑。例如,使用 nested 子句处理带有嵌套结构的 JSON 数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"query": {
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{"match": {"comments.user": "kimchy"}},
{"range": {"comments.date": {"gte": "2022-01-01"}}}
]
}
}
}
}
}

这个例子用于查询 comments 里 user 为 kimchy 且 date 大于等于 2022-01-01 的记录。

4)使用脚本进行高级查询
Elasticsearch 允许使用脚本进行更高级的查询,尽管这可能会耗费更多资源。在 _score 子句里可以用脚本来控制评分逻辑。例如,用一个简单的 Painless 脚本来进行自定义评分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"query": {
"function_score": {
"query": {
"match": {"title": "Elasticsearch"}
},
"script_score": {
"script": {
"source": "doc['views'].value * _score"
}
}
}
}
}

这个例子中,评分由文档的 views 值乘以匹配查询的默认评分值。

Comments
On this page
如何通过 Elasticsearch 实现复杂的查询过滤条件?