🚀 Попробуйте Zilliz Cloud, полностью управляемый Milvus, бесплатно — ощутите 10-кратное увеличение производительности! Попробовать сейчас>

milvus-logo
LFAI
Главная
  • Руководство пользователя
  • Home
  • Docs
  • Руководство пользователя

  • Поиск и ранжирование

  • Группировка Поиск

Группировочный поиск

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

Обзор

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

Предположим, что в коллекции хранится несколько документов (обозначаемых docId). Чтобы сохранить как можно больше семантической информации при преобразовании документов в векторы, каждый документ разбивается на более мелкие, управляемые абзацы (или куски) и хранится как отдельные сущности. Даже если документ разделен на более мелкие части, пользователи часто заинтересованы в том, чтобы определить, какие документы наиболее релевантны их потребностям.

ANN Search ANN-поиск

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

Grouping Search Группировка поиска

Чтобы улучшить разнообразие результатов поиска, можно добавить параметр group_by_field в запрос на поиск, чтобы включить группировочный поиск. Как показано на рисунке, можно установить group_by_field на docId. Получив этот запрос, Milvus.

  • Выполнит ANN-поиск на основе предоставленного вектора запроса, чтобы найти все сущности, наиболее похожие на запрос.

  • Сгруппирует результаты поиска по указанному group_by_field, например docId.

  • Вернет верхние результаты для каждой группы, как определено параметром limit, с наиболее похожими сущностями из каждой группы.

По умолчанию группировочный поиск возвращает только одну сущность на группу. Если вы хотите увеличить количество результатов, возвращаемых для каждой группы, вы можете управлять этим с помощью параметров group_size и strict_group_size.

В этом разделе приведены примеры кода, демонстрирующие использование группировочного поиска. В следующем примере предполагается, что коллекция включает поля id, vector, chunk и docId.

[
        {"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "chunk": "pink_8682", "docId": 1},
        {"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "chunk": "red_7025", "docId": 5},
        {"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "chunk": "orange_6781", "docId": 2},
        {"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "chunk": "pink_9298", "docId": 3},
        {"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "chunk": "red_4794", "docId": 3},
        {"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "chunk": "yellow_4222", "docId": 4},
        {"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "chunk": "red_9392", "docId": 1},
        {"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "chunk": "grey_8510", "docId": 2},
        {"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "chunk": "white_9381", "docId": 5},
        {"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "chunk": "purple_4976", "docId": 3},
]


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

from pymilvus import MilvusClient

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

query_vectors = [
    [0.14529211512077012, 0.9147257273453546, 0.7965055218724449, 0.7009258593102812, 0.5605206522382088]]

# Group search results
res = client.search(
    collection_name="group_search_collection",
    data=query_vectors,
    limit=3,
    group_by_field="docId",
    output_fields=["docId"]
)

# Retrieve the values in the `docId` column
doc_ids = [result['entity']['docId'] for result in res[0]]

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .token("root:Milvus")
        .build());

FloatVec queryVector = new FloatVec(new float[]{0.14529211512077012f, 0.9147257273453546f, 0.7965055218724449f, 0.7009258593102812f, 0.5605206522382088f});
SearchReq searchReq = SearchReq.builder()
        .collectionName("group_search_collection")
        .data(Collections.singletonList(queryVector))
        .topK(3)
        .groupByFieldName("docId")
        .outputFields(Collections.singletonList("docId"))
        .build();

SearchResp searchResp = client.search(searchReq);

List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    System.out.println("TopK results:");
    for (SearchResp.SearchResult result : results) {
        System.out.println(result);
    }
}

// Output
// TopK results:
// SearchResp.SearchResult(entity={docId=5}, score=0.74767184, id=1)
// SearchResp.SearchResult(entity={docId=2}, score=0.6254269, id=7)
// SearchResp.SearchResult(entity={docId=3}, score=0.3611898, id=3)

// nolint
func ExampleClient_Search_grouping() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    milvusAddr := "127.0.0.1:19530"
    token := "root:Milvus"

    cli, err := client.New(ctx, &client.ClientConfig{
        Address: milvusAddr,
        APIKey:  token,
    })
    if err != nil {
        log.Fatal("failed to connect to milvus server: ", err.Error())
    }

    defer cli.Close(ctx)

    queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}

    resultSets, err := cli.Search(ctx, client.NewSearchOption(
        "my_collection", // collectionName
        3,               // limit
        []entity.Vector{entity.FloatVector(queryVector)},
    ).WithGroupByField("docId"))
    if err != nil {
        log.Fatal("failed to perform basic ANN search collection: ", err.Error())
    }

    for _, resultSet := range resultSets {
        log.Println("IDs: ", resultSet.IDs)
        log.Println("Scores: ", resultSet.Scores)
    }
    // Output:
    // IDs:
    // Scores:
}

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});

var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 3,
    // highlight-start
    group_by_field: "docId"
    // highlight-end
})

// Retrieve the values in the `docId` column
var docIds = res.results.map(result => result.entity.docId)

export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "group_search_collection",
    "data": [
        [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
    ],
    "annsField": "vector",
    "limit": 3,
    "groupingField": "docId",
    "outputFields": ["docId"]
}'

В приведенном выше запросе limit=3 указывает на то, что система вернет результаты поиска из трех групп, причем каждая группа будет содержать одну наиболее похожую на вектор запроса сущность.

Настройка размера группы

По умолчанию группировочный поиск возвращает только одну сущность на группу. Если вы хотите получить несколько результатов на группу, настройте параметры group_size и strict_group_size.

# Group search results

res = client.search(
    collection_name="group_search_collection", 
    data=query_vectors, # Query vector
    limit=5, # Top K results to return
    group_by_field="docId", # Group by docId
    group_size=2, # Return 2 entities per group
    strict_group_size=True, # Ensure each group has 2 entities
    output_fields=["docId"]
)

FloatVec queryVector = new FloatVec(new float[]{0.14529211512077012f, 0.9147257273453546f, 0.7965055218724449f, 0.7009258593102812f, 0.5605206522382088f});
SearchReq searchReq = SearchReq.builder()
        .collectionName("group_search_collection")
        .data(Collections.singletonList(queryVector))
        .topK(5)
        .groupByFieldName("docId")
        .groupSize(2)
        .strictGroupSize(true)
        .outputFields(Collections.singletonList("docId"))
        .build();

SearchResp searchResp = client.search(searchReq);

List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    System.out.println("TopK results:");
    for (SearchResp.SearchResult result : results) {
        System.out.println(result);
    }
}

// Output
// TopK results:
// SearchResp.SearchResult(entity={docId=5}, score=0.74767184, id=1)
// SearchResp.SearchResult(entity={docId=5}, score=-0.49148706, id=8)
// SearchResp.SearchResult(entity={docId=2}, score=0.6254269, id=7)
// SearchResp.SearchResult(entity={docId=2}, score=0.38515577, id=2)
// SearchResp.SearchResult(entity={docId=3}, score=0.3611898, id=3)
// SearchResp.SearchResult(entity={docId=3}, score=0.19556211, id=4)

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});

var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 3,
    group_by_field: "docId",
    // highlight-start
    group_size: 2,
    strict_group_size: true
    // highlight-end
})

// Retrieve the values in the `docId` column
var docIds = res.results.map(result => result.entity.docId)

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "group_search_collection",
    "data": [
        [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
    ],
    "annsField": "vector",
    "limit": 5,
    "groupingField": "docId",
    "groupSize":2,
    "strictGroupSize":true,
    "outputFields": ["docId"]
}'

В примере выше.

  • group_size: Указывает желаемое количество сущностей, возвращаемых в каждой группе. Например, если задать group_size=2, то каждая группа (или каждый docId) в идеале должна возвращать два наиболее похожих абзаца (или фрагмента). Если group_size не задан, система по умолчанию возвращает один результат на группу.

  • strict_group_size: Этот булевский параметр управляет тем, должна ли система строго придерживаться подсчета, заданного group_size. Если задан strict_group_size=True, система попытается включить в каждую группу точное количество сущностей, заданное group_size (например, два абзаца), если только в этой группе не будет достаточно данных. По умолчанию (strict_group_size=False), системе приоритетнее удовлетворить количество групп, заданное параметром limit, чем гарантировать, что каждая группа содержит сущности group_size. Такой подход обычно более эффективен в случаях, когда распределение данных неравномерно.

Дополнительные сведения о параметрах см. в разделе Поиск().

Соображения

  • Количество групп: Параметр limit управляет количеством групп, из которых возвращаются результаты поиска, а не конкретным количеством сущностей в каждой группе. Установка подходящего значения limit помогает контролировать разнообразие поиска и производительность запросов. Уменьшение limit может снизить затраты на вычисления, если данные распределены плотно или производительность вызывает беспокойство.

  • Сущности на группу: Параметр group_size управляет количеством сущностей, возвращаемых на группу. Настройка параметра group_size в зависимости от конкретного случая использования может повысить насыщенность результатов поиска. Однако если данные распределены неравномерно, некоторые группы могут возвращать меньше сущностей, чем указано на group_size, особенно в сценариях с ограниченным количеством данных.

  • Строгий размер группы: При использовании strict_group_size=True система будет пытаться вернуть указанное количество сущностей (group_size) для каждой группы, если только в этой группе нет достаточного количества данных. Эта настройка обеспечивает постоянное количество сущностей в группе, но может привести к снижению производительности при неравномерном распределении данных или ограниченных ресурсах. Если строгий подсчет сущностей не требуется, установка strict_group_size=False может повысить скорость выполнения запросов.

Попробуйте Managed Milvus бесплатно

Zilliz Cloud работает без проблем, поддерживается Milvus и в 10 раз быстрее.

Начать
Обратная связь

Была ли эта страница полезной?