Агрегация результатов поискаCompatible with Milvus 3.0.x

Когда покупатель ищет «черные кроссовки для ежедневных тренировок», поиск по методу ближайшего соседа (ANN) ранжирует товары по сходству векторов и возвращает плоский список Top-K. Результаты могут быть релевантными, но повторяющимися: в приведенном ниже примере четыре из первых шести результатов — товары бренда A, а бренды B и C появляются по одному разу.

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

Агрегация результатов поиска группирует отобранные кандидаты ANN в сегменты на основе выбранных скалярных полей. В данном примере каждый бренд становится отдельным сегментом. Milvus может рассчитывать статистику для каждого сегмента, упорядочивать сегменты и привязывать к ним репрезентативные продукты. Приложение получает этот ответ, ориентированный на сегменты, через интерфейс « result.agg_buckets ».

A flat running-shoe search result becomes a set of comparable brand buckets Плоский набор результатов поиска кроссовок превращается в набор сопоставимых групп по брендам

Агрегация результатов поиска не выполняет точную агрегацию по всей коллекции. Наличие корзин, количество элементов, метрики, порядок и репрезентативные результаты зависят от кандидатов, отобранных на этапах ANN и группировки.

Как это работает

ANN candidates grouped by bucket keys and returned with counts, metrics, and representative hits Кандидаты ANN, сгруппированные по ключам сегментов и возвращаемые с подсчётами, метриками и репрезентативными результатами

  1. Извлечение кандидатов. Milvus запускает поиск с помощью ANN, чтобы найти сущности, наиболее близкие к вектору запроса. Затем на этапе группировки сохраняется ограниченное количество кандидатов для каждого полного составного ключа. Этот лимит кандидатов на ключ равен наибольшему значению TopHits.size в любом месте дерева агрегации или 1, если ни на одном уровне не задано значение top_hits.

  2. Построение корзин. SearchAggregation.fields определяет ключ корзины. Каждая уникальная комбинация значений полей создаёт отдельный ключ. На рисунке fields=["brand"] создаёт ключи корзин (Brand A), (Brand B) и (Brand C). Сохраненные кандидаты с одинаковым ключом относятся к одной корзине и вносят вклад в её count. SearchAggregation.size ограничивает количество корзин, возвращаемых Milvus.

  3. Вычисление и возвращение результатов. Каждый возвращаемый бакет содержит свой ключ и количество сохраненных кандидатов. Milvus также может вычислять настроенные метрики, упорядочивать бакеты, возвращать репрезентативные сущности и создавать дочерние бакеты. Каждый AggregationBucket в result.agg_buckets предоставляет key, count, metrics, hits и sub_groups. Когда включена агрегация поиска, обычный список результатов поиска пуст.

На диаграмме TopHits.size=4 предоставляет бюджет кандидатов в размере четырех на каждый ключ, поэтому четыре сохраненных кандидата бренда A формируют count: 4. На готовой карте бренда A показаны только два из четырех возвращенных репрезентативных результатов, чтобы рисунок оставался компактным.

При использовании « sub_aggregation » Milvus повторяет шаги 2 и 3 внутри каждого родительского сегмента. Изменения в коэффициенте воспроизведения ANN или бюджете кандидатов на ключ могут повлиять на количество сегментов, метрики, порядок, результаты поиска и вложенные результаты.

Ограничения

Перед использованием агрегации поиска обратите внимание на следующие ограничения:

  • Вложенные агрегации: запрос может содержать одну корневую агрегацию « SearchAggregation » и до трёх вложенных уровней « sub_aggregation », что в сумме даёт не более четырёх уровней. На всех уровнях для создания ключей корзин можно использовать не более 10 полей.

  • Поля, используемые для создания ключей корзины: « SearchAggregation.fields » поддерживает поля типа «Boolean», «integer», « VARCHAR » и « TIMESTAMPTZ ». Не поддерживаются поля типа « FLOAT », « DOUBLE », « ARRAY », « JSON », « GEOMETRY », « TEXT », а также векторные и динамические поля.

  • Поля метрики: count принимает "*" или любое не-JSON, нединамическое поле и пропускает значения NULL, если указано поле. sum и avg принимают целочисленные и поля с плавающей запятой. min и max дополнительно принимают строковые и TIMESTAMPTZ поля.

  • Поля сортировки Top Hits: TopHits.sort допускает сопоставимые поля типа «Boolean», «integer», «floating-point», «string» и « TIMESTAMPTZ », а также « _score ». Не поддерживаются поля типа « ARRAY », « JSON », « GEOMETRY », векторные или динамические поля.

  • Бюджет кандидатов: наибольшее значение TopHits.size в любом месте дерева агрегации также является количеством кандидатов, сохраняемых на каждый полный составной ключ. Если ни на одном уровне не настроено top_hits, Milvus сохраняет одного кандидата на каждый ключ. Размер корзины count и метрики рассчитываются на основе этих сохраненных кандидатов, поэтому изменение TopHits.size может повлиять на них.

  • Поля корзины, допускающие значение null: значение NULL формирует собственный ключ корзины. Чтобы исключить корзину с нулевыми значениями, добавьте в запрос на поиск фильтр, например brand is not null.

  • Повторяющиеся поля: одно и то же поле не может фигурировать более чем в одном списке SearchAggregation.fields. Например, если корневая агрегация использует fields=["category"], вложенная агрегация sub_aggregation не может одновременно использовать fields=["category"].

  • Неподдерживаемые комбинации: агрегация поиска не может сочетаться с ненулевым значением параметра « offset », итераторами поиска, гибридным поиском, выделением результатов или групповым поиском. Значение параметра « offset » верхнего уровня, равное « 0 », эквивалентно пропуску этого параметра. В запросах поиска REST v2 параметры « searchAggregation » и « ids » не могут указываться одновременно.

  • Возвращаемые записи: по умолчанию Milvus отклоняет запрос на агрегацию результатов поиска, если рассчитанное максимальное количество записей в результатах превышает 10 000. Этот порог регулируется параметром proxy.maxSearchAggregationResultEntries. Чтобы отключить эту проверку, установите значение конфигурации равным 0 или отрицательному числу.

    Milvus рассчитывает это максимальное количество следующим образом:

    number of query vectors × product of the effective search_size at every aggregation level × largest TopHits.size at any level

    Для этого вычисления на стороне сервера эффективным значением параметра « search_size » на уровне является явно настроенное значение « search_size » или значение « size » для данного уровня, если параметр « search_size » опущен. API PyMilvus, используемое в данном руководстве, в настоящее время не предоставляет доступ к параметру « search_size », поэтому запросы PyMilvus используют значение « size » каждого уровня для этого вычисления. Используйте 1 для последнего множителя, если ни на одном уровне не настроено TopHits. Например, один вектор запроса, 10 корневых корзин, пять дочерних корзин на каждую корневую корзину и два совпадения на каждую дочернюю корзину дают расчётный максимум:

    1 × 10 × 5 × 2 = 100

Используйте агрегацию поиска

Выберите пример в зависимости от того, что вы хотите достичь:

Перейдите вОписаниеКлючевые настройки
Сравнение и сортировка корзинРассчитайте статистику по каждому сегменту для их сравнения, а затем отсортируйте полученные сегменты по метрикам, количествам или ключам.fields, size, metrics, order
Показать репрезентативные результаты из каждого сегментаВерните ограниченное количество объектов из каждого сегмента и отсортируйте эти объекты независимо друг от друга по скалярным полям или векторной оценке.top_hits, TopHits.size, TopHits.sort
Группировка результатов на нескольких уровняхСгруппируйте результаты по уровням родительских и дочерних корзин для последовательного анализа нескольких измерений.sub_aggregation

В приведенных ниже примерах используется коллекция товаров с полями «бренд», «категория», «цвет», «цена» и «рейтинг». Все названия брендов, названия товаров, цены, рейтинги и результаты поиска являются синтетическими примерами данных. Разверните следующий раздел, чтобы создать коллекцию и определить общие переменные поиска.

Настройка примерной коллекции

from pymilvus import DataType, MilvusClient, SearchAggregation, TopHits

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus",
)

collection_name = "product_search_aggregation"

if client.has_collection(collection_name):
    client.drop_collection(collection_name)

schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=5)
schema.add_field("name", DataType.VARCHAR, max_length=200)
schema.add_field("brand", DataType.VARCHAR, max_length=100)
schema.add_field("category", DataType.VARCHAR, max_length=100)
schema.add_field("color", DataType.VARCHAR, max_length=50)
schema.add_field("price", DataType.DOUBLE)
schema.add_field("rating", DataType.DOUBLE)
schema.add_field("in_stock", DataType.BOOL)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",
    metric_type="COSINE",
)

client.create_collection(
    collection_name=collection_name,
    schema=schema,
    index_params=index_params,
    # Make preceding writes visible to searches from this client.
    consistency_level="Session",
)

client.insert(
    collection_name=collection_name,
    data=[
        {
            "id": 1,
            "embedding": [0.12, 0.42, 0.18, 0.66, 0.31],
            "name": "Runner A1",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 129.99,
            "rating": 4.7,
            "in_stock": True,
        },
        {
            "id": 2,
            "embedding": [0.10, 0.39, 0.20, 0.61, 0.29],
            "name": "Trail A2",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "blue",
            "price": 139.99,
            "rating": 4.6,
            "in_stock": True,
        },
        {
            "id": 3,
            "embedding": [0.14, 0.44, 0.19, 0.68, 0.33],
            "name": "Runner B1",
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 4,
            "embedding": [0.16, 0.41, 0.22, 0.62, 0.30],
            "name": "Runner C1",
            "brand": "Brand C",
            "category": "running_shoes",
            "color": "red",
            "price": 119.99,
            "rating": 4.4,
            "in_stock": False,
        },
        {
            "id": 5,
            "embedding": [0.48, 0.20, 0.59, 0.15, 0.71],
            "name": "Jacket A1",
            "brand": "Brand A",
            "category": "jackets",
            "color": "black",
            "price": 99.99,
            "rating": 4.5,
            "in_stock": True,
        },
        {
            "id": 6,
            "embedding": [0.45, 0.18, 0.55, 0.17, 0.69],
            "name": "Jacket B1",
            "brand": "Brand B",
            "category": "jackets",
            "color": "blue",
            "price": 89.99,
            "rating": 4.3,
            "in_stock": True,
        },
        {
            "id": 7,
            "embedding": [0.09, 0.38, 0.17, 0.60, 0.27],
            "name": "Runner A3",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 8,
            "embedding": [0.13, 0.43, 0.21, 0.65, 0.32],
            "name": "Runner A4",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 149.99,
            "rating": 4.9,
            "in_stock": True,
        },
    ],
)

client.load_collection(collection_name)

query_vector = [0.11, 0.40, 0.19, 0.64, 0.30]
search_params = {
    "metric_type": "COSINE",
    "params": {},
}

Приведенная выше настройка конфигурирует COSINE как для векторного индекса, так и для параметров поиска. Поэтому в последующих примерах используется {"_score": "desc"}, чтобы сначала отображать результаты с более высоким косинусным сходством. Для метрики расстояния, такой как L2, используйте {"_score": "asc"}.

Сравнение и сортировка корзин

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

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

Следующая конфигурация создаёт до трёх групп по брендам, вычисляет показатели для каждой группы и сортирует группы по средней цене:

aggregation = SearchAggregation(
    # Form one bucket for each distinct brand value.
    fields=["brand"],
    # Return up to three buckets at this aggregation level.
    size=3,
    # Calculate named metrics for every selected bucket.
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
        "min_price": {"min": "price"},
    },
    # Sort buckets by average price, highest first.
    order=[
        {"avg_price": "desc"},
        # If average prices are equal, sort by bucket key in ascending order.
        {"_key": "asc"},
    ],
)

Передайте объект в параметр search_aggregation метода MilvusClient.search():

result = client.search(
    collection_name=collection_name,
    data=[query_vector],
    anns_field="embedding",
    search_params=search_params,
    output_fields=[
        "name",
        "brand",
        "category",
        "color",
        "price",
        "rating",
        "in_stock",
    ],
    search_aggregation=aggregation,
)

Когда установлен параметр ` search_aggregation `, PyMilvus не возвращает обычные совпадения сущностей в ` result[0]`. Вместо этого считывайте ответ по сегментам из ` result.agg_buckets[0] `. Параметр ` output_fields ` контролирует, какие скалярные поля появляются в каждом возвращаемом отображении ` AggregationHit.fields `; Milvus по-прежнему может использовать поля источника метрик и сортировки, которые не перечислены в ` output_fields`.

Просмотр примера вывода данных из бакета

Следующий вывод был получен из вышеуказанного запроса и сериализован в формат JSON для удобства чтения. PyMilvus возвращает объекты AggregationBucket, а не JSON. Значение key всегда представляет собой упорядоченный список компонентов ключа, даже если fields содержит только одно поле. Это позволяет сохранить порядок полей для составных ключей.

[
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand B"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 159.99,
      "min_price": 159.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand A"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 129.99,
      "min_price": 129.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand C"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 119.99,
      "min_price": 119.99
    },
    "hits": [],
    "sub_groups": []
  }
]

Для вектора с одним запросом, приведённого в данном руководстве, прочитайте возвращаемые корзины верхнего уровня из result.agg_buckets[0]. Каждая корзина предоставляет свои упорядоченные компоненты ключа, сохраненные кандидаты count, вычисленные значения metrics, репрезентативные значения hits и вложенные корзины в sub_groups.

Прочитайте конфигурацию следующим образом:

ПараметрЧто контролируетВ данном примере
fieldsКак Milvus создает ключи корзинСоздает один бакет для каждого уникального значения brand.
sizeМаксимальное количество возвращаемых корзинВозвращает до трёх корзин по брендам.
metricsСтатистика, рассчитанная для каждого бакетаРассчитывает количество товаров, среднюю цену и минимальную цену.
orderКак Milvus сортирует возвращаемые сегментыСортировка производится по средней цене, а при равенстве значений используется ключ сегмента для определения порядка.

Milvus игнорирует параметр « limit », если установлен параметр « search_aggregation ». Используйте значение корневого параметра « SearchAggregation.size » для управления количеством сегментов верхнего уровня.

При таких настройках Milvus возвращает сегменты «Brand B», «Brand A» и «Brand C» в порядке убывания значения avg_price. Критерий « _key » применяется только в том случае, если корзины имеют одинаковую среднюю цену. Поскольку в данной конфигурации не задан параметр « top_hits », список « hits » для каждой корзины пуст, а бюджет кандидата для каждого ключа равен « 1 ». Поэтому отображаемые значения количества и метрики описывают одного сохраненного кандидата на каждый бренд. Настройте параметр « top_hits » с более крупным значением « TopHits.size », если для агрегации требуется более широкое окно метрики для каждого ключа.

Метрики и правила сортировки

Каждая запись в файле SearchAggregation.metrics сопоставляет пользовательский псевдоним с {operation: source}:

ИсточникПоддерживаемые операцииПоведение
Любое поле, не являющееся полемJSON и не являющееся динамическим полемcountПодсчитывает сохраненные кандидаты, исходное поле которых не является полем типа NULL.
Поле целого или с плавающей запятойsum, avg, min, maxВычисляется по непустым сохраненным значениям.
Поле типа «строка» или « TIMESTAMPTZ »min, maxвыбирает минимальное или максимальное непустое сохраненное значение.
"*"countПодсчитывает количество всех сохраненных кандидатов в корзине. Результат соответствует bucket.count.
_scoresum, avg, min, maxАгрегирует значения сходства или расстояния по ANN для сохраненных кандидатов.

SearchAggregation.order Принимает следующие ключи:

Ключ «Order»Значение
Псевдоним метрикиСортировка по значению, вычисленному в metrics на том же уровне агрегации, например avg_price.
_countСортировка по количеству сохраненных кандидатов в каждом сегменте.
_keyСортировка по ключу корзины, а не по полю коллекции с именем « _key ».

Каждая запись в « order » сопоставляет ключ значению « "asc" » или « "desc" ». Milvus оценивает несколько записей от первой до последней. Если опустить « order », Milvus сохраняет порядок обнаружения корзин из набора сохраненных кандидатов.

Чтобы отсортировать корзины по качеству совпадения векторов, сначала вычислите метрику на уровне корзины из _score, а затем используйте псевдоним метрики в order. Нельзя использовать _score напрямую в качестве ключа для упорядочивания корзин, поскольку каждая корзина может содержать несколько оценок сущностей. Например, при использовании COSINE или IP:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    metrics={"max_score": {"max": "_score"}},
    order=[{"max_score": "desc"}],
)

Используя L2, вычислите минимальное значение _score и отсортируйте псевдоним метрики по возрастанию, чтобы корзины с наименьшим расстоянием располагались первыми.

Создание составных ключей сегментов

Чтобы создать составной ключ корзины, передайте несколько имен полей в одном списке:

aggregation = SearchAggregation(
    # Combine brand and color to form a composite bucket key.
    fields=["brand", "color"],
    size=6,
)

Такая конфигурация может генерировать ключи, такие как (Brand A, black), (Brand A, blue) и (Brand B, white). Две сущности находятся в одном сегменте только в том случае, если оба значения совпадают. Milvus сохраняет порядок списка, поэтому brand является первым компонентом ключа, а color — вторым. Когда _key используется в order, Milvus сравнивает компоненты составного ключа в том же порядке. Передавайте несколько строк в одном плоском списке; вложенные списки не поддерживаются.

size=6 — это максимальное количество составных корзин, возвращаемых на данном уровне агрегации. Пример данных содержит пять различных комбинаций бренда и цвета, поэтому могут быть возвращены все пять. В пределе возвращаемых записей этот запрос вносит 1 query vector × 6 buckets × 1 = 6 настроенных записей результатов.

Наличие нескольких полей в одном списке SearchAggregation.fields создает составной ключ сегмента на данном уровне агрегации. Для создания иерархии сегментов «родитель-потомок» используйте вложенную агрегацию.

В приведенных ниже примерах переопределяется aggregation. Передайте обновленный объект в тот же параметр search_aggregation и повторно выполните вызов поиска.

Показать репрезентативные результаты из каждого сегмента

Включите репрезентативные сущности, если приложению необходимо отобразить реальные продукты из каждого сегмента. В этом примере Milvus возвращает до двух продуктов из каждого сегмента по бренду, отсортированных по рейтингу, а затем по векторному баллу.

Настройте параметр ` TopHits ` следующим образом:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    # Return and sort representative entities for each selected bucket.
    top_hits=TopHits(
        # Return up to two entities per bucket.
        size=2,
        # Apply sort criteria in list order.
        sort=[
            {"rating": "desc"},
            {"_score": "desc"},
        ],
    ),
)

Просмотр корзины с репрезентативными результатами

Следующий сегмент «Бренд A» был извлечен из приведенного выше запроса и сериализован в формате JSON для удобства чтения.

{
  "key": [
    {
      "field_id": 103,
      "field_name": "brand",
      "value": "Brand A"
    }
  ],
  "count": 2,
  "metrics": {},
  "hits": [
    {
      "pk": 1,
      "score": 0.99976646900177,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "black",
        "in_stock": true,
        "name": "Runner A1",
        "price": 129.99,
        "rating": 4.7
      }
    },
    {
      "pk": 2,
      "score": 0.9997048377990723,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "blue",
        "in_stock": true,
        "name": "Trail A2",
        "price": 139.99,
        "rating": 4.6
      }
    }
  ],
  "sub_groups": []
}

ПараметрНазначение
top_hitsНеобязательный. Настраивает репрезентативные сущности для данного уровня агрегации. Если параметр опущен, поле « bucket.hits » остается пустым, а бюджет кандидатов на ключ по умолчанию равен единице.
TopHits.sizeВозвращает до двух репрезентативных объектов из каждого выбранного сегмента и устанавливает бюджет кандидатов на ключ равным двум для всего дерева агрегации.
TopHits.sortУпорядочивает сущности внутри каждого сегмента с использованием перечисленных критериев.

Настройте параметр « top_hits », если приложению требуются репрезентативные сущности или если для подсчётов и метрик необходимо более широкое окно кандидатов на ключ. Увеличение значения параметра « TopHits.size » повышает как бюджет кандидатов, так и максимальное количество возвращаемых записей при вычислении в разделе «Limits».

SearchAggregation.order сортирует корзины, в то время как « TopHits.sort » сортирует сохраненные сущности внутри каждой корзины. Порядок сортировки не влияет на то, какие кандидаты были сохранены для « count » и метрик. « TopHits.sort » принимает имена поддерживаемых сравниваемых скалярных полей и встроенное поле « _score », которое представляет сходство или расстояние по ANN. Milvus оценивает записи « sort » от первой до последней. В данном примере продукты сортируются по rating от наибольшего к наименьшему значению, а _score используется только в случае равенства двух оценок. Поскольку в настройках используется COSINE, убывающая сортировка по _score помещает более похожий продукт на первое место.

Поля, используемые в metrics или TopHits.sort, не обязательно должны фигурировать в output_fields. Milvus извлекает эти поля внутренне, но в отображение fields каждого возвращаемого результата включаются только поля, явно перечисленные в output_fields. Первичные ключи и векторные оценки остаются доступными через AggregationHit.pk и AggregationHit.score.

Каждый возвращаемый результат AggregationHit предоставляет свой первичный ключ в pk, векторный балл в score и запрашиваемые выходные поля в fields.

Группировка результатов на нескольких уровнях

Используйте вложенную агрегацию, когда вам нужен один уровень корзин внутри другого. В этом примере Milvus сначала создает корзины категорий, а затем создает корзины брендов внутри каждой категории.

Дочерняя агрегация получает только сущности, назначенные её родительскому сегменту. Параметр fields управляет ключом сегмента на каждом уровне агрегации, а параметр sub_aggregation формирует иерархию «родитель-дочерний».

Приведенная ниже конфигурация создает корзину категории с ключом (running_shoes). Внутри этой родительской корзины дочерняя агрегация создает отдельные корзины брендов с такими ключами, как (Brand A), (Brand B) и (Brand C).

Parent bucket key:
(running_shoes)

Child bucket keys:
├── (Brand A)
├── (Brand B)
└── (Brand C)

На каждом уровне можно независимо использовать несколько полей. Например, использование fields=["brand", "color"] в дочерней агрегации приведет к созданию составных дочерних ключей, таких как (Brand A, black).

Следующая конфигурация реализует эту иерархию:

aggregation = SearchAggregation(
    fields=["category"],
    size=2,
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
    },
    order=[{"product_count": "desc"}],
    # For each category bucket, group only its entities by brand.
    sub_aggregation=SearchAggregation(
        fields=["brand"],
        size=3,
        metrics={
            "brand_count": {"count": "*"},
            "avg_rating": {"avg": "rating"},
        },
        order=[{"avg_rating": "desc"}],
        top_hits=TopHits(
            size=2,
            sort=[{"rating": "desc"}],
        ),
    ),
)

Просмотр результата вложенного контейнера

В приведённом ниже сериализованном отрывке показан родительский бакет running_shoes и его дочерний бакет «Brand B». Дочерние бакеты «Brand A» и «Brand C» опущены для краткости.

{
  "key": [
    {
      "field_id": 104,
      "field_name": "category",
      "value": "running_shoes"
    }
  ],
  "count": 4,
  "metrics": {
    "avg_price": 137.49,
    "product_count": 4
  },
  "hits": [],
  "sub_groups": [
    {
      "key": [
        {
          "field_id": 103,
          "field_name": "brand",
          "value": "Brand B"
        }
      ],
      "count": 1,
      "metrics": {
        "avg_rating": 4.8,
        "brand_count": 1
      },
      "hits": [
        {
          "pk": 3,
          "score": 0.9994542598724365,
          "fields": {
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "in_stock": true,
            "name": "Runner B1",
            "price": 159.99,
            "rating": 4.8
          }
        }
      ],
      "sub_groups": []
    }
  ]
}

Отображаемый результат представляет путь к корзине (running_shoes) → (Brand B), а не отдельный составной ключ корзины (running_shoes, Brand B).

Сначала Milvus выбирает до двух корзин категорий, упорядоченных по product_count. Затем он независимо запускает запрос sub_aggregation в каждой выбранной категории и возвращает до трёх корзин брендов, упорядоченных по avg_rating.

В приведённом выше выводе:

  • корневой блок « running_shoes » содержит четыре отобранных кандидата по своим дочерним составным ключам. Его « metrics » содержат значения « avg_price » и « product_count » корневого уровня.
  • Список sub_groups корневого сегмента содержит дочерние сегменты брендов. Отображаемый сегмент бренда B содержит один сохраненный кандидат и собственные значения avg_rating и brand_count.
  • Список hits корневого корзины пуст, поскольку для корневой агрегации не настроено значение top_hits. Дочерний корзина бренда B содержит репрезентативное совпадение, поскольку значение top_hits настроено в sub_aggregation.

Часто задаваемые вопросы

Насколько точны подсчёты и метрики корзин?

Агрегация поиска суммирует сохраненные кандидаты ANN. Она не выполняет агрегацию по всей коллекции.

Сохранение кандидатов проходит два этапа аппроксимации. Поиск ANN может пропустить релевантные объекты коллекции, а на этапе группировки сохраняется не более TopHits.size кандидатов для каждого полного составного ключа. Если ни на одном уровне не настроено top_hits, это ограничение на ключ составляет один.

Например, предположим, что коллекция содержит 5 000 продуктов бренда A, и многие из них релевантны векторному запросу. Если при агрегации используется параметр ` TopHits(size=4)`, корзина бренда A может сохранить не более четырёх кандидатов для полного составного ключа. Параметры ` count ` и метрики описывают именно эти сохраненные кандидаты, а не все релевантные продукты бренда A и не все 5 000 объектов коллекции.

Приближенность имеет наибольшее значение, когда в агрегации « order » используется псевдоним метрики. Изменения в полноте поиска могут изменить значения метрик и, следовательно, повлиять на то, какие корзины попадают в « SearchAggregation.size ». Вложенная агрегация может усилить этот эффект, поскольку каждый дочерний уровень работает с сущностями, доступными в своей родительской корзине.

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

Выбор следует делать исходя из основной формы результатов приложения:

Основная потребностьРекомендуетсяРезультат для использования
Возвращает стандартный ранжированный список сущностей с меньшим количеством повторяющихся значений в поле группировкиГрупповой поискРезультаты плоского поиска для каждого вектора запроса
Просмотр или сравнение групп в виде корзин с ключами, подсчётами, метриками, упорядочением, репрезентативными результатами или дочерними корзинамиАгрегация результатов поискаAggregationBucket объекты в result.agg_buckets

Даже если в настройках агрегации результатов поиска задано « top_hits », основным ответом по-прежнему остаётся дерево корзин. Групповой поиск по-прежнему полезен, когда приложение уже обрабатывает обычные результаты поиска и в первую очередь нуждается в разнообразии результатов.

Эти API являются взаимоисключающими. PyMilvus генерирует исключение « ParamError », если в одном запросе сочетаются « search_aggregation » с « group_by_field » или « group_by_fields ».