elasticsearch/docs/reference/aggregations/metrics/weighted-avg-aggregation.asciidoc
Nik Everett 6a1220e7f3
Convert metric aggs docs runtime fields (#71260)
This replaces the `script` docs for bucket aggregations with runtime
fields. We expect runtime fields to be nicer to work with because you
can also fetch them or filter on them. We expect them to be faster
because their don't need this sort of `instanceof` tree:
a92a647b9f/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptDoubleValues.java (L42)

Relates to #69291

Co-authored-by: James Rodewig <40268737+jrodewig@users.noreply.github.com>
Co-authored-by: Adam Locke <adam.locke@elastic.co>
2021-04-05 13:08:13 -04:00

239 lines
6.1 KiB
Text

[[search-aggregations-metrics-weight-avg-aggregation]]
=== Weighted avg aggregation
++++
<titleabbrev>Weighted avg</titleabbrev>
++++
A `single-value` metrics aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.
These values can be extracted either from specific numeric fields in the documents.
When calculating a regular average, each datapoint has an equal "weight" ... it contributes equally to the final value. Weighted averages,
on the other hand, weight each datapoint differently. The amount that each datapoint contributes to the final value is extracted from the
document.
As a formula, a weighted average is the `∑(value * weight) / ∑(weight)`
A regular average can be thought of as a weighted average where every value has an implicit weight of `1`.
[[weighted-avg-params]]
.`weighted_avg` Parameters
[options="header"]
|===
|Parameter Name |Description |Required |Default Value
|`value` | The configuration for the field or script that provides the values |Required |
|`weight` | The configuration for the field or script that provides the weights |Required |
|`format` | The numeric response formatter |Optional |
|===
The `value` and `weight` objects have per-field specific configuration:
[[value-params]]
.`value` Parameters
[options="header"]
|===
|Parameter Name |Description |Required |Default Value
|`field` | The field that values should be extracted from |Required |
|`missing` | A value to use if the field is missing entirely |Optional |
|===
[[weight-params]]
.`weight` Parameters
[options="header"]
|===
|Parameter Name |Description |Required |Default Value
|`field` | The field that weights should be extracted from |Required |
|`missing` | A weight to use if the field is missing entirely |Optional |
|===
==== Examples
If our documents have a `"grade"` field that holds a 0-100 numeric score, and a `"weight"` field which holds an arbitrary numeric weight,
we can calculate the weighted average using:
[source,console]
--------------------------------------------------
POST /exams/_search
{
"size": 0,
"aggs": {
"weighted_grade": {
"weighted_avg": {
"value": {
"field": "grade"
},
"weight": {
"field": "weight"
}
}
}
}
}
--------------------------------------------------
// TEST[setup:exams]
Which yields a response like:
[source,console-result]
--------------------------------------------------
{
...
"aggregations": {
"weighted_grade": {
"value": 70.0
}
}
}
--------------------------------------------------
// TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
While multiple values-per-field are allowed, only one weight is allowed. If the aggregation encounters
a document that has more than one weight (e.g. the weight field is a multi-valued field) it will abort the search.
If you have this situation, you should build a <<search-aggregations-metrics-weight-avg-aggregation-runtime-field>>
to combine those values into a single weight.
This single weight will be applied independently to each value extracted from the `value` field.
This example show how a single document with multiple values will be averaged with a single weight:
[source,console]
--------------------------------------------------
POST /exams/_doc?refresh
{
"grade": [1, 2, 3],
"weight": 2
}
POST /exams/_search
{
"size": 0,
"aggs": {
"weighted_grade": {
"weighted_avg": {
"value": {
"field": "grade"
},
"weight": {
"field": "weight"
}
}
}
}
}
--------------------------------------------------
// TEST
The three values (`1`, `2`, and `3`) will be included as independent values, all with the weight of `2`:
[source,console-result]
--------------------------------------------------
{
...
"aggregations": {
"weighted_grade": {
"value": 2.0
}
}
}
--------------------------------------------------
// TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
The aggregation returns `2.0` as the result, which matches what we would expect when calculating by hand:
`((1*2) + (2*2) + (3*2)) / (2+2+2) == 2`
[[search-aggregations-metrics-weight-avg-aggregation-runtime-field]]
==== Runtime field
If you have to sum or weigh values that don't quite line up with the indexed
values, run the aggregation on a <<runtime,runtime field>>.
[source,console]
----
POST /exams/_doc?refresh
{
"grade": 100,
"weight": [2, 3]
}
POST /exams/_doc?refresh
{
"grade": 80,
"weight": 3
}
POST /exams/_search?filter_path=aggregations
{
"size": 0,
"runtime_mappings": {
"weight.combined": {
"type": "double",
"script": """
double s = 0;
for (double w : doc['weight']) {
s += w;
}
emit(s);
"""
}
},
"aggs": {
"weighted_grade": {
"weighted_avg": {
"value": {
"script": "doc.grade.value + 1"
},
"weight": {
"field": "weight.combined"
}
}
}
}
}
----
Which should look like:
[source,console-result]
----
{
"aggregations": {
"weighted_grade": {
"value": 93.5
}
}
}
----
==== Missing values
The `missing` parameter defines how documents that are missing a value should be treated.
The default behavior is different for `value` and `weight`:
By default, if the `value` field is missing the document is ignored and the aggregation moves on to the next document.
If the `weight` field is missing, it is assumed to have a weight of `1` (like a normal average).
Both of these defaults can be overridden with the `missing` parameter:
[source,console]
--------------------------------------------------
POST /exams/_search
{
"size": 0,
"aggs": {
"weighted_grade": {
"weighted_avg": {
"value": {
"field": "grade",
"missing": 2
},
"weight": {
"field": "weight",
"missing": 3
}
}
}
}
}
--------------------------------------------------
// TEST[setup:exams]