自学内容网 自学内容网

ES filter和post_filter的区别

ES filter和post_filter的区别

在Elasticsearch中,过滤搜索的结果是我们经常要做的事。在我刚开始接触 Elasticsearch,我就了解到有两种可以过滤搜索结果的方法。当时还不是很明白,为什么有的地方用 filter,而有的地方需要使用到 post_filter。在今天的文章中,我来用一个鲜活的例子来进行展示。

总体说来,我们可以使用如下的两个方法来过滤搜索的结果:

使用带有 filter 子句的布尔查询。搜索请求将布尔过滤器应用于搜索命中和聚合。

使用搜索 API 的 post_filter参数。搜索请求仅将 post_filter应用于搜索命中,而不是聚合。你可以使用 post_filter根据更广泛的结果集计算聚合,然后进一步缩小结果。讲得通俗一点:在已经计算聚合之后,post_filter 将应用于搜索请求最后的搜索命中。从这里的描述中,我们可以看出来,post_filter的使用和 aggregation 相关。

你还可以在 post_filter之后重新对命中进行评分,以提高相关性并重新排序结果

Post filter

当你使用 post_filter 参数过滤搜索结果时,会在计算聚合后过滤搜索命中。 Post filter 对聚合结果没有影响。

例如,你销售的衬衫具有以下属性:

PUT shirts

{

  "mappings": {

    "properties": {

      "brand": { "type": "keyword"},

      "color": { "type": "keyword"},

      "model": { "type": "keyword"}

    }

  }

}

我们使用如下的命令来摄入 3 个文档:

PUT shirts/_doc/1?refresh

{

  "brand": "gucci",

  "color": "red",

  "model": "slim"

}



PUT shirts/_doc/2?refresh

{

    "brand": "polo",

    "color": "red",

    "model": "large"

  }



  PUT shirts/_doc/3?refresh

  {

    "brand": "polo",

    "color": "blue",

    "model": "medium"

  }

假想你有一个用户,他想买一个 red 的衣服。通常你会使用如下的 bool query:

GET shirts/_search?filter_path=**.hits

{

 "query": {

   "bool": {

     "filter": [

       {

         "term": {

           "color": "red"

         }

         }

       ]

     }

   }

 }

上面显示的结果为:

{

  "hits" : {

    "hits" : [

      {

        "_index" : "shirts",

        "_id" : "1",

        "_score" : 0.0,

        "_source" : {

          "brand" : "gucci",

            "color" : "red",

            "model" : "slim"

          }

        },

        {

          "_index" : "shirts",

          "_id" : "2",

          "_score" : 0.0,

          "_source" : {

            "brand" : "polo",

            "color" : "red",

            "model" : "large"

          }

        }

      ]

    }

  }

显然搜索的结果显示了所有 red 的衣服。但是,你还想使用分面导航来显示用户可以单击的其他选项列表(比如大小尺寸)。 也许你有一个 model 字段,允许用户将搜索结果限制为红色 Gucci T 恤或 Polo 的衣服。这可以通过 terms aggregation 来完成:

GET shirts/_search

{

  "query": {

    "bool": {

      "filter": [

        {

          "term": {

            "color": "red"

          }

          }

        ]

      }

    },

    "aggs": {

      "models": {

        "terms": {

          "field": "model"

        }

      }

    }

  }

在上面,我们通过 terms 聚合来显示各个尺寸(model)的文档数。最多的将排在前面。上面命令显示的结果为:

{

 "took" : 0,

 "timed_out" : false,

 "_shards" : {

   "total" : 1,

   "successful" : 1,

   "skipped" : 0,

   "failed" : 0

 },

   "hits" : {

     "total" : {

       "value" : 2,

       "relation" : "eq"

     },

     "max_score" : 0.0,

     "hits" : [

       {

         "_index" : "shirts",

         "_id" : "1",

         "_score" : 0.0,

         "_source" : {

           "brand" : "gucci",

           "color" : "red",

           "model" : "slim"

         }

       },

       {

         "_index" : "shirts",

         "_id" : "2",

         "_score" : 0.0,

         "_source" : {

           "brand" : "polo",

           "color" : "red",

           "model" : "large"

         }

       }

     ]

   },

   "aggregations" : {

     "models" : {

       "doc_count_error_upper_bound" : 0,

       "sum_other_doc_count" : 0,

       "buckets" : [

         {

           "key" : "large",

           "doc_count" : 1

         },

         {

           "key" : "slim",

           "doc_count" : 1

         }

       ]

    }

    }

}

在上面,我们可以看出颜色为 red 的衣服,各个 model 的统计情况:large 及 slim 个一件。显然这个是我们想要的结果。我们注意到的一点是 aggregation 是基于前面的 boolean filter 所过滤后的数据集来进行统计的。其统计结果都是是红色的衣服。

但也许你还想告诉用户有多少 polo 衬衫可供选择而不是所有的品牌。我们可以使用如下的搜索:

GET shirts/_search

{

  "query": {

    "bool": {

      "filter": [

        {

          "term": {

            "color": "red"

          }

          }

        ]

      }

    },

    "aggs": {

      "models": {

        "terms": {

          "field": "model"

        }

      }

    },

    "post_filter": {

      "term": {

        "brand": "polo"

      }

    }

}

在上面,我们使用 filter 把 red 的文档搜索出来,然后使用 terms aggregatiion 来对所有 red 的文档进行 model 的统计。我们接下来使用 post_filter 来对我们的搜索结果再次过滤。在这里需要注意的是:post_filter 的使用不会对 aggs 的结果产生任何的影响。如同上面写的顺序一样,post_filter 是在最后面运行的。上面的命令产生的结果是:

{

  "took" : 0,

  "timed_out" : false,

  "_shards" : {

    "total" : 1,

    "successful" : 1,

    "skipped" : 0,

    "failed" : 0

  },

    "hits" : {

      "total" : {

        "value" : 1,

        "relation" : "eq"

      },

      "max_score" : 0.0,

      "hits" : [

        {

          "_index" : "shirts",

          "_id" : "2",

          "_score" : 0.0,

          "_source" : {

            "brand" : "polo",

            "color" : "red",

            "model" : "large"

          }

        }

      ]

    },

    "aggregations" : {

      "models" : {

        "doc_count_error_upper_bound" : 0,

        "sum_other_doc_count" : 0,

        "buckets" : [

          {

            "key" : "large",

            "doc_count" : 1

          },

          {

            "key" : "slim",

            "doc_count" : 1

          }

        ]

      }

    }

  }

如上所示,我们最终得到的搜索结果是 color:red 并且 brand:polo 的搜索结果,但是 aggregations 的结果是针对 color:red 而的出来的。我们可以看到上面的 slim 统计结果是来自 gucci 品牌的而不是 polo。

更为复杂的查询是这样的:

GET shirts/_search

{

 "query": {

   "bool": {

     "filter": {

       "term": { "brand": "polo" }

     }

   }

 },

   "aggs": {

     "colors": {

       "terms": { "field": "color" }

     },

     "color_red": {

       "filter": {

         "term": { "color": "red" }

       },

       "aggs": {

         "models": {

           "terms": { "field": "model" }

         }

       }

     }

   },

   "post_filter": {

     "term": { "color": "red" }

   }

 }

在上面,我们首先使用的 filter 来过滤数据集。只有 brand:polo 的文档才可以进行聚合。aggs 里含有两个 aggregations。一个是按照 colors 来进行的分类,另外一个是先过滤 red 颜色的 polo,然后再按照 model 进行分类。在最后,我们使用 post_fitler 来过滤结果。最终的搜索结果(位于 hits 里)是 brand:polo 并且 color:red:

{

 "took" : 0,

 "timed_out" : false,

 "_shards" : {

   "total" : 1,

   "successful" : 1,

   "skipped" : 0,

   "failed" : 0

 },

   "hits" : {

     "total" : {

       "value" : 1,

       "relation" : "eq"

     },

     "max_score" : 0.0,

     "hits" : [

       {

         "_index" : "shirts",

         "_id" : "2",

         "_score" : 0.0,

         "_source" : {

           "brand" : "polo",

           "color" : "red",

           "model" : "large"

         }

       }

     ]

   },

   "aggregations" : {

     "color_red" : {

       "doc_count" : 1,

       "models" : {

         "doc_count_error_upper_bound" : 0,

         "sum_other_doc_count" : 0,

         "buckets" : [

           {

             "key" : "large",

             "doc_count" : 1

           }

         ]

       }

     },

     "colors" : {

       "doc_count_error_upper_bound" : 0,

       "sum_other_doc_count" : 0,

       "buckets" : [

         {

           "key" : "blue",

           "doc_count" : 1

         },

         {

           "key" : "red",

           "doc_count" : 1

         }

       ]

     }

   }

 }

作者:Elasticsearch

链接:https://juejin.cn/post/7114169318669025316


原文地址:https://blog.csdn.net/Zhuxiaoyu_91/article/details/145327255

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!