6

I have index with Product entities and nested Variation entities. Product entity consist of Id, Title and nested variations. Variation entity consist of Color, Size and Price fields. I need to aggregate search result by Color, Size and Price fields to get number of products for each color, size and price groups. If I use nested aggregation for these fields I get correct buckes but the number of documents in buckets is number of Variation entities per bucket. But I need to get number of Product entities (root documents) per bucket.

For example, the first product has variation (red, small, $10), (green, small, $10), (red, medium, $11) and the second product has variations (green, medium, $15). Nested aggregation returns 2 for red and 2 for small because 2 variations has red color and small size. But I need number of products (root entities) per bucket which should be 1 for red and 1 for small.

I also can't use children documents instead of nested documents because of other requirements.

How to compose the query to get this result?

Here is the mapping:

{
  "product": {
    "properties": {
      "id": {
        "type": "long"
      },
      "title": {
        "type": "string"
      },
      "brand": {
        "type": "string"
      },
      "variations": {
        "type": "nested",
        "properties": {
          "id": {
            "type": "long"
          },
          "colour": {
            "type": "string"
          },
          "size": {
            "type": "string"
          },
          "price": {
            "type": "double"
          }
        }
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

And here is a query

{
  "aggs": {
    "Variations": {
      "nested": {
        "path": "variations"
      },
      "aggs": {
        "Colous": {
          "terms": {
            "field": "variations.colour"
          }
        },
        "Sizes": {
          "terms": {
            "field": "variations.size"
          }
        }
      }
    },
    "Brands": {
      "terms": {
        "field": "brand"
      }
    }
  },
  "query": {
    "match_all": {}
  }
}

The Brand aggregation works well because it gets number of root documents per group but nested aggregations return number of nested documents instead of number of root documents.

2
  • Can you include your mapping in your question as well as the query you're trying? That will help people recreate the problem and find solutions. Commented Oct 10, 2015 at 2:55
  • Sure. Added mapping and query. Commented Oct 10, 2015 at 15:17

1 Answer 1

8

You've tackled the problem the right way. Now you can simply use the reverse_nested aggregation in order to "join back" to the root product and get the count of matching products for each for your variations.

{
  "aggs": {
    "Variations": {
      "nested": {
        "path": "variations"
      },
      "aggs": {
        "Colous": {
          "terms": {
            "field": "variations.colour"
          },
          "aggs": {
            "product_count": {            <--- add this reverse nested agg
              "reverse_nested": {}
            }
          }
        },
        "Sizes": {
          "terms": {
            "field": "variations.size"
          },
          "aggs": {
            "product_count": {            <--- add this reverse nested agg
              "reverse_nested": {}
            }
          }
        }
      }
    },
    "Brands": {
      "terms": {
        "field": "brand"
      }
    }
  },
  "query": {
    "match_all": {}
  }
}

In the response, you'll see that:

  • 2 products are matching colour: green
  • 1 product is matching colour: red
  • 2 products are matching size: medium
  • 1 product is matching size: small
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.