ElasticSearch | bool 查询 | Query Content vs Filter Context

本文深入解析Elasticsearch中的Bool查询,包括must、should、must_not和filter子句的使用,以及如何通过boost调整字段权重,实现更精准的搜索结果。

bool 查询 | 复合查询

  • 一个 bool 查询,是一个或多个查询子句的组合;
  • bool 查询总共包含 4 种子句,其中 2 种会影响算分,2 种不影响算分;
Query Context | 影响算分
  • must
  • should
Filter Context | 不影响算分
  • must_not
  • filter - 必须匹配

相关性算分不只是全文本检索的专利,也适用于 Yes | No 的子句,匹配的子句越多,相关性评分越高;如果多条查询子句被合并为一条复合查询语句,比如 bool 查询,则每个查询子句计算得出的评分会被合并到总的相关性评分中;

bool 查询 | 举几个栗子

0 | bool 查询 | 基本语法
POST /products/_search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "price" : "30" }
      },
      "filter": {
        "term" : { "avaliable" : "true" }
      },
      "must_not" : {
        "range" : {
          "price" : { "lte" : 10 }
        }
      },
      "should" : [
        { "term" : { "productID.keyword" : "JODL-X-1937-#pV7" } },
        { "term" : { "productID.keyword" : "XHDK-A-1293-#fJ3" } }
      ],
      "minimum_should_match" :1
    }
  }
}
1 | 多值(数组)字段的精确匹配 | must 子句 | 结果有算分
  • 改变数据模型,增加字段,解决数组包含而不是精确匹配的问题;
POST /newmovies/_bulk
{ "index": { "_id": 1 }}
{ "title" : "Father of the Bridge Part II","year":1995, "genre":"Comedy","genre_count":1 }
{ "index": { "_id": 2 }}
{ "title" : "Dave","year":1993,"genre":["Comedy","Romance"],"genre_count":2 }
  • 数组字段精确匹配的查询语法,通过增加 genre_count 字段的限制;
POST /newmovies/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"genre.keyword": {"value": "Comedy"}}},
        {"term": {"genre_count": {"value": 1}}}
      ]
    }
  }
}
2 | 多值(数组)字段的精确匹配 | filter 子句 | 结果无算分
POST /newmovies/_search
{
  "query": {
    "bool": {
      "filter": [
        {"term": {"genre.keyword": {"value": "Comedy"}}},
        {"term": {"genre_count": {"value": 1}}}
        ]
    }
  }
}
3 | 准备数据 | blogs
DELETE blogs
POST /blogs/_bulk
{ "index": { "_id": 1 }}
{"title":"Apple iPad", "content":"Apple iPad,Apple iPad" }
{ "index": { "_id": 2 }}
{"title":"Apple iPad,Apple iPad", "content":"Apple iPad" }
4 | 通过 boost 提高某个字段的权重
  • 对于关键词 "apple ipad" 而言,其在 2 篇文档的 2 个字段中的命中率都是 100%,区别在于,_id 为 1 的字段中,title 字段的命中率为 1/3,_id 为 2 的字段中,title 字段的命中率为 2/3;
  • 如果不为字段指定 boost 的值,2 篇文档的算分是一样的;
  • 如果指定了 title 的 boost 值更大,意味着 title 贡献率更大的 _id 为 2 的文档的算分会更大,反之亦然;
POST blogs/_search
{
  "query": {
    "bool": {
      "should": [
        {"match": {
            "title": {
              "query": "apple,ipad",
              "boost": 1.1
            }
          }
        },
        {"match": {
            "content": {
              "query": "apple,ipad",
              "boost":2
            }
          }
        }
      ]
    }
  }
}
5 | 准备数据 | news
POST /products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10,"avaliable":true,"date":"2018-01-01", "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20,"avaliable":true,"date":"2019-01-01", "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30,"avaliable":true, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30,"avaliable":false, "productID" : "QQPX-R-3956-#aD8" }
6 | bool 查询
  • 文档的 content 字段必须包含 "apple";
POST news/_search
{
  "query": {
    "bool": {
      "must": {
        "match":{"content":"apple"}
      }
    }
  }
}
  • 文档的 content 字段必须包含 "apple",并且必须不包含 "pie";
POST news/_search
{
  "query": {
    "bool": {
      "must": {
        "match":{"content":"apple"}
      },
      "must_not": {
        "match":{"content":"pie"}
      }
    }
  }
}
  • 文档的 content 字段可以包含 "apple" ,也可以包含 "pie",只不过把包含 "pie" 的算分打低一点;
POST news/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "content": "apple"
        }
      },
      "negative": {
        "match": {
          "content": "pie"
        }
      },
      "negative_boost": 0.5
    }
  }
}
### Elasticsearchfilterquery 的使用对比 在 Elasticsearch 中,`filter` 和 `query` 是两种不同的查询方式,它们的使用场景和性能表现各有不同。理解它们的区别有助于优化搜索性能。 #### 1. **Query Context** 在 `query` 上下文中,Elasticsearch 会计算文档与查询条件的相关性得分(relevance score)。这意味着系统不仅要查找匹配的文档,还要评估这些文档与查询的匹配程度。这种方式适用于需要排序和评分的场景,例如全文检索。 ```json { "query": { "match": { "flag": "foo" } } } ``` 这种查询方式返回的结果是根据相关性排序的,适合用于用户输入关键词进行模糊匹配的场景 [^1]。 #### 2. **Filter Context** 在 `filter` 上下文中,Elasticsearch 不会计算相关性得分,而是仅仅判断文档是否满足查询条件。由于不涉及评分计算,`filter` 查询通常比 `query` 更快,并且可以利用缓存机制来提高性能。这种方式适用于精确匹配或范围查询等不需要评分的场景。 ```json { "query": { "bool": { "filter": [ { "term": { "status": "published" } }, { "range": { "date": { "gte": "2023-01-01" } } } ] } } } ``` `filter` 查询特别适合那些频繁执行但结果不会经常变化的查询,因为 Elasticsearch 可以将这些查询的结果缓存起来,从而加快后续请求的响应速度 [^3]。 #### 3. **性能差异** - **计算开销**:`query` 上下文需要计算相关性得分,因此其计算成本较高;而 `filter` 上下文只需进行布尔判断,计算成本较低。 - **缓存机制**:`filter` 查询可以被完全缓存到 Query Cache 中,而 `query` 查询则无法享受这种级别的缓存优化 [^3]。 - **适用场景**:对于需要评分和排序的复杂查询,应使用 `query`;而对于只需要筛选出符合条件的数据集的情况,则推荐使用 `filter`。 #### 4. **混合使用** 实际应用中,可以根据需求混合使用 `query` 和 `filter`。例如,在一个复杂的搜索请求中,可以通过 `filter` 来缩小搜索范围,然后再通过 `query` 进行精细的相关性匹配。 ```json { "query": { "bool": { "must": [ { "match": { "content": "elasticsearch" } } ], "filter": [ { "term": { "category": "technology" } } ] } } } ``` 此示例中,`match` 查询用于找到包含特定关键词的内容,而 `term` 查询作为过滤器,确保只返回属于“technology”类别的文章 [^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值