Bool查询

之前的查询都是针对某一个field的,Elasticsearch也支持类似关系型数据库中where a=x and c=x这种对多个字段的查询。布尔查询是将多个查询条件组合在一起。

Bool查询现在包括四种子句,must,filter, should, must_not

must:返回的文档必须满足must子句的条件,并且参与计算分值

must_not:返回的文档必须不满足must_not定义的条件。

filter:返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值

should:返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match参数定义了至少满足几个子句。

must查询

must:返回的文档必须满足must子句的条件,并且参与计算分值

例如查询recipe索引中ingredients.name == parmesanpreparation_time_minutes >= 10的记录:

GET /recipe/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ingredients.name": "parmesan"
          }
        },
        {
          "range": {
            "preparation_time_minutes": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

image-20220730143125266

filter查询

filter:返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值

和上面一样,使用filter方式查询recipe索引中ingredients.name == parmesanpreparation_time_minutes >= 10的记录:

GET /recipe/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ingredients.name": "parmesan"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "preparation_time_minutes": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

返回的结果内容与上面一致,但是注意``max_score全部比must查询的结果小1,这是因为filter不会计算relevance score`:

image-20220730143306700

bool 查询会为每个文档计算相关度评分 _score ,再将所有匹配的 mustshould 语句的分数 _score 求和,最后除以 mustshould 语句的总数。

must_not查询

must_not:返回的文档必须不满足must_not定义的条件。

在上面查询的基础上增加一个条件,过滤掉ingredients.name == tuna的记录:

GET /recipe/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ingredients.name": "parmesan"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "ingredients.name": "tuna"
          }
        }
      ], 
      "filter": [
        {
          "range": {
            "preparation_time_minutes": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

从结果可以看到,must_not 语句不会影响评分;它的作用只是将不相关的文档排除。

image-20220730143616024

should查询

should:返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。

在上面查询的基础上增加一个条件,用should查询ingredients.name == parsley的记录:

GET /recipe/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ingredients.name": "parmesan"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "ingredients.name": "tuna"
          }
        }
      ], 
      "should": [
        {
          "match": {
            "ingredients.name": "parsley"
          }
        }
      ], 
      "filter": [
        {
          "range": {
            "preparation_time_minutes": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

查询到的结果虽然和上面一致,但排序有变化,这是因为bool 查询会将所有匹配的 mustshould 语句的分数 _score 求和。

image-20220730144024637

named query

如果想知道到底是bool里面哪个条件匹配,可以使用named query查询:

GET /recipe/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ingredients.name": {
              "query": "parmesan",
              "_name": "parmesan_must"
            } 
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "ingredients.name": {
              "query":   "tuna",
              "_name": "tuna_must_not"
            }
          }
        }
      ], 
      "should": [
        {
          "match": {
            "ingredients.name": {
              "query": "parsley",
              "_name": "parsley_should"
            }
          }
        }
      ], 
      "filter": [
        {
          "range": {
            "preparation_time_minutes": {
              "gte": 10,
              "_name": "preparation_time_minutes_range"
            }
          }
        }
      ]
    }
  }
}

返回结果中将每条记录命中的查询以列表显示出来:

image-20220730154314784