Link Search Menu Expand Document Documentation Menu

Weighted average aggregation

The weighted_avg aggregation computes a weighted average of numeric values extracted from documents. Unlike a regular average where each data point contributes equally, a weighted average assigns different importance to each data point based on a corresponding weight value.

The weighted average is calculated using the formula \(\frac{\sum_{i=1}^n \text{value}_i \cdot \text{weight}_i}{\sum_{i=1}^n \text{weight}_i}\).

In a regular average, every data point contributes equally, which is equivalent to assigning a weight of 1 to all values.

Parameters

The weighted_avg aggregation takes the following parameters.

Parameter Required/Optional Description
value Required Defines how to obtain the numeric values to average. Requires a field or script.
weight Required Defines how to obtain the weight for each value. Requires a field or script.
format Optional A DecimalFormat formatting string. Returns the formatted output in the aggregation’s value_as_string property.
value_type Optional A type hint for the values when using scripts or unmapped fields.

You can specify the following parameters within value or weight.

Parameter Required/Optional Description
field Optional The document field to use for the value or weight.
missing Optional A default value or weight to use when the field is missing. See Missing values.
script Optional A script that provides the value or weight. Mutually exclusive with field.

Example

First, create an index and add some data. Product C is missing the rating and num_reviews fields:

POST _bulk
{ "index": { "_index": "products" } }
{ "name": "Product A", "rating": 4.5, "num_reviews": 100 }
{ "index": { "_index": "products" } }
{ "name": "Product B", "rating": 3.8, "num_reviews": 50 }
{ "index": { "_index": "products" } }
{ "name": "Product C"}

The following request calculates a weighted average product rating, where each product’s rating is weighted by its num_reviews. Products with more reviews have a greater influence on the final average:

GET /products/_search
{
  "size": 0,
  "aggs": {
    "weighted_rating": {
      "weighted_avg": {
        "value": {
          "field": "rating"
        },
        "weight": {
          "field": "num_reviews"
        },
        "format": "#.##"
      }
    }
  }
}

Example response

The response contains the weighted_rating, calculated as (4.5 * 100 + 3.8 * 50) / (100 + 50) = 4.27. Only documents containing values for both rating and num_reviews are included in the calculation:

{
  "took": 21,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "weighted_rating": {
      "value": 4.266666650772095,
      "value_as_string": "4.27"
    }
  }
}

Multi-valued fields

The value field can contain multiple values per document, but the weight field must resolve to exactly one value. Documents with multiple weights cause an error. To handle multi-valued weight fields, use a script that reduces them to a single number.

When a document contains multiple values, the single weight is applied to each value independently. The following example indexes a document where rating is a multi-valued field and then runs the aggregation:

POST /products/_doc?refresh=true
{
  "name": "Product D",
  "rating": [1, 2, 3],
  "num_reviews": 2
}

GET /products/_search
{
  "size": 0,
  "query": {
    "term": { "name.keyword": "Product D" }
  },
  "aggs": {
    "weighted_rating": {
      "weighted_avg": {
        "value": {
          "field": "rating"
        },
        "weight": {
          "field": "num_reviews"
        }
      }
    }
  }
}

The three values (1, 2, and 3) are each weighted by 2, resulting in ((1*2) + (2*2) + (3*2)) / (2+2+2) = 2.0:

{
  ...
  "aggregations": {
    "weighted_rating": {
      "value": 2.0
    }
  }
}

Using a script

You can supply scripts for the value, the weight, or both to compute derived quantities on the fly. The following example adds 1 to each rating and weight before computing the weighted average:

GET /products/_search
{
  "size": 0,
  "aggs": {
    "weighted_rating": {
      "weighted_avg": {
        "value": {
          "script": "if (doc['rating'].size() == 0) return 0; return doc['rating'].value + 1"
        },
        "weight": {
          "script": "if (doc['num_reviews'].size() == 0) return 0; return doc['num_reviews'].value + 1"
        }
      }
    }
  }
}

Missing values

Documents missing the value field are excluded from the calculation by default. Documents missing the weight field are still included with an implicit weight of 1.

The missing parameter overrides these defaults by specifying a substitute value for documents that lack the field. The following example assigns a default rating of 3.0 and a default review count of 1 to documents missing those fields:

GET /products/_search
{
  "size": 0,
  "aggs": {
    "weighted_rating": {
      "weighted_avg": {
        "value": {
          "field": "rating",
          "missing": 3.0
        },
        "weight": {
          "field": "num_reviews",
          "missing": 1
        },
        "format": "#.##"
      }
    }
  }
}

With the missing values applied, the weighted average is calculated as (4.5 * 100 + 3.8 * 50 + 3.0 * 1) / (100 + 50 + 1) = 4.26:

{
  ...
  "aggregations": {
    "weighted_rating": {
      "value": 4.258278129906055,
      "value_as_string": "4.26"
    }
  }
}
350 characters left

Have a question? .

Want to contribute? or .