Группировка результатов поиска с помощью StructArray

Используйте эту страницу для группировки результатов поиска на уровне элементов StructArray по родительскому объекту. Поиск на уровне элементов может возвращать несколько результатов из одного и того же объекта, если несколько элементов Struct соответствуют запросу. Группировка сворачивает эти результаты на уровне элементов, так что каждый родительский объект отображается не более одного раза.

На этой странице используется коллекция « tech_articles » из раздела «Создание поля StructArray». В коллекции имеется поле StructArray с именем « chunks ». Поле-вектор « chunks[emb] » индексировано для поиска на уровне элементов с использованием стандартной векторной метрики.

Как группировка применяется к StructArray

Режим поискаПоведение группировкиПоведение результатов
Поиск в EmbeddingListНе поддерживается.Не применимо.
Поиск на уровне элементовПоддерживается путем группировки по первичному ключу.Возвращается не более одного результата на каждую родительскую сущность. Метаданные на уровне элементов сохраняются, поэтому индекс или смещение выбранного элемента могут быть возвращены при предоставлении доступа через API или SDK.
Гибридный поискПоддерживается только в том случае, если все подзапросы нацелены на векторные поля на уровне элементов в рамках одного и того же поля StructArray.Подзапросы на уровне элементов группируются по первичному ключу перед обработкой окончательного результата.

Используйте группировку, если поиск на уровне элементов без группировки возвращает слишком много дубликатов родительских сущностей. Если вы хотите, чтобы каждый совпадающий элемент Struct рассматривался как отдельный результат, используйте базовый векторный поиск с StructArray без параметра ` group_by_field`.

Прежде чем начать

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

ТребованияПодробности
Векторное подполе на уровне элементовИспользуйте подполе вектора StructArray, например chunks[emb], индексированное с помощью обычной векторной метрики.
Обычный векторный запросИспользуйте вектор обычного запроса, а не EmbeddingList.
Группировка по первичному ключуИспользуйте первичный ключ коллекции в виде group_by_field, например doc_id.
Отсутствие параметров диапазонаНе сочетайте поиск с группировкой с параметрами поиска по диапазону, такими как radius или range_filter.

Информацию о настройке индекса см. в разделе «Поля StructArray индекса».

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

from pymilvus import MilvusClient

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

query_vector = [0.19, 0.24, 0.30, 0.37]

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    limit=5,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
        "chunks[page]",
        "chunks[quality_score]",
    ],
)

for hits in results:
    for hit in hits:
        print(
            "doc_id:", hit["id"],
            "distance:", hit["distance"],
            "offset:", hit.get("offset"),
            "entity:", hit["entity"],
        )

Без группировки один и тот же doc_id может появиться несколько раз, если запросу соответствуют несколько фрагментов. При использовании group_by_field="doc_id" каждая родительская сущность появляется не более одного раза. Группировка сохраняет метаданные на уровне элементов, поэтому сгруппированный результат по-прежнему может включать выбранный индекс или смещение элемента Struct, если API или SDK его предоставляют.

Добавление скалярных фильтров

Вы можете комбинировать поиск с группировкой со скалярной фильтрацией StructArray. Используйте « element_filter », когда скалярное условие должно ограничивать, какие элементы Struct участвуют в векторном поиске на уровне элементов.

filter_expr = (
    'category == "search" && '
    'element_filter(chunks, '
    '$[section] == "index" && '
    '$[quality_score] > 0.9)'
)

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    filter=filter_expr,
    limit=5,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "category",
        "chunks[text]",
        "chunks[section]",
        "chunks[quality_score]",
    ],
)

Предикат верхнего уровня выбирает кандидатов-сущностей. Предикат ` element_filter ` ограничивает векторный поиск на уровне элементов только соответствующими элементами Struct. Затем группировка сворачивает совпадающие элементы по первичному ключу.

Гибридная группировка с StructArray является функцией на уровне элементов. Она поддерживается только в том случае, если все подпоиски нацелены на векторные поля на уровне элементов в рамках одного и того же поля StructArray. Не используйте запросы на уровне EmbeddingList в гибридном поиске по StructArray с группировкой.

В следующем примере предполагается, что поле StructArray « chunks » имеет два подполя векторного типа на уровне элементов: « chunks[emb] » и « chunks[code_emb] », и оба индексируются с помощью обычных векторных метрик.

from pymilvus import AnnSearchRequest, RRFRanker

index_chunk_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="chunks[emb]",
    limit=10,
    expr='element_filter(chunks, $[section] == "index")',
)

code_chunk_req = AnnSearchRequest(
    data=[code_query_vector],
    anns_field="chunks[code_emb]",
    limit=10,
    expr='element_filter(chunks, $[has_code] == true)',
)

results = client.hybrid_search(
    collection_name="tech_articles",
    reqs=[index_chunk_req, code_chunk_req],
    ranker=RRFRanker(),
    limit=5,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
    ],
)

В данном примере оба подзапроса нацелены на векторные поля на уровне элементов в рамках одного и того же поля StructArray — chunks. Гибридный поиск не поддерживает группировку на уровне элементов, если в нем смешаны обычные векторные поля, разные поля StructArray или запросы на уровне EmbeddingList.

Интерпретация сгруппированных результатов

Элемент результатаЗначение
idПервичный ключ сгруппированной родительской сущности.
distance или оценкаОценка или расстояние выбранного элемента Struct для данной родительской сущности.
offsetПозиция выбранного элемента Struct с нулевой базой при возвращении.
Повторяющиеся первичные ключиНе ожидаются при группировке по первичному ключу.
limitПрименимо к сгруппированным результатам родительских сущностей.

Ограничения

  • Поиск с группировкой применяется только к векторному поиску StructArray на уровне элементов. Поиск EmbeddingList и гибридный поиск на уровне EmbeddingList не поддерживают группировку.

  • Используйте первичный ключ в виде group_by_field. Группировка на уровне элементов StructArray не является универсальной группировкой по произвольным скалярным полям.

  • Не сочетайте поиск с группировкой с поиском по диапазону.

  • Не используйте запрос « EmbeddingList » или метрику « MAX_SIM* » для группированного поиска.

  • Гибридная группировка поддерживается только в том случае, если все подзапросы нацелены на векторные поля на уровне элементов в рамках одного и того же поля StructArray.

  • Гибридная группировка не поддерживается, если гибридный поиск сочетает обычное векторное поле, другое поле StructArray или запрос на уровне EmbeddingList.

Распространенные ошибки

  • Использование группировки с chunks[emb_list_vector], которая предназначена для поиска по EmbeddingList.

  • Группировка по скалярному полю, не являющемуся первичным ключом.

  • Группировка по нескольким полям. Группировка StructArray на уровне элементов поддерживает только группировку по первичному ключу.

  • Ожидание того, что сгруппированные результаты будут представлять каждый найденный элемент Struct. Группировка возвращает не более одного результата на каждую родительскую сущность.

  • Предположение, что группированный поиск на уровне элементов пересчитывает оценку MAX_SIM* в стиле EmbeddingList. Группировка сворачивает совпадения на уровне элементов; она не изменяет модель оценки.

  • Объединение group_by_field с radius или range_filter.

Следующие шаги

  1. Чтобы сначала изучить поиск на уровне элементов без группировки, ознакомьтесь с разделом «Базовый векторный поиск с использованием StructArray».

  2. Чтобы добавить скалярные фильтры к группированному поиску, ознакомьтесь с разделом «Фильтрованный поиск с StructArray».

  3. Чтобы использовать границы оценки или расстояния вместо группировки, ознакомьтесь с разделом «Поиск по диапазону с StructArray».

  4. Чтобы ознакомиться с ограничениями поиска с использованием StructArray, прочтите раздел «Ограничения StructArray».