Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Агрегации ›Метрические агрегации

Агрегация weighted avg

Метрическая агрегация single-value, вычисляющая взвешенное среднее значение числовых значений, извлеченных из агрегированных документов. Эти значения могут быть извлечены из конкретных числовых полей в документах.

При вычислении обычного среднего значения каждый элемент данных имеет равный «вес» … он одинаково вносит вклад в конечное значение. Взвешенные средние значения, с другой стороны, весят каждый элемент данных по-разному. Величина вклада каждого элемента данных в конечное значение извлекается из документа.

Формула взвешенного среднего значения выглядит следующим образом: ∑(value * weight) / ∑(weight)

Обычное среднее можно рассматривать как взвешенное среднее, где каждое значение имеет неявный вес 1.

Таблица 53. weighted_avg Параметры

Имя параметра Описание Обязательно Значение по умолчанию

value

Настройка для поля или скрипта, предоставляющего значения

Обязательно

weight

Настройка для поля или скрипта, предоставляющего веса

Обязательно

format

Формат представления числового результата

Необязательно

Объекты value и weight имеют специфическую конфигурацию для каждого поля:

Таблица 54. value Параметры

Имя параметра Описание Обязательно Значение по умолчанию

field

Поле, из которого следует извлечь значения

Обязательно

missing

Значение, используемое, если поле отсутствует полностью

Необязательно

Таблица 55. weight Параметры

Имя параметра Описание Обязательно Значение по умолчанию

field

Поле, из которого следует извлечь веса

Обязательно

missing

Вес, используемый, если поле отсутствует полностью

Необязательно

Примеры

Если наши документы содержат поле "grade", хранящее числовой рейтинг от 0 до 100, и поле "weight", содержащее произвольный числовой вес, мы можем рассчитать взвешенное среднее значение с помощью:

resp = client.search(
    index="exams",
    size=0,
    aggs={
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade"
                },
                "weight": {
                    "field": "weight"
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'exams',
  body: {
    size: 0,
    aggregations: {
      weighted_grade: {
        weighted_avg: {
          value: {
            field: 'grade'
          },
          weight: {
            field: 'weight'
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "exams",
  size: 0,
  aggs: {
    weighted_grade: {
      weighted_avg: {
        value: {
          field: "grade",
        },
        weight: {
          field: "weight",
        },
      },
    },
  },
});
console.log(response);
POST /exams/_search
{
  "size": 0,
  "aggs": {
    "weighted_grade": {
      "weighted_avg": {
        "value": {
          "field": "grade"
        },
        "weight": {
          "field": "weight"
        }
      }
    }
  }
}

Что дает ответ, похожий на:

{
  ...
  "aggregations": {
    "weighted_grade": {
      "value": 70.0
    }
  }
}

Хотя разрешены несколько значений на поле, разрешен только один вес. Если агрегация обнаруживает документ, содержащий более одного веса (например, поле веса является многозначным полем), она прервет поиск. В этой ситуации вы должны создать вычислительное поле для объединения этих значений в один вес.

Этот единственный вес будет применяться независимо к каждому значению, извлеченному из поля value.

Этот пример демонстрирует, как среднее арифметическое одного документа с несколькими значениями будет вычислено с одним весом:

resp = client.index(
    index="exams",
    refresh=True,
    document={
        "grade": [
            1,
            2,
            3
        ],
        "weight": 2
    },
)
print(resp)

resp1 = client.search(
    index="exams",
    size=0,
    aggs={
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade"
                },
                "weight": {
                    "field": "weight"
                }
            }
        }
    },
)
print(resp1)
response = client.index(
  index: 'exams',
  refresh: true,
  body: {
    grade: [
      1,
      2,
      3
    ],
    weight: 2
  }
)
puts response

response = client.search(
  index: 'exams',
  body: {
    size: 0,
    aggregations: {
      weighted_grade: {
        weighted_avg: {
          value: {
            field: 'grade'
          },
          weight: {
            field: 'weight'
          }
        }
      }
    }
  }
)
puts response
const response = await client.index({
  index: "exams",
  refresh: "true",
  document: {
    grade: [1, 2, 3],
    weight: 2,
  },
});
console.log(response);

const response1 = await client.search({
  index: "exams",
  size: 0,
  aggs: {
    weighted_grade: {
      weighted_avg: {
        value: {
          field: "grade",
        },
        weight: {
          field: "weight",
        },
      },
    },
  },
});
console.log(response1);
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"
        }
      }
    }
  }
}

Три значения (1, 2 и 3) будут включены как независимые значения, все с весом 2:

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

Агрегация возвращает 2.0 в качестве результата, что соответствует ожидаемому результату при ручном расчете: ((1*2) + (2*2) + (3*2)) / (2+2+2) == 2

Вычислительное поле

Если вам необходимо суммировать или взвешивать значения, которые не совсем соответствуют индексированным значениям, выполните агрегацию на вычислительном поле.

resp = client.index(
    index="exams",
    refresh=True,
    document={
        "grade": 100,
        "weight": [
            2,
            3
        ]
    },
)
print(resp)

resp1 = client.index(
    index="exams",
    refresh=True,
    document={
        "grade": 80,
        "weight": 3
    },
)
print(resp1)

resp2 = client.search(
    index="exams",
    filter_path="aggregations",
    size=0,
    runtime_mappings={
        "weight.combined": {
            "type": "double",
            "script": "\n        double s = 0;\n        for (double w : doc['weight']) {\n          s += w;\n        }\n        emit(s);\n      "
        }
    },
    aggs={
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "script": "doc.grade.value + 1"
                },
                "weight": {
                    "field": "weight.combined"
                }
            }
        }
    },
)
print(resp2)
response = client.index(
  index: 'exams',
  refresh: true,
  body: {
    grade: 100,
    weight: [
      2,
      3
    ]
  }
)
puts response

response = client.index(
  index: 'exams',
  refresh: true,
  body: {
    grade: 80,
    weight: 3
  }
)
puts response

response = client.search(
  index: 'exams',
  filter_path: 'aggregations',
  body: {
    size: 0,
    runtime_mappings: {
      'weight.combined' => {
        type: 'double',
        script: "\n        double s = 0;\n        for (double w : doc['weight']) {\n          s += w;\n        }\n        emit(s);\n      "
      }
    },
    aggregations: {
      weighted_grade: {
        weighted_avg: {
          value: {
            script: 'doc.grade.value + 1'
          },
          weight: {
            field: 'weight.combined'
          }
        }
      }
    }
  }
)
puts response
const response = await client.index({
  index: "exams",
  refresh: "true",
  document: {
    grade: 100,
    weight: [2, 3],
  },
});
console.log(response);

const response1 = await client.index({
  index: "exams",
  refresh: "true",
  document: {
    grade: 80,
    weight: 3,
  },
});
console.log(response1);

const response2 = await client.search({
  index: "exams",
  filter_path: "aggregations",
  size: 0,
  runtime_mappings: {
    "weight.combined": {
      type: "double",
      script:
        "\n        double s = 0;\n        for (double w : doc['weight']) {\n          s += w;\n        }\n        emit(s);\n      ",
    },
  },
  aggs: {
    weighted_grade: {
      weighted_avg: {
        value: {
          script: "doc.grade.value + 1",
        },
        weight: {
          field: "weight.combined",
        },
      },
    },
  },
});
console.log(response2);
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"
        }
      }
    }
  }
}

Что должно выглядеть так:

{
  "aggregations": {
    "weighted_grade": {
      "value": 93.5
    }
  }
}

Отсутствующие значения

По умолчанию агрегация исключает документы с отсутствующим или null значением для поля value или weight. Используйте параметр missing, чтобы указать значение по умолчанию для этих документов вместо этого.

resp = client.search(
    index="exams",
    size=0,
    aggs={
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade",
                    "missing": 2
                },
                "weight": {
                    "field": "weight",
                    "missing": 3
                }
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "exams",
  size: 0,
  aggs: {
    weighted_grade: {
      weighted_avg: {
        value: {
          field: "grade",
          missing: 2,
        },
        weight: {
          field: "weight",
          missing: 3,
        },
      },
    },
  },
});
console.log(response);
POST /exams/_search
{
  "size": 0,
  "aggs": {
    "weighted_grade": {
      "weighted_avg": {
        "value": {
          "field": "grade",
          "missing": 2
        },
        "weight": {
          "field": "weight",
          "missing": 3
        }
      }
    }
  }
}

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-aggregations-metrics-weight-avg-aggregation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API