Search code examples
elasticsearchelasticsearch-7

Remove selected filters from Nested and Aggregation in Elasticsearh to perform filtered search


I am trying to use elasticsearch (VERSION 7.8.0) to perform Faceted search and have gotten something to work. However I want to remove the selected filters from my returned aggregations. E.g. If I had a shop selling clothes and I filter the products by colour: red Then I don't want colour: red to appear in my aggregations as that has been selected already.

To perform my filters I have the following Nested field on my example products:

"search_filters" : {
    "type" : "nested",
    "properties" : {
        "key" : {
          "type" : "keyword"
        },
        "value" : {
          "type" : "keyword"
        }
     }
 },

So if I had data like

 "search_filters" : [
     {
         "key" : "colour",
         "value" : "red"
     }
 ]

I then perform a search like:

  {
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "search_filters",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "search_filters.key": "colour"
                    }
                  },
                  {
                    "match": {
                      "search_filters.value": "red"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "filters": {
      "nested": {
        "path": "search_filters"
      },
      "aggs": {
        "search_keys": {
          "terms": {
            "field": "search_filters.key"
          },
          "aggs": {
            "search_values": {
              "terms": {
                "field": "search_filters.value"
              }
            }
          }
        }
      }
    }
  }
}

This gives me the right documents but my aggregations shows colour: red E.g.

{
  ...
  "filters": {
    "doc_count": 31,
    "search_keys": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "colour",
          "doc_count": 31,
          "search_values": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "red",
                "doc_count": 31
              }
              ...
            ]
          }
        }
        ...
      ]
    }
  }
}

Is there a way to exclude these from elasticsearch or do I have to manually parse and ignore/remove my selected filters?

I have seen the use of filter in the aggregation field part of the request but I couldn't get that to work with my filter field; especially when I applied more than one filter e.g. colour and size.


Solution

  • You can use the filter aggregation, to exclude those results that match with "search_filters.key": "colour" "search_filters.value": "red". This can contain additional musts for additional filters.

    {
      "query": {
        "nested": {
          "path": "search_filters",
          "query": {
            "bool": {
              "must": [
                {
                  "match": {
                    "search_filters.key": "colour"
                  }
                },
                {
                  "match": {
                    "search_filters.value": "red"
                  }
                }
              ]
            }
          }
        }
      },
      "aggs": {
        "filters": {
          "nested": {
            "path": "search_filters"
          },
          "aggs": {
            "filterResult": {
              "filter": {
                "bool": {
                  "must_not": {
                    {
                      "bool": {
                        "must": [
                          {
                            "match": {
                              "search_filters.key": "colour"
                            }
                          },
                          {
                            "match": {
                              "search_filters.value": "red"
                          }
                        }
                      ]
                    }
                  }
                }
              },
              "aggs": {
                "search_keys": {
                  "terms": {
                    "field": "search_filters.key"
                  },
                  "aggs": {
                    "search_values": {
                      "terms": {
                        "field": "search_filters.value"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    

    Search Result will be

    "hits": {
        "total": {
          "value": 1,
          "relation": "eq"
        },
        "max_score": 0.8754687,
        "hits": [
          {
            "_index": "66222818",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.8754687,
            "_source": {
              "search_filters": [
                {
                  "key": "colour",
                  "value": "red"                 // note this
                }
              ]
            }
          }
        ]
      },
      "aggregations": {
        "filters": {
          "doc_count": 1,
          "filterResult": {
            "doc_count": 0,
            "search_keys": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": []                                // note this
            } 
          }
        }
      }