elasticsearchelasticsearch-aggregationelasticsearch-nested

How to compare parent field value with aggregated values from nested objects in Elasticsearch?


I have such documents in my index:

  {
    "Pieces": 5,
    "parts": [
      {
        "Quantity": 1,
        "PartID": 1,
      },
      {
        "Quantity": 1,
        "PartID": 2
      },
      {
        "Quantity": 1,
        "PartID": 3
      },
      {
        "Quantity": 1,
        "PartID": 4
      }
    ]
  }

I would like to prepare query which lists all docs where Pieces value does not equal to the sum of Quantity in all parts. I have something like that:

GET /_search
{
  "size": 0,
  "aggs": {
    "group_by_id": {
      "terms": {
        "field": "_id",
        "size": 1000000000
      },
      "aggs": {
        "sum_of_parts": {
          "nested": {
            "path": "parts"
          },
          "aggs": {
            "sum_of_quantity": {
              "sum": {
                "field": "parts.Quantity"
              }
            }
          }
        },
        "sum_of_parts_vs_pieces": {
          "bucket_selector": {
            "buckets_path": {
              "sumOfPart": "sum_of_parts>sum_of_quantity"
            },
            "script": "params.sumOfPart != HOW_TO_PUT_Pieces_VALUE_HERE???"
          }
        }
      }
    }
  }
}

which almost works (counts the sum of Quantity for all parts) ... but... I have no idea how to pass Pieces value to the bucket_selector.

Do you have any idea how to do this? Or maybe you have an idea of how to accomplish this task in another way?


Solution

  • You can do it like this, by adding the average of the Pieces field (going back up one level using reverse_nested):

    GET pieces/_search
    {
      "size": 0,
      "aggs": {
        "group_by_id": {
          "terms": {
            "field": "_id",
            "size": 1000000000
          },
          "aggs": {
            "sum_of_parts": {
              "nested": {
                "path": "parts"
              },
              "aggs": {
                "avg_of_pieces": {
                  "reverse_nested": {},
                  "aggs": {
                    "avg_of_pieces": {
                      "avg": {
                        "field": "Pieces"
                      }
                    }
                  }
                },
                "sum_of_quantity": {
                  "sum": {
                    "field": "parts.Quantity"
                  }
                }
              }
            },
            "sum_of_parts_vs_pieces": {
              "bucket_selector": {
                "buckets_path": {
                  "sumOfPart": "sum_of_parts>sum_of_quantity",
                  "nbPieces": "sum_of_parts>avg_of_pieces>avg_of_pieces"
                },
                "script": "params.sumOfPart != params.nbPieces"
              }
            }
          }
        }
      }
    }