重生之我们在ES顶端相遇第8 章- 它来了,开发中最常用的查询: Bool 查询

76 阅读3分钟

思维导图

image.png

1 前言

在前几章,我们介绍了,如何创建 Mapping,以及常见的搜索。 接下来,我们将介绍开发中最最最常用的查询: Bool Query

为什么常用呢?
因为 Bool Query 足够灵活,能够满足大部分业务开发。

Bool Query 一共有 4 个参数,我们也将介绍该 4 个参数。

  • must
  • filter
  • should
  • must_not

2 must

2.1 描述

文档必须满足 must 中声明的查询条件,并且贡献得分
非常重要的一点:must 是贡献得分的。贡献得分也就意味着,ES 有额外的开销去计算得分。

2.2 demo

写入文档

PUT /test6/_doc/1
{
  "name": "hello world",
  "hobby": "basketball",
  "company": "a",
  "ctime": "2024/07/22 00:00:00"
}

PUT /test6/_doc/2
{
  "name": "welcome my channel",
  "hobby": "watch TV",
  "company": "b",
  "ctime": "2024/06/22 00:00:00"
}

PUT /test6/_doc/3
{
  "name": "love apple",
  "hobby": "pingpong",
  "company": "C",
  "ctime": "2024/05/22 00:00:00"
}

查询 ctime 大于等于 2024/06/22 00:00:00hobbywatch TV 的文档。

GET /test6/_search
{
  "query": {
    "bool": {
      "must": [
        {
         "range": {
           "ctime": {
             "gte": "2024/06/22 00:00:00"
           }
         }
        },
        {
          "term": {
            "hobby.keyword": "watch TV"
          }
        }
      ]
    }
  }
}

must 参数是一个数组,可以包含多个子查询。

2.3 得分计算规则

must 得分计算规则 = sum(所有子查询的得分)

3 must_not

文档必须不能满足 must_not 中的子查询,不贡献得分

GET /test6/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "hobby": "TV"
          }
        },
        {
          "range": {
            "ctime": {
              "gte": "2024/06/12 00:00:00",
              "lte": "2024/06/23 00:00:00"
            }
          }
        }
      ]
    }
  }
}

4 should

4.1 描述

Mysql 的 or 查询类似。默认只要满足 should 中一个子查询(在存在 must 或者 filter 的情况下,should 默认不生效)。

4.2 demo

GET /test6/_search?explain=true
{
  "query": {
    "bool": {
      "should": [
        {
          "terms": {
            "hobby.keyword": ["watch TV", "basketball"]
          }
        },
        {
          "match": {
            "name": "hello"
          }
        }
      ]
    }
  }
}

4.3 最少匹配 minimum_should_match

minimum_should_match 可以修改至少要被满足的子查询个数。

GET /test6/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "terms": {
            "hobby.keyword": ["watch TV", "basketball"]
          }
        },
        {
          "match": {
            "name": "hello"
          }
        }
      ],
      "minimum_should_match": 2
    }
  }
}

minimum_should_match:文档必须满足至少 2 个 should 中的子查询。

再来看个 demo:当存在 must 或者 filter 时,minimum_should_match 值默认为 0,即 should 语句不生效。

GET /test6/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "hello"
          }
        }
      ],
      "should": [
        {
          "terms": {
            "hobby.keyword": ["not match"]
          }
        }
      ]
    }
  }
}

4.4 得分计算规则

should 得分计算规则 = sum(所有子查询的得分)

5 filter

5.1 描述

文档必须满足 filter 中的子查询,且不贡献算分。

重要:ES 会缓存 filter 中的子查询结果,可以加速查询!!!在实际开发中,如果查询条件不需要算分,都可以放在 filter 中执行。

5.2 demo

GET /test6/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "company": "a"
          }
        }
      ]
    }
  }  
}

6 混合使用demo

GET /test6/_search?explain=true
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "hello pingpong",
            "fields": ["name^2", "hobby"]
          }
        }
      ], 
      "filter": [
        {
          "terms": {
            "company": ["a", "b", "c"]
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "ctime": {
              "gte": "2024/06/12 00:00:00",
              "lte": "2024/06/23 00:00:00"
            }
          }
        }
      ]
    }
  }  
}

7 总结

mustmust_notshouldfilter
描述必须匹配必须不能匹配选择性匹配必须匹配
算分sum(子查询得分)不算分sum(子查询得分)不算分, ES 会缓存子查询结果