milvus-logo
LFAI
Home
  • Guía del usuario

Búsqueda de agrupación

Una búsqueda de agrupación permite a Milvus agrupar los resultados de la búsqueda por los valores de un campo especificado para agregar datos a un nivel superior. Por ejemplo, puede utilizar una búsqueda RNA básica para encontrar libros similares al que tiene entre manos, pero puede utilizar una búsqueda de agrupación para encontrar las categorías de libros que pueden implicar los temas tratados en ese libro. Este tema describe cómo utilizar la búsqueda de agrupación junto con consideraciones clave.

Resumen

Cuando las entidades de los resultados de la búsqueda comparten el mismo valor en un campo escalar, esto indica que son similares en un atributo concreto, lo que puede afectar negativamente a los resultados de la búsqueda.

Supongamos que una colección almacena varios documentos (denotados por docId). Para conservar tanta información semántica como sea posible al convertir los documentos en vectores, cada documento se divide en párrafos (o trozos) más pequeños y manejables y se almacenan como entidades independientes. Aunque el documento esté dividido en secciones más pequeñas, los usuarios suelen seguir interesados en identificar qué documentos son los más relevantes para sus necesidades.

ANN Search Búsqueda RNA

Cuando se realiza una búsqueda por vecino más próximo (RNA) en una colección de este tipo, los resultados de la búsqueda pueden incluir varios párrafos del mismo documento, lo que puede hacer que se pasen por alto otros documentos, lo que puede no ajustarse al caso de uso previsto.

Grouping Search Búsqueda por grupos

Para mejorar la diversidad de los resultados de la búsqueda, puede añadir el parámetro group_by_field en la petición de búsqueda para activar la Búsqueda por agrupación. Como se muestra en el diagrama, puede establecer group_by_field en docId. Al recibir esta solicitud, Milvus.

  • Realizará una búsqueda RNA basada en el vector de consulta proporcionado para encontrar todas las entidades más similares a la consulta.

  • Agrupará los resultados de la búsqueda por el group_by_field especificado, como docId.

  • Devolverá los resultados principales de cada grupo, definidos por el parámetro limit, con la entidad más similar de cada grupo.

Por defecto, la búsqueda agrupada sólo devuelve una entidad por grupo. Si desea aumentar el número de resultados por grupo, puede controlarlo con los parámetros group_size y strict_group_size.

Esta sección proporciona código de ejemplo para demostrar el uso de la Búsqueda por agrupación. El siguiente ejemplo asume que la colección incluye campos para id, vector, chunk, y 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},
]


En la solicitud de búsqueda, establezca group_by_field y output_fields en docId. Milvus agrupará los resultados por el campo especificado y devolverá la entidad más similar de cada grupo, incluyendo el valor de docId para cada entidad devuelta.

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"]
}'

En la petición anterior, limit=3 indica que el sistema devolverá resultados de búsqueda de tres grupos, conteniendo cada grupo la entidad más similar al vector de consulta.

Configurar el tamaño de los grupos

Por defecto, la búsqueda por grupos sólo devuelve una entidad por grupo. Si desea obtener varios resultados por grupo, ajuste los parámetros group_size y 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"]
}'

En el ejemplo anterior

  • group_size: Especifica el número deseado de entidades a devolver por grupo. Por ejemplo, si se define group_size=2, lo ideal es que cada grupo (o cada docId) devuelva dos de los párrafos (o trozos) más similares. Si no se define group_size, el sistema devuelve por defecto un resultado por grupo.

  • strict_group_size: Este parámetro booleano controla si el sistema debe aplicar estrictamente el recuento establecido por group_size. Si se define strict_group_size=True, el sistema intentará incluir el número exacto de entidades especificado por group_size en cada grupo (por ejemplo, dos párrafos), a menos que no haya suficientes datos en ese grupo. Por defecto (strict_group_size=False), el sistema da prioridad a cumplir el número de grupos especificado por el parámetro limit, en lugar de asegurarse de que cada grupo contiene entidades de group_size. Este enfoque suele ser más eficaz en los casos en que la distribución de los datos es desigual.

Para más detalles sobre los parámetros, consulte search().

Consideraciones

  • Número de grupos: El parámetro limit controla el número de grupos de los que se devuelven los resultados de la búsqueda, en lugar del número específico de entidades dentro de cada grupo. Establecer un limit adecuado ayuda a controlar la diversidad de la búsqueda y el rendimiento de la consulta. Reducir limit puede reducir los costes de cálculo si los datos están densamente distribuidos o el rendimiento es un problema.

  • Entidades por grupo: El parámetro group_size controla el número de entidades devueltas por grupo. Ajustar group_size en función de su caso de uso puede aumentar la riqueza de los resultados de búsqueda. Sin embargo, si los datos están distribuidos de forma desigual, algunos grupos pueden devolver menos entidades de las especificadas por group_size, especialmente en escenarios de datos limitados.

  • Tamaño de grupo estricto: En strict_group_size=True, el sistema intentará devolver el número especificado de entidades (group_size) para cada grupo, a menos que no haya suficientes datos en ese grupo. Esta configuración garantiza un recuento coherente de entidades por grupo, pero puede reducir el rendimiento en caso de distribución desigual de los datos o de recursos limitados. Si no se requieren recuentos de entidades estrictos, la configuración de strict_group_size=False puede mejorar la velocidad de consulta.

Traducido porDeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

¿Fue útil esta página?