Агрегирование метрик на основе скриптов
Метрическое агрегирование, которое выполняется с помощью скриптов для вычисления метрики.
Использование скриптов может привести к замедлению скорости поиска. См. Скрипты, кэширование и скорость поиска.
Пример:
POST ledger/_search?size=0
{
"query": {
"match_all": {}
},
"aggs": {
"profit": {
"scripted_metric": {
"init_script": "state.transactions = []",
"map_script": "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
"combine_script": "double profit = 0; for (t in state.transactions) { profit += t } return profit",
"reduce_script": "double profit = 0; for (a in states) { profit += a } return profit"
}
}
}
} |
|
Приведённое выше агрегирование демонстрирует, как с помощью агрегирования на основе скриптов вычислить общую прибыль от транзакций продаж и затрат.
Результат выполнения вышеуказанного агрегирования:
{
"took": 218,
...
"aggregations": {
"profit": {
"value": 240.0
}
}
} Приведенный выше пример также может быть задан с использованием хранимых скриптов следующим образом:
POST ledger/_search?size=0
{
"aggs": {
"profit": {
"scripted_metric": {
"init_script": {
"id": "my_init_script"
},
"map_script": {
"id": "my_map_script"
},
"combine_script": {
"id": "my_combine_script"
},
"params": {
"field": "amount"
},
"reduce_script": {
"id": "my_reduce_script"
}
}
}
}
} | Параметры скрипта для |
Дополнительные сведения о спецификации скриптов см. в документации по скриптам.
Допустимые типы возвращаемых значений
Несмотря на то, что в одном скрипте можно использовать любой допустимый скриптовый объект, скрипты должны возвращать или хранить в объекте state только следующие типы:
- примитивные типы
- Строка
- Карта (содержащая только ключи и значения перечисленных здесь типов)
- Массив (содержащий элементы только перечисленных здесь типов)
Область действия скриптов
Агрегирование метрик на основе скриптов использует скрипты на 4 этапах выполнения:
- init_script
-
Выполняется до сбора любых документов. Позволяет агрегации установить начальное состояние.
В приведенном выше примере
init_scriptсоздает массивtransactionsв объектеstate. - map_script
-
Выполняется один раз на каждый собранный документ. Это обязательный скрипт. Если не указан combine_script, результат необходимо сохранить в объекте
state.В приведенном выше примере,
map_scriptпроверяет значение поля type. Если значение равно sale, значение поля amount добавляется в массив transactions. Если значение поля type не равно sale, отрицательное значение поля amount добавляется в transactions. - combine_script
-
Выполняется один раз на каждом фрагменте после завершения сбора документов. Это обязательный скрипт. Позволяет агрегации объединить состояние, возвращенное из каждого фрагмента.
В приведенном выше примере,
combine_scriptперебирает все сохраненные транзакции, суммирует значения в переменнойprofitи, наконец, возвращаетprofit. - reduce_script
-
Выполняется один раз на узле координации после того, как все фрагменты вернули свои результаты. Это обязательный скрипт. Скрипт имеет доступ к переменной
states, которая является массивом результатов combine_script на каждом фрагменте.В приведенном выше примере,
reduce_scriptперебирает массивprofit, возвращаемый каждым фрагментом, суммирует значения, прежде чем вернуть окончательную комбинированную прибыль, которая будет возвращена в ответе на агрегирование.
Пример работы
Представьте себе ситуацию, когда вы индексируете следующие документы в индекс с 2 фрагментами:
PUT /transactions/_bulk?refresh
{"index":{"_id":1}}
{"type": "sale","amount": 80}
{"index":{"_id":2}}
{"type": "cost","amount": 10}
{"index":{"_id":3}}
{"type": "cost","amount": 30}
{"index":{"_id":4}}
{"type": "sale","amount": 130} Допустим, что документы 1 и 3 попадают на фрагмент A, а документы 2 и 4 — на фрагмент B. Ниже приведён разбор результата агрегирования на каждом этапе приведенного выше примера.
До выполнения init_script
state инициализируется как новый пустой объект.
"state" : {} После выполнения init_script
Этот скрипт выполняется один раз на каждом фрагменте перед началом сбора документов, и поэтому у нас будет копия на каждом фрагменте:
- Фрагмент A
-
"state" : { "transactions" : [] } - Фрагмент B
-
"state" : { "transactions" : [] }
После выполнения map_script
Каждый фрагмент собирает свои документы и выполняет map_script для каждого собранного документа:
- Фрагмент A
-
"state" : { "transactions" : [ 80, -30 ] } - Фрагмент B
-
"state" : { "transactions" : [ -10, 130 ] }
После выполнения combine_script
combine_script выполняется на каждом фрагменте после сбора документов и уменьшает все транзакции до одной общей прибыли для каждого фрагмента (суммируя значения в массиве transactions), которая передаётся узлу координации:
- Фрагмент A
- 50
- Фрагмент B
- 120
После выполнения reduce_script
reduce_script получает массив states, содержащий результат combine_script для каждого фрагмента:
"states" : [
50,
120
] Он сводит ответы фрагментов до одной итоговой прибыли (суммируя значения) и возвращает это значение как результат агрегирования, чтобы получить ответ:
{
...
"aggregations": {
"profit": {
"value": 170
}
}
} Другие параметры
| params |
Необязательный. Объект, содержимое которого будет передано как переменные в "params" : {} |
Пустые корзины
Если родительская корзина агрегирования метрик на основе скриптов не собирает никаких документов, из фрагмента возвращается пустой ответ агрегирования с значением null. В этом случае переменная reduce_script's states будет содержать null в качестве ответа от этого фрагмента. reduce_script должны ожидать и обрабатывать ответы null от фрагментов.
© 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/7.17/search-aggregations-metrics-scripted-metric-aggregation.html