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.
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.
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, comodocId
.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
.
Realizar una búsqueda por grupos
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 definegroup_size=2
, lo ideal es que cada grupo (o cadadocId
) devuelva dos de los párrafos (o trozos) más similares. Si no se definegroup_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 porgroup_size
. Si se definestrict_group_size=True
, el sistema intentará incluir el número exacto de entidades especificado porgroup_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ámetrolimit
, en lugar de asegurarse de que cada grupo contiene entidades degroup_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 unlimit
adecuado ayuda a controlar la diversidad de la búsqueda y el rendimiento de la consulta. Reducirlimit
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. Ajustargroup_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 porgroup_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 destrict_group_size=False
puede mejorar la velocidad de consulta.