Elodie
Elodie

Reputation: 193

ElasticSearch : Group by field with Terms aggregation and aggregate on Min price

Consider a OneToMany relation between Articles and VariationGroups.

In ElasticSearch, each article document has a "variationGroup" field.

I use a Terms aggregation to group results by the field "variationGroup" of articles documents.
I use a TopHits sub-aggregation to get the first document of each bucket.

How can I get the minimum price of each variation group ? If i use a Min sub-aggregation on my term Aggregation, minimum price will be calculated on documents that match the query.

I would like to get the minimum price for all documents that could be grouped under a variation group.

For example the VariationGroup named "Tshirt with stars" contains 6 Articles. The query "red Tshirt" returns 2 of those 6 articles.
I would like to get the minimum price for the 6 articles and not only for the 2 articles that match the query.

Is that even possible in the same call ?

Here is the corresponding json :

{
  "query": {
    "match": {
      "name": "red Tshirt"
    }
  },
  "size": 0,
  "aggs": {
    "variation_groups": {
      "terms": {
        "field": "variationGroup",
        "size": 0
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "price"
          }
        },
        "max_price": {
          "max": {
            "field": "price"
          }
        },
        "top_article": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  }
}

Upvotes: 1

Views: 3243

Answers (1)

Val
Val

Reputation: 217294

Yes, that's because the aggregations are applied on the matched documents only. You want to use post_filter instead of a normal query, that way your aggregations will run on all documents and then at the very end, only red Tshirt documents will be returned.

{
  "aggs": {
    "variation_groups": {
      "terms": {
        "field": "variationGroup",
        "size": 0
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "price"
          }
        },
        "max_price": {
          "max": {
            "field": "price"
          }
        },
        "top_article": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  },
  "post_filter": {               <---- move your query in a post_filter
      "query": {
         "match": {
            "name": "red Tshirt"
         }
      }
  }   
}

UPDATE

Based on your comment, I would do it like this:

{
  "size": 0,
  "aggs": {
    "variation_groups": {
      "terms": {
        "field": "variationGroup",
        "size": 0
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "price"
          }
        },
        "max_price": {
          "max": {
            "field": "price"
          }
        },
        "top_article": {
          "filter": {
            "query": {
              "match": {
                "name": "red Tshirt"
              }
            }
          },
          "aggs": {
            "top_article": {
              "top_hits": {
                "size": 1
              }
            }
          }
        }
      }
    }
  }
}

Upvotes: 3

Related Questions