Agregação de PesquisasCompatible with Milvus 3.0.x
Quando um comprador pesquisa «ténis de corrida pretos para treino diário», a pesquisa por vizinho mais próximo aproximado (ANN) classifica os produtos por semelhança vetorial e apresenta uma lista plana dos Top-K. Os resultados podem ser relevantes, mas repetitivos: no exemplo abaixo, quatro dos seis primeiros resultados são produtos da Marca A, enquanto a Marca B e a Marca C aparecem uma vez cada.
Uma lista plana não consegue fornecer diretamente um resumo orientado por categorias. Uma aplicação pode precisar de comparar marcas com base no número de candidatos retidos ou no preço médio, analisar um pequeno número de produtos representativos de cada marca ou organizar os resultados em vários níveis de categorias.
A Agregação de Pesquisa organiza os candidatos ANN retidos em categorias com base em campos escalares selecionados. Neste exemplo, cada marca torna-se uma categoria separada. O Milvus pode calcular estatísticas para cada categoria, ordenar as categorias e associar-lhes produtos representativos. A aplicação utiliza esta resposta «categoria-primeiro» através de result.agg_buckets.
Um resultado de pesquisa simples sobre sapatilhas de corrida transforma-se num conjunto de categorias de marcas comparáveis
A Agregação de Pesquisa não executa uma agregação exata de toda a coleção. A existência dos grupos, as contagens, as métricas, a ordenação e os resultados representativos dependem dos candidatos retidos pelas fases da ANN e de agrupamento.
Como funciona
Candidatos da ANN agrupados por chaves de bucket e devolvidos com contagens, métricas e resultados representativos
Recuperar candidatos. O Milvus executa uma pesquisa ANN para encontrar as entidades mais próximas do vetor de consulta. A fase de agrupamento retém, em seguida, um número limitado de candidatos para cada chave composta completa. Este limite de candidatos por chave corresponde ao maior valor de «
TopHits.size» em qualquer ponto da árvore de agregação, ou a «1» quando nenhum nível define «top_hits».Criação de buckets.
SearchAggregation.fieldsdefine a chave do bucket. Cada combinação única de valores de campo cria uma chave separada. Na figura,fields=["brand"]cria as chaves de bucket(Brand A),(Brand B)e(Brand C). Os candidatos retidos com a mesma chave pertencem ao mesmo bucket e contribuem para o seucount.SearchAggregation.sizelimita o número de buckets que o Milvus devolve.Calcular e devolver resultados. Cada bucket devolvido contém a sua chave e a contagem de candidatos retidos. O Milvus também pode calcular métricas configuradas, ordenar os buckets, devolver entidades representativas e criar buckets filhos. Cada
AggregationBucketemresult.agg_bucketsexpõekey,count,metrics,hitsesub_groups. Quando a Agregação de Pesquisa está ativada, a lista normal de resultados de pesquisa fica vazia.
No diagrama, TopHits.size=4 fornece um orçamento de candidatos por chave de quatro, pelo que os quatro candidatos retidos da Marca A produzem count: 4. O cartão da Marca A concluído mostra apenas dois dos quatro resultados representativos devolvidos, para manter a figura compacta.
Com « sub_aggregation », o Milvus repete os passos 2 e 3 dentro de cada bucket pai. Alterações na taxa de recuperação da ANN ou no orçamento de candidatos por chave podem alterar o número de buckets, as métricas, a ordenação, os resultados e os resultados aninhados.
Limites
Antes de utilizar a Agregação de Pesquisa, tenha em atenção os seguintes limites:
Agregações aninhadas: um pedido pode conter uma «
SearchAggregation» raiz e até três níveis aninhados de «sub_aggregation», num total máximo de quatro níveis. Em todos os níveis, podem ser utilizados, no máximo, 10 campos para criar chaves de bucket.Campos utilizados para criar chaves de bucket: o
SearchAggregation.fieldssuporta campos booleanos, inteiros,VARCHAReTIMESTAMPTZ. Não suporta camposFLOAT,DOUBLE,ARRAY,JSON,GEOMETRY,TEXT, vetoriais ou dinâmicos.Campos métricos:
countaceita"*"ou qualquer campo nãoJSONe não dinâmico, e ignora valoresNULLquando um campo é especificado.sumeavgaceitam campos inteiros e de ponto flutuante.minemaxaceitam adicionalmente campos de cadeia de caracteres eTIMESTAMPTZ.Campos de ordenação dos «Top Hits»:
TopHits.sortaceita campos comparáveis do tipo booleano, inteiro, de ponto flutuante, cadeia de caracteres eTIMESTAMPTZ, além de_score. Não suportaARRAY,JSON,GEOMETRY, vetores nem campos dinâmicos.Orçamento de candidatos: O maior valor de «
TopHits.size» em qualquer ponto da árvore de agregação corresponde também ao número de candidatos retidos por cada chave composta completa. Se nenhum nível configurar «top_hits», o Milvus retém um candidato por chave. O «count» do bucket e as métricas são calculados a partir destes candidatos retidos, pelo que alterar «TopHits.size» pode alterá-los.Campos de bucket nulos: Um valor «
NULL» forma a sua própria chave de bucket. Para excluir o bucket nulo, adicione um filtro como «brand is not null» à solicitação de pesquisa.Campos repetidos: O mesmo campo não pode aparecer em mais do que uma lista de «
SearchAggregation.fields». Por exemplo, se a agregação raiz utilizar «fields=["category"]», uma agregação aninhada «sub_aggregation» não pode utilizar também «fields=["category"]».Combinações não suportadas: A agregação de pesquisa não pode ser combinada com um `
offset` diferente de zero, iteradores de pesquisa, pesquisa híbrida, um `Highlighter` ou pesquisa de agrupamento. Um valor de nível superior de `offset` igual a `0` equivale a omitir o parâmetro. Nas solicitações de pesquisa REST v2, `searchAggregation` e `ids` não podem ser especificados em conjunto.Entradas devolvidas: Por predefinição, o Milvus rejeita um pedido de «Search Aggregation» quando o número máximo calculado de entradas de resultados do pedido excede 10 000. Este limiar é controlado por «
proxy.maxSearchAggregationResultEntries». Defina o valor de configuração como «0» ou um número negativo para desativar esta verificação.O Milvus calcula este máximo da seguinte forma:
number of query vectors × product of the effective search_size at every aggregation level × largest TopHits.size at any levelPara este cálculo do lado do servidor, o valor efetivo de «
search_size» num nível é o valor explicitamente configurado em «search_size», ou o valor de «size» desse nível quando «search_size» for omitido. A API do PyMilvus utilizada neste guia não expõe atualmente «search_size», pelo que as solicitações do PyMilvus utilizam o valor de «size» de cada nível para este cálculo. Utilize1para o último fator quando nenhum nível configurarTopHits. Por exemplo, um vetor de consulta, 10 buckets raiz, cinco buckets filhos por bucket raiz e dois resultados por bucket filho produzem um máximo calculado de:1 × 10 × 5 × 2 = 100
Utilizar a agregação de pesquisa
Escolha um exemplo com base no que pretende alcançar:
| Aceda a | Descrição | Definições-chave |
|---|---|---|
| Comparar e ordenar buckets | Calcule estatísticas por bucket para comparar buckets e, em seguida, ordene os buckets devolvidos por métricas, contagens ou chaves. | fields, size, metrics, order |
| Mostrar resultados representativos de cada bucket | Retorne um número limitado de entidades de cada bucket e ordene essas entidades de forma independente por campos escalares ou pontuação vetorial. | top_hits, TopHits.size, TopHits.sort |
| Agrupar resultados em vários níveis | Organize os resultados em níveis de grupo pai e filho para analisar várias dimensões em sequência. | sub_aggregation |
Os exemplos abaixo utilizam uma coleção de produtos com campos de marca, categoria, cor, preço e classificação. Todos os nomes de marcas, nomes de produtos, preços, classificações e resultados de pesquisa são dados de exemplo sintéticos. Expanda a secção seguinte para criar a coleção e definir as variáveis de pesquisa partilhadas.
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": {},
}
A configuração acima define COSINE tanto para o índice vetorial como para os parâmetros de pesquisa. Por isso, os exemplos seguintes utilizam {"_score": "desc"} para colocar em primeiro lugar a maior similaridade cosinusoidal. Para uma métrica de distância como L2, utilize {"_score": "asc"}.
Comparar e ordenar buckets
Utilize este padrão quando precisar de comparar grupos de entidades recuperadas utilizando estatísticas calculadas e controlar a ordem em que os buckets são devolvidos. Neste exemplo, o Milvus agrupa os produtos recuperados por brand, calcula métricas de preço para cada bucket de marca e ordena os buckets por preço médio.
Se o seu objetivo for apenas melhorar a diversidade dos resultados, devolvendo uma ou mais entidades por valor de campo, utilize, em vez disso, a Pesquisa por Agrupamento.
A configuração seguinte cria até três buckets de marcas, calcula métricas para cada bucket e ordena os buckets por preço médio:
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"},
],
)
Passe o objeto para o parâmetro « search_aggregation » de « 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,
)
Quando « search_aggregation » está definido, o PyMilvus não devolve resultados de entidades comuns em « result[0] ». Em vez disso, leia a resposta do grupo em « result.agg_buckets[0] ». O parâmetro « output_fields » controla quais os campos escalares que aparecem em cada mapeamento « AggregationHit.fields » devolvido; o Milvus pode ainda utilizar campos de origem de métricas e de ordenação que não estejam listados em « output_fields ».
A saída seguinte foi capturada a partir do pedido acima e serializada como JSON para facilitar a leitura. O PyMilvus devolve objetos AggregationBucket em vez de JSON. O valor key é sempre uma lista ordenada de componentes-chave, mesmo quando fields contém apenas um campo. Isto preserva a ordem dos campos para chaves compostas.
[
{
"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": []
}
]
Para o vetor de consulta único deste guia, leia os buckets de nível superior devolvidos em result.agg_buckets[0]. Cada bucket expõe os seus componentes de chave ordenados, o candidato retido count, o valor calculado metrics, o valor representativo hits e os buckets aninhados em sub_groups.
Leia a configuração da seguinte forma:
| Definição | O que controla | Neste exemplo |
|---|---|---|
fields | Como o Milvus cria as chaves dos buckets | Cria um bucket para cada valor distinto de « brand ». |
size | O número máximo de buckets devolvidos | Retorna até três buckets de marca. |
metrics | As estatísticas calculadas para cada bucket | Calcula a contagem de produtos, o preço médio e o preço mínimo. |
order | Como o Milvus ordena os buckets devolvidos | Ordena por preço médio e, em seguida, utiliza a chave do grupo para desempatar. |
O Milvus ignora limit quando search_aggregation está definido. Utilize o valor raiz SearchAggregation.size para controlar o número de buckets de nível superior.
Com estas definições, o Milvus devolve os buckets da Marca B, da Marca A e da Marca C por ordem descendente de avg_price. O critério « _key » aplica-se apenas quando os buckets têm o mesmo preço médio. Como esta configuração não define « top_hits », a lista « hits » de cada bucket está vazia e o orçamento por chave é « 1 ». As contagens e métricas apresentadas descrevem, portanto, um candidato retido por marca. Configure « top_hits » com um « TopHits.size » maior quando a agregação necessitar de uma janela de métricas por chave mais ampla.
Cada entrada em SearchAggregation.metrics mapeia um alias definido pelo utilizador para {operation: source}:
| Fonte | Operações suportadas | Comportamento |
|---|---|---|
Qualquer campo que não seja «JSON » e que não seja dinâmico | count | Conta os candidatos retidos cujo campo de origem não seja « NULL ». |
| Campo inteiro ou de ponto flutuante | sum, « avg », « min », max | Calcula com base nos valores retidos não nulos. |
Campo de cadeia de caracteres ou « TIMESTAMPTZ » | min, max | Seleciona o valor retido não nulo mínimo ou máximo. |
"*" | count | Conta todos os candidatos retidos no bucket. O resultado corresponde a bucket.count. |
_score | sum, avg, min, max | Agrega valores de similaridade ou distância ANN para os candidatos retidos. |
SearchAggregation.order Aceita as seguintes chaves:
| Chave de ordem | Significado |
|---|---|
| Um alias da métrica | Ordena por um valor calculado no « metrics » no mesmo nível de agregação, como « avg_price ». |
_count | Ordena pelo número de candidatos retidos em cada bucket. |
_key | Ordena pela chave do bucket, em vez de por um campo da coleção denominado « _key ». |
Cada entrada de « order » mapeia uma chave para « "asc" » ou « "desc" ». O Milvus avalia várias entradas, da primeira à última. Se omitir « order », o Milvus mantém a ordem de descoberta dos buckets a partir do conjunto de candidatos retidos.
Para ordenar os buckets pela qualidade da correspondência do vetor, calcule primeiro uma métrica ao nível do bucket a partir de _score e, em seguida, utilize o alias da métrica em order. Não é possível utilizar _score diretamente como chave de ordenação dos buckets, uma vez que cada bucket pode conter várias pontuações de entidades. Por exemplo, com COSINE ou IP:
aggregation = SearchAggregation(
fields=["brand"],
size=3,
metrics={"max_score": {"max": "_score"}},
order=[{"max_score": "desc"}],
)
Com L2, calcule o valor mínimo de _score e ordene o alias da métrica por ordem crescente, de modo a que os buckets com a distância mais baixa apareçam em primeiro lugar.
Para criar uma chave de bucket composta, passe vários nomes de campos na mesma lista:
aggregation = SearchAggregation(
# Combine brand and color to form a composite bucket key.
fields=["brand", "color"],
size=6,
)
Esta configuração pode produzir chaves como (Brand A, black), (Brand A, blue) e (Brand B, white). Duas entidades partilham um bucket apenas quando ambos os valores coincidem. O Milvus preserva a ordem da lista, pelo que brand é o primeiro componente da chave e color é o segundo. Quando _key é utilizado em order, o Milvus compara os componentes da chave composta na mesma ordem. Passe várias cadeias de caracteres numa lista plana; não são suportadas listas aninhadas.
size=6 é o número máximo de buckets compostos devolvidos neste nível de agregação. Os dados de exemplo contêm cinco combinações distintas de marca e cor, pelo que todas as cinco podem ser devolvidas. No limite de entradas devolvidas, este pedido contribui com 1 query vector × 6 buckets × 1 = 6 entradas de resultado configuradas.
Vários campos numa lista SearchAggregation.fields criam uma chave de bucket composta nesse nível de agregação. Para criar uma hierarquia de buckets pai-filho, utilize uma agregação aninhada.
Os exemplos que se seguem redefinem ` aggregation`. Passe o objeto atualizado para o mesmo parâmetro ` search_aggregation ` e volte a executar a chamada de pesquisa.
Mostrar resultados representativos de cada grupo
Inclua entidades representativas quando a aplicação precisar de apresentar produtos reais de cada bucket. Neste exemplo, o Milvus devolve até dois produtos de cada bucket de marca, ordenados por classificação e, em seguida, por pontuação vetorial.
Configure TopHits da seguinte forma:
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"},
],
),
)
O seguinte bucket da Marca A foi capturado a partir do pedido acima e serializado como JSON para facilitar a leitura.
{
"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": []
}
| Parâmetro | Finalidade |
|---|---|
top_hits | Opcional. Configura entidades representativas para este nível de agregação. Se omitido, « bucket.hits » fica vazio e o orçamento candidato por chave assume o valor padrão de um. |
TopHits.size | Devolve até duas entidades representativas de cada grupo selecionado e define o orçamento candidato por chave como dois para toda a árvore de agregação. |
TopHits.sort | Ordena as entidades dentro de cada bucket utilizando os critérios indicados. |
Configure « top_hits » quando a aplicação necessitar de entidades representativas ou quando as contagens e métricas necessitarem de uma janela de candidatos por chave mais ampla. Um « TopHits.size » maior aumenta tanto o orçamento de candidatos como o cálculo do número máximo de entradas devolvidas em «Limits».
SearchAggregation.order O «sorts buckets» ordena os buckets, enquanto o « TopHits.sort » ordena as entidades retidas dentro de cada bucket. A ordem de ordenação não altera quais os candidatos que foram retidos para o « count » e as métricas. O « TopHits.sort » aceita nomes de campos escalares comparáveis suportados e o campo integrado « _score », que representa a semelhança ou distância ANN. O Milvus avalia as entradas « sort » da primeira à última. Neste exemplo, ordena os produtos por rating do mais alto para o mais baixo e utiliza _score apenas quando duas classificações são iguais. Como a configuração utiliza COSINE, a ordem descendente _score coloca o produto mais semelhante em primeiro lugar.
Os campos utilizados por metrics ou TopHits.sort não têm de aparecer em output_fields. O Milvus obtém esses campos internamente, mas apenas os campos explicitamente listados em output_fields são incluídos no mapeamento fields de cada resultado devolvido. As chaves primárias e as pontuações vetoriais permanecem disponíveis através de AggregationHit.pk e AggregationHit.score.
Cada resultado devolvido AggregationHit expõe a sua chave primária em pk, a pontuação vetorial em score e os campos de saída solicitados em fields.
Agrupar resultados em vários níveis
Utilize a agregação aninhada quando precisar de um nível de buckets dentro de outro. Neste exemplo, o Milvus cria primeiro os buckets de categoria e, em seguida, cria os buckets de marca dentro de cada categoria.
A agregação filha recebe apenas as entidades atribuídas ao seu bucket pai. fields controla a chave do bucket em cada nível de agregação, enquanto sub_aggregation cria a hierarquia pai-filho.
A configuração abaixo cria um bucket de categoria com a chave (running_shoes). Dentro desse bucket pai, a agregação filha cria buckets de marca separados com chaves como (Brand A), (Brand B) e (Brand C).
Parent bucket key:
(running_shoes)
Child bucket keys:
├── (Brand A)
├── (Brand B)
└── (Brand C)
Cada nível pode utilizar vários campos de forma independente. Por exemplo, a utilização de fields=["brand", "color"] na agregação filha criaria chaves filhas compostas, como (Brand A, black).
A configuração seguinte implementa esta hierarquia:
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"}],
),
),
)
O excerto serializado a seguir mostra o bucket pai running_shoes e o seu bucket filho «Brand B». Os buckets filhos «Brand A» e «Brand C» foram omitidos por uma questão de concisão.
{
"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": []
}
]
}
O resultado apresentado representa o caminho do bucket (running_shoes) → (Brand B), e não uma única chave de bucket composta (running_shoes, Brand B).
O Milvus seleciona primeiro até dois buckets de categoria, ordenados por product_count. Em seguida, executa sub_aggregation de forma independente dentro de cada categoria selecionada e devolve até três buckets de marca, ordenados por avg_rating.
Na saída acima:
- O grupo raiz «
running_shoes» contém quatro candidatos retidos nas suas chaves compostas filhas. Os seus «metrics» contêm os valores de nível raiz «avg_price» e «product_count». - A lista «
sub_groups» do bucket raiz contém os buckets de marca filhos. O bucket «Brand B» apresentado contém um candidato retido e os seus próprios valores «avg_rating» e «brand_count». - A lista
hitsdo bucket raiz está vazia porque a agregação raiz não configuratop_hits. O bucket filho da Marca B contém um resultado representativo porquetop_hitsestá configurado emsub_aggregation.
Perguntas frequentes
Qual é o nível de precisão das contagens e métricas dos buckets?
A agregação de pesquisa resume os candidatos ANN retidos. Não executa uma agregação da coleção completa.
A retenção de candidatos tem duas fases de aproximação. A pesquisa ANN pode omitir entidades relevantes da coleção, e a fase de agrupamento retém, no máximo, os maiores candidatos TopHits.size para cada chave composta completa. Se nenhum nível configurar top_hits, este limite por chave é um.
Por exemplo, suponha que uma coleção contenha 5 000 produtos da Marca A e que muitos sejam relevantes para a consulta vetorial. Se a agregação utilizar « TopHits(size=4) », o bucket da Marca A pode reter, no máximo, quatro candidatos para uma chave composta completa. O seu « count » e as suas métricas descrevem esses candidatos retidos, e não todos os produtos relevantes da Marca A nem todas as 5 000 entidades da coleção.
A aproximação é mais importante quando a « order » utiliza um alias de métrica. Alterações na taxa de recuperação da pesquisa podem alterar os valores das métricas e, consequentemente, alterar quais os buckets que se enquadram no « SearchAggregation.size ». A agregação aninhada pode amplificar este efeito, uma vez que cada nível filho opera sobre as entidades disponíveis no seu bucket pai.
Se precisar de estatísticas exatas sobre todas as entidades correspondentes, utilize um fluxo de trabalho de agregação de consulta exata em vez da Agregação de Pesquisa.
Em que difere a «Agressão de Pesquisa» da «Pesquisa por Agrupamento»?
Escolha com base no formato de resultados principal da aplicação:
| Necessidade principal | Preferência | Resposta a consumir |
|---|---|---|
| Devolver uma lista de entidades ordenada padrão com menos valores repetidos num campo de agrupamento | Pesquisa agrupada | Resultados de pesquisa planos para cada vetor de consulta |
| Inspecionar ou comparar grupos como compartimentos, com chaves, contagens, métricas, ordenação, resultados representativos ou compartimentos filhos | Agregação de pesquisa | AggregationBucket objetos em result.agg_buckets |
Mesmo quando a Agregação de Pesquisa configura « top_hits », a sua resposta principal continua a ser uma árvore de buckets. A Pesquisa por Agrupamento continua a ser útil quando a aplicação já processa resultados de pesquisa normais e pretende, principalmente, diversidade nos resultados.
As APIs são mutuamente exclusivas. O PyMilvus lança uma exceção « ParamError » quando « search_aggregation » é combinado com « group_by_field » ou « group_by_fields » na mesma solicitação.