Агрегирование Multi Terms
Агрегирование на основе источника значений для нескольких корзин, где корзины создаются динамически — по одному на каждый набор уникальных значений. Агрегирование multi terms очень похоже на terms aggregation, однако в большинстве случаев оно будет медленнее, чем агрегирование terms, и потребует больше памяти. Поэтому, если один и тот же набор полей постоянно используется, будет эффективнее индексировать объединенный ключ для этих полей как отдельное поле и использовать агрегирование terms для этого поля.
Агрегирование multi_term наиболее полезно, когда требуется сортировка по количеству документов или метрическому агрегированию по составному ключу и получению N лучших результатов. Если сортировка не требуется и все значения ожидают получения с помощью вложенного агрегирования terms или composite aggregations, будет более быстрым и эффективным решением с точки зрения памяти.
Пример:
resp = client.search(
index="products",
aggs={
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre"
},
{
"field": "product"
}
]
}
}
},
)
print(resp) response = client.search(
index: 'products',
body: {
aggregations: {
genres_and_products: {
multi_terms: {
terms: [
{
field: 'genre'
},
{
field: 'product'
}
]
}
}
}
}
)
puts response const response = await client.search({
index: "products",
aggs: {
genres_and_products: {
multi_terms: {
terms: [
{
field: "genre",
},
{
field: "product",
},
],
},
},
},
});
console.log(response); GET /products/_search
{
"aggs": {
"genres_and_products": {
"multi_terms": {
"terms": [{
"field": "genre"
}, {
"field": "product"
}]
}
}
}
} | Агрегирование |
Ответ:
{
...
"aggregations" : {
"genres_and_products" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : [
"rock",
"Product A"
],
"key_as_string" : "rock|Product A",
"doc_count" : 2
},
{
"key" : [
"electronic",
"Product B"
],
"key_as_string" : "electronic|Product B",
"doc_count" : 1
},
{
"key" : [
"jazz",
"Product B"
],
"key_as_string" : "jazz|Product B",
"doc_count" : 1
},
{
"key" : [
"rock",
"Product B"
],
"key_as_string" : "rock|Product B",
"doc_count" : 1
}
]
}
}
} | верхняя граница ошибки в подсчете документов для каждого термина, см. <<search-aggregations-bucket-multi-terms-aggregation-approximate-counts,ниже> | |
| если есть много уникальных терминов, Elasticsearch возвращает только лучшие термины; это число равно сумме подсчетов документов для всех корзин, которые не входят в ответ | |
| список лучших корзин. | |
| ключи — массивы значений, отсортированные так же, как выражение в параметре |
По умолчанию агрегирование multi_terms вернет корзины для десяти лучших терминов, отсортированные по doc_count. Это поведение можно изменить, установив параметр size.
Параметры агрегирования
Поддерживаются следующие параметры. Подробнее см. terms aggregation.
| size | Необязательно. Определяет количество корзин с терминами, которые должны быть возвращены из общего списка терминов. По умолчанию 10. |
| shard_size | Необязательно. Чем выше значение запрашиваемого |
| show_term_doc_count_error | Необязательно. Вычисляет ошибку количества документов для каждого термина. По умолчанию |
| order | Необязательно. Указывает порядок корзин. По умолчанию — количество документов на корзину. Значение термина корзины используется в качестве разрыва для корзин с одинаковым количеством документов. |
| min_doc_count | Необязательно. Минимальное количество документов в корзине для ее возврата. По умолчанию 1. |
| shard_min_doc_count | Необязательно. Минимальное количество документов в корзине на каждом фрагменте для ее возврата. По умолчанию |
| collect_mode | Необязательно. Указывает стратегию сбора данных. Поддерживаются режимы |
Скрипт
Генерация терминов с помощью скрипта:
resp = client.search(
index="products",
runtime_mappings={
"genre.length": {
"type": "long",
"script": "emit(doc['genre'].value.length())"
}
},
aggs={
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre.length"
},
{
"field": "product"
}
]
}
}
},
)
print(resp) response = client.search(
index: 'products',
body: {
runtime_mappings: {
'genre.length' => {
type: 'long',
script: "emit(doc['genre'].value.length())"
}
},
aggregations: {
genres_and_products: {
multi_terms: {
terms: [
{
field: 'genre.length'
},
{
field: 'product'
}
]
}
}
}
}
)
puts response const response = await client.search({
index: "products",
runtime_mappings: {
"genre.length": {
type: "long",
script: "emit(doc['genre'].value.length())",
},
},
aggs: {
genres_and_products: {
multi_terms: {
terms: [
{
field: "genre.length",
},
{
field: "product",
},
],
},
},
},
});
console.log(response); GET /products/_search
{
"runtime_mappings": {
"genre.length": {
"type": "long",
"script": "emit(doc['genre'].value.length())"
}
},
"aggs": {
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre.length"
},
{
"field": "product"
}
]
}
}
}
} Ответ:
{
...
"aggregations" : {
"genres_and_products" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : [
4,
"Product A"
],
"key_as_string" : "4|Product A",
"doc_count" : 2
},
{
"key" : [
4,
"Product B"
],
"key_as_string" : "4|Product B",
"doc_count" : 2
},
{
"key" : [
10,
"Product B"
],
"key_as_string" : "10|Product B",
"doc_count" : 1
}
]
}
}
} Пропущенное значение
Параметр missing определяет, как следует обрабатывать документы, у которых отсутствует значение. По умолчанию, если любой из компонентов ключа отсутствует, весь документ игнорируется, но также возможно рассматривать их как имеющие значение, используя параметр missing.
resp = client.search(
index="products",
aggs={
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre"
},
{
"field": "product",
"missing": "Product Z"
}
]
}
}
},
)
print(resp) response = client.search(
index: 'products',
body: {
aggregations: {
genres_and_products: {
multi_terms: {
terms: [
{
field: 'genre'
},
{
field: 'product',
missing: 'Product Z'
}
]
}
}
}
}
)
puts response const response = await client.search({
index: "products",
aggs: {
genres_and_products: {
multi_terms: {
terms: [
{
field: "genre",
},
{
field: "product",
missing: "Product Z",
},
],
},
},
},
});
console.log(response); GET /products/_search
{
"aggs": {
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre"
},
{
"field": "product",
"missing": "Product Z"
}
]
}
}
}
} Ответ:
{
...
"aggregations" : {
"genres_and_products" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : [
"rock",
"Product A"
],
"key_as_string" : "rock|Product A",
"doc_count" : 2
},
{
"key" : [
"electronic",
"Product B"
],
"key_as_string" : "electronic|Product B",
"doc_count" : 1
},
{
"key" : [
"electronic",
"Product Z"
],
"key_as_string" : "electronic|Product Z",
"doc_count" : 1
},
{
"key" : [
"jazz",
"Product B"
],
"key_as_string" : "jazz|Product B",
"doc_count" : 1
},
{
"key" : [
"rock",
"Product B"
],
"key_as_string" : "rock|Product B",
"doc_count" : 1
}
]
}
}
} | Документы без значения в поле |
Смешивание типов полей
При агрегировании по нескольким индексам тип агрегированного поля может отличаться в разных индексах. Некоторые типы совместимы друг с другом (integer и long или float и double), но когда типы смешаны (десятичные и не десятичные числа), агрегирование terms преобразует не десятичные числа в десятичные. Это может привести к потере точности значений в корзинах.
Примеры вложенных агрегаций и сортировки
Как и большинство агрегаций по корзинам, multi_term поддерживает вложенные агрегации и сортировку корзин по метрическим вложенным агрегациям:
resp = client.search(
index="products",
aggs={
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre"
},
{
"field": "product"
}
],
"order": {
"total_quantity": "desc"
}
},
"aggs": {
"total_quantity": {
"sum": {
"field": "quantity"
}
}
}
}
},
)
print(resp) response = client.search(
index: 'products',
body: {
aggregations: {
genres_and_products: {
multi_terms: {
terms: [
{
field: 'genre'
},
{
field: 'product'
}
],
order: {
total_quantity: 'desc'
}
},
aggregations: {
total_quantity: {
sum: {
field: 'quantity'
}
}
}
}
}
}
)
puts response const response = await client.search({
index: "products",
aggs: {
genres_and_products: {
multi_terms: {
terms: [
{
field: "genre",
},
{
field: "product",
},
],
order: {
total_quantity: "desc",
},
},
aggs: {
total_quantity: {
sum: {
field: "quantity",
},
},
},
},
},
});
console.log(response); GET /products/_search
{
"aggs": {
"genres_and_products": {
"multi_terms": {
"terms": [
{
"field": "genre"
},
{
"field": "product"
}
],
"order": {
"total_quantity": "desc"
}
},
"aggs": {
"total_quantity": {
"sum": {
"field": "quantity"
}
}
}
}
}
} {
...
"aggregations" : {
"genres_and_products" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : [
"jazz",
"Product B"
],
"key_as_string" : "jazz|Product B",
"doc_count" : 1,
"total_quantity" : {
"value" : 10.0
}
},
{
"key" : [
"rock",
"Product A"
],
"key_as_string" : "rock|Product A",
"doc_count" : 2,
"total_quantity" : {
"value" : 9.0
}
},
{
"key" : [
"electronic",
"Product B"
],
"key_as_string" : "electronic|Product B",
"doc_count" : 1,
"total_quantity" : {
"value" : 3.0
}
},
{
"key" : [
"rock",
"Product B"
],
"key_as_string" : "rock|Product B",
"doc_count" : 1,
"total_quantity" : {
"value" : 1.0
}
}
]
}
}
}
© 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-bucket-multi-terms-aggregation.html