Оглавление курса
Теоретический курс · 5 / 6

Агрегации

Агрегации обобщают найденные документы. Bucket-агрегации создают группы, метрические — вычисляют значения. Используйте size: 0, когда нужны только статистики.

Разделов: 5Elasticsearch 9.4.3Ещё не прочитан

Чему вы научитесь

  • Различать страницы документов, buckets и метрики.
  • Считать документы и числовые показатели на нужном наборе.
  • Понимать глобальные фильтры и область вложенных агрегаций.

Агрегации отвечают на вопросы о группах совпавших документов. Bucket-агрегация формирует группы; метрическая вычисляет показатель внутри текущей группы. Верхнеуровневый query ограничивает набор для всех обычных агрегаций. size: 0 убирает документы из выдачи, но не отключает вычисление статистики.

Имена агрегаций задаёт автор запроса: они становятся ключами ответа. Используйте имена из условия, поскольку это часть контракта. Тренажёр поддерживает aggs и aggregations, но допускает не более трёх уровней агрегаций и бюджет 1000 buckets.

У каждой метрики свой набор
  • Совпадения query
    • Категория A
      • avg(price) внутри A
    • Категория B
      • avg(price) внутри B

Дочерняя метрика видит только документы родительского bucket. Параллельные соседи не фильтруют друг друга.

Примеры выполнены на публичном наборе products в Elasticsearch 9.4.3. Ответы — сокращённые фрагменты JSON: время, сведения о шардах и индексе опущены. Числовые оценки иллюстративны и могут меняться. Примеры объясняют способ решения; значения в заданиях могут отличаться.

01 / 05

Количество по брендам

terms-агрегация создаёт buckets для точных индексированных значений. Здесь группировка идёт по category вместо бренда. У каждого bucket есть key и doc_count. size внутри terms управляет числом buckets, а корневой size — числом документов. Это разные параметры с одинаковым именем.

Для групп по целому значению нужны keyword-поля: category или brand.keyword. По умолчанию terms предпочитает группы с большим счётчиком, разрешая равенство через ключ. На промышленном индексе с несколькими шардами возможны особенности точности top terms; здесь один primary shard, а size примеров достаточен для всех значений.

Разберём другой сценарий

POST /products/_search
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category",
        "size": 10
      }
    }
  }
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 300,
      "relation": "eq"
    },
    "hits": []
  },
  "aggregations": {
    "categories": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Accessories",
          "doc_count": 75
        },
        {
          "key": "Audio",
          "doc_count": 75
        },
        {
          "key": "Computers",
          "doc_count": 75
        },
        {
          "key": "Smartphones",
          "doc_count": 75
        }
      ]
    }
  }
}

Как читать результат

Документы не возвращаются. categories.buckets содержит ключи и счётчики набора, а hits.total по-прежнему показывает общее число совпавших документов.

Закрепить в задании 21
02 / 05

Средняя цена

avg вычисляет среднее индексированных числовых значений текущей области. Пример считает среднюю цену только для Audio благодаря верхнеуровневому query. В ответе метрики находится value, а не список товаров или счётчик группы. Без query показатель относился бы ко всему индексу.

Документы без поля метрики не добавляют значение в обычное среднее. Если числовых значений нет, value равен null, а не нулю. Десятичные результаты — числовые вычисления: несущественные различия floating-point не меняют смысл.

Разберём другой сценарий

POST /products/_search
{
  "size": 0,
  "query": {
    "term": {
      "category": "Audio"
    }
  },
  "aggs": {
    "audio_average": {
      "avg": {
        "field": "price"
      }
    }
  }
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 75,
      "relation": "eq"
    },
    "hits": []
  },
  "aggregations": {
    "audio_average": {
      "value": 859.4133333333333
    }
  }
}

Как читать результат

audio_average.value обобщает все совпавшие товары Audio, а не первую страницу. Имя метрики выбрано для этого примера.

Закрепить в задании 22
03 / 05

Границы цен

min и max — независимые метрические агрегации, поэтому располагаются соседями в aggs. Пример ограничивает набор Accessories и запрашивает обе границы цены. Метрика наследует текущую область: сосед не меняет набор документов другой метрики.

Это наблюдаемые значения, а не границы range-фильтра. Если query допускает цену ниже 800, максимальная фактическая цена может быть меньше 800. На пустом наборе метрики равны null: не заменяйте отсутствие значения выдуманным нулём.

Разберём другой сценарий

POST /products/_search
{
  "size": 0,
  "query": {
    "term": {
      "category": "Accessories"
    }
  },
  "aggs": {
    "lowest": {
      "min": {
        "field": "price"
      }
    },
    "highest": {
      "max": {
        "field": "price"
      }
    }
  }
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 75,
      "relation": "eq"
    },
    "hits": []
  },
  "aggregations": {
    "lowest": {
      "value": 99
    },
    "highest": {
      "value": 2499
    }
  }
}

Как читать результат

Оба value описывают один набор Accessories. Их можно получить без запроса и сортировки отдельных документов.

Закрепить в задании 23
04 / 05

Агрегация товаров в наличии

filter-агрегация создаёт один bucket документов, проходящих вложенный запрос. Ограничение наследуют только её дочерние агрегации. В примере hits.total по-прежнему учитывает все товары, но out_of_stock содержит недоступные и его среднее описывает только их.

Верхнеуровневый query ограничил бы все агрегации и поисковый результат. Выбирайте область по бизнес-вопросу: локальное сравнение требует filter-bucket, общее ограничение для всего — query. filter-bucket содержит doc_count, помогающий проверить набор метрики.

Разберём другой сценарий

POST /products/_search
{
  "size": 0,
  "aggs": {
    "out_of_stock": {
      "filter": {
        "term": {
          "in_stock": false
        }
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 300,
      "relation": "eq"
    },
    "hits": []
  },
  "aggregations": {
    "out_of_stock": {
      "doc_count": 100,
      "average_price": {
        "value": 724.3
      }
    }
  }
}

Как читать результат

Сравните hits.total.value и out_of_stock.doc_count. Они описывают разные наборы, потому что ограничение действует локально внутри агрегации.

Закрепить в задании 24
05 / 05

Метрики по брендам

Bucket может содержать дочерние aggs. Сгруппируйте категории и вычислите average_price для каждой. Получатся отдельные средние, а не один глобальный показатель рядом со всеми группами. Ответ повторяет дерево запроса: читайте его от родительского ключа к потомкам.

Вложенность агрегаций не равна nested query по полю с mapping nested. Товары содержат обычные скалярные поля: для дерева категория → метрика nested-mapping не нужен. Соблюдайте лимиты и оценивайте умножение числа buckets перед добавлением новой группировки.

Разберём другой сценарий

POST /products/_search
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category",
        "size": 10
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 300,
      "relation": "eq"
    },
    "hits": []
  },
  "aggregations": {
    "categories": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Accessories",
          "doc_count": 75,
          "average_price": {
            "value": 859.4
          }
        },
        {
          "key": "Audio",
          "doc_count": 75,
          "average_price": {
            "value": 859.4133333333333
          }
        },
        {
          "key": "Computers",
          "doc_count": 75,
          "average_price": {
            "value": 589.2
          }
        },
        {
          "key": "Smartphones",
          "doc_count": 75,
          "average_price": {
            "value": 589.88
          }
        }
      ]
    }
  }
}

Как читать результат

Каждый bucket категории содержит собственный average_price.value. Положение метрики внутри bucket указывает, какой набор она описывает.

Закрепить в задании 25

Краткая памятка

  • Корневой size управляет документами; terms.size — группами.
  • Для групп по значениям используйте keyword, для числовых метрик — числа.
  • query ограничивает все обычные агрегации; filter-агрегация — своих потомков.
  • Метрика должна быть внутри bucket, документы которого описывает.
  • Пустая числовая метрика равна null, а не нулю.

Официальная документация

Готовы применить знания?

Подтвердите прочтение, чтобы сохранить своё место. Чтение и решение заданий учитываются отдельно в этом браузере с помощью гостевой cookie.