Elasticsearch 中的 post_filter 后置过滤器

发布于 2021-06-02 12:59:57 字数 4952 浏览 1148 评论 0

一、概述

post_filter 出现在聚合章节,描述 post_filter 的作用为:只过滤搜索结果,不过滤聚合结果

二、假设一个查询聚合的需求

假设我们的查询需求是:品牌为 ford 的汽车有哪些颜色

这个需求是容易实现的:先限定查询范围(品牌为 ford),再用类型为 terms 的桶对 color 字段做聚合;

1、用查询结果生成聚合结果,然后只返回聚合结果

只要设置 size 参数为 0,就不会返回查询结果(返回 JSON 中,hits.hits 的数组长度为 0)

GET /cars/transactions/_search
{
  "size": 0, 
  "query": {                ---查询
    "bool": {               ---布尔查询
      "filter": {           ---用了过滤器
        "term": {           ---精确匹配
          "make": "ford"    ---匹配make字段为ford的文档
        }
      }
    }
  },
  "aggs": {
    "colors": {
      "terms": {           ---桶类型为terms
        "field": "color"   ---根据color字段聚合
      }
    }
  }
}

返回内容中只有聚合结果

{
  "took" : 144,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [ ]           ---这里面是查询结果,现在长度为0
  },
  "aggregations" : {       ---这里面是用前面的查询结果来做聚合的结果,所有品牌为ford的文档,根据颜色不同进入了两个桶
    "colors" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "blue",  ---蓝色
          "doc_count" : 1
        },
        {
          "key" : "green", ---绿色
          "doc_count" : 1
        }
      ]
    }
  }
}

2、用查询结果生成聚合结果,然后返回聚合结果和查询结果

如果我们想在返回内容中包含查询结果,只要把 "size": 0,这个参数去掉即可

GET /cars/transactions/_search
{
  "query": {                ---查询
    "bool": {               ---布尔查询
      "filter": {           ---用了过滤器
        "term": {           ---精确匹配
          "make": "ford"    ---匹配make字段为ford的文档
        }
      }
    }
  },
  "aggs": {
    "colors": {
      "terms": {           ---桶类型为terms
        "field": "color"   ---根据color字段聚合
      }
    }
  }
}

返回的内容如下所示,hits.hits的内容不再为空,而是包含了查询结果,至于聚合结果和前面是一样的:

{
  "took" : 39,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [                    ---这个JSON数组的每个元素,都一个品牌字段为ford的文档
      {
        "_index" : "cars",
        "_type" : "transactions",
        "_id" : "hVOQeGoBgL6DDzH6-9ay",
        "_score" : 0.0,
        "_source" : {
          "price" : 30000,
          "color" : "green",      ---颜色是green
          "make" : "ford",
          "sold" : "2014-05-18"
        }
      },
      {
        "_index" : "cars",
        "_type" : "transactions",
        "_id" : "ilOQeGoBgL6DDzH6-9ay",
        "_score" : 0.0,
        "_source" : {
          "price" : 25000,
          "color" : "blue",      ---颜色是blue
          "make" : "ford",
          "sold" : "2014-02-12"
        }
      }
    ]
  },
  "aggregations" : {
    "colors" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "blue",
          "doc_count" : 1
        },
        {
          "key" : "green",
          "doc_count" : 1
        }
      ]
    }
  }
}

3、用查询结果生成聚合结果,然后返回聚合结果和被再次过滤后的查询结果

第三种返回的聚合结果与前面两种一模一样,都是品牌为ford的汽车的颜色;

聚合结果生成完毕后,查询结果可以根据post_filter参数的设置而被再次过滤,例如品牌为ford的汽车,可以把其他颜色过滤掉,只要蓝色的,然后再返回,此时返回的查询结果中就只有品牌为ford并且颜色是blue的文档,具体的DSL如下

GET /cars/transactions/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "make": "ford"
        }
      }
    }
  },
  "post_filter": {      ---在生成了聚合结果后,对即将返回的查询结果做一次过滤
    "term": {
      "color": "blue"   ---过滤条件是只保留color字段为blue的文档
    }
  },
  "aggs": {
    "colors": {
      "terms": {
        "field": "color"
      }
    }
  }
}

返回数据如下,可见聚合结果和前面两种一模一样,只是查询结果中只有color字段为blue的文档:

{
  "took" : 13,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "cars",
        "_type" : "transactions",
        "_id" : "ilOQeGoBgL6DDzH6-9ay",
        "_score" : 0.0,
        "_source" : {
          "price" : 25000,
          "color" : "blue",
          "make" : "ford",
          "sold" : "2014-02-12"
        }
      }
    ]
  },
  "aggregations" : {
    "colors" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "blue",
          "doc_count" : 1
        },
        {
          "key" : "green",
          "doc_count" : 1
        }
      ]
    }
  }
}

至此,post_filter 的基本功能已介绍完毕,如果只做查询不做聚合,post_filter 的作用和我们常用的 filter 是类似的,但由于 post_filter 是在查询之后才会执行,所以 post_filter 不具备 filter 对查询带来的好处(忽略评分、缓存等),因此,在普通的查询中不要用 post_filter 来替代 filter。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

已经忘了多久

文章 0 评论 0

15867725375

文章 0 评论 0

LonelySnow

文章 0 评论 0

走过海棠暮

文章 0 评论 0

轻许诺言

文章 0 评论 0

信馬由缰

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文