[[search-request-post-filter]]
=== Post filter

The `post_filter` is applied to the search `hits` at the very end of a search
request,  after aggregations have already been calculated. Its purpose is
best explained by example:

Imagine that you are selling shirts that have the following properties:

[source,js]
-------------------------------------------------
PUT /shirts
{
    "mappings": {
        "item": {
            "properties": {
                "brand": { "type": "keyword"},
                "color": { "type": "keyword"},
                "model": { "type": "keyword"}
            }
        }
    }
}

PUT /shirts/item/1?refresh
{
    "brand": "gucci",
    "color": "red",
    "model": "slim"
}
------------------------------------------------
// CONSOLE
// TESTSETUP


Imagine a user has specified two filters:

`color:red` and `brand:gucci`.  You only want to show them red shirts made by
Gucci in the search results.  Normally you would do this with a 
<<query-dsl-bool-query,`bool` query>>:

[source,js]
--------------------------------------------------
GET /shirts/_search 
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  }
}
--------------------------------------------------
// CONSOLE

However, you would also like to use _faceted navigation_ to display a list of
other options that the user could click on.  Perhaps you have a `model` field
that would allow the user to limit their search results to red Gucci
`t-shirts` or `dress-shirts`.

This can be done with a 
<<search-aggregations-bucket-terms-aggregation,`terms` aggregation>>:

[source,js]
--------------------------------------------------
GET /shirts/_search 
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  },
  "aggs": {
    "models": {
      "terms": { "field": "model" } <1>
    }
  }
}
--------------------------------------------------
// CONSOLE
<1> Returns the most popular models of red shirts by Gucci.

But perhaps you would also like to tell the user how many Gucci shirts are
available in *other colors*. If you just add a `terms` aggregation on the
`color` field, you will only get back the color `red`, because your query
returns only red shirts by Gucci.

Instead, you want to include shirts of all colors during aggregation, then
apply the `colors` filter only to the search results.  This is the purpose of
the `post_filter`:

[source,js]
--------------------------------------------------
GET /shirts/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": { "brand": "gucci" } <1>
      }
    }
  },
  "aggs": {
    "colors": {
      "terms": { "field": "color" } <2>
    },
    "color_red": {
      "filter": {
        "term": { "color": "red" } <3>
      },
      "aggs": {
        "models": {
          "terms": { "field": "model" } <3>
        }
      }
    }
  },
  "post_filter": { <4>
    "term": { "color": "red" }
  }
}
--------------------------------------------------
// CONSOLE
<1> The main query now finds all shirts by Gucci, regardless of color.
<2> The `colors` agg returns popular colors for shirts by Gucci.
<3> The `color_red` agg limits the `models` sub-aggregation 
    to *red* Gucci shirts.
<4> Finally, the `post_filter` removes colors other than red
    from the search `hits`.

