Aggregazione dei risultati di ricercaCompatible with Milvus 3.0.x
Quando un acquirente cerca "scarpe da corsa nere per l'allenamento quotidiano", la ricerca "Approssimazione del vicino più prossimo" (ANN) classifica i prodotti in base alla somiglianza vettoriale e restituisce un elenco piatto Top-K. I risultati possono essere pertinenti ma ripetitivi: nell'esempio riportato di seguito, quattro dei primi sei risultati sono prodotti del Marchio A, mentre il Marchio B e il Marchio C compaiono una volta ciascuno.
Un elenco piatto non può fornire direttamente un riepilogo orientato ai bucket. Un’applicazione potrebbe dover confrontare i marchi in base al numero di candidati selezionati o al prezzo medio, esaminare un numero ridotto di prodotti rappresentativi di ciascun marchio oppure organizzare i risultati in più livelli di bucket.
L’aggregazione della ricerca organizza i candidati ANN selezionati in bucket in base a campi scalari selezionati. In questo esempio, ogni marchio diventa un bucket separato. Milvus può calcolare le statistiche per ciascun bucket, ordinare i bucket e associarvi prodotti rappresentativi. L’applicazione utilizza questa risposta “bucket-first” tramite result.agg_buckets.
Un risultato di ricerca piatto relativo alle scarpe da corsa diventa un insieme di bucket di marchi comparabili
L’aggregazione della ricerca non esegue un’aggregazione esatta dell’intera collezione. L’esistenza dei bucket, i conteggi, le metriche, l’ordinamento e i risultati rappresentativi dipendono dai candidati selezionati dalle fasi della rete neurale artificiale (ANN) e di raggruppamento.
Come funziona
Candidati ANN raggruppati in base alle chiavi dei bucket e restituiti con conteggi, metriche e risultati rappresentativi
Recupero dei candidati. Milvus esegue una ricerca ANN per individuare le entità più vicine al vettore di query. La fase di raggruppamento trattiene quindi un numero limitato di candidati per ciascuna chiave composita completa. Questo limite di candidati per chiave corrisponde al valore più grande di
TopHits.sizein qualsiasi punto dell’albero di aggregazione, oppure a1quando nessun livello configuratop_hits.Creazione dei bucket.
SearchAggregation.fieldsdefinisce la chiave del bucket. Ogni combinazione univoca di valori dei campi crea una chiave separata. Nella figura,fields=["brand"]crea le chiavi dei bucket(Brand A),(Brand B)e(Brand C). I candidati conservati con la stessa chiave appartengono allo stesso bucket e contribuiscono al suocount.SearchAggregation.sizelimita il numero di bucket restituiti da Milvus.Calcolo e restituzione dei risultati. Ogni bucket restituito contiene la propria chiave e il conteggio dei candidati conservati. Milvus può anche calcolare le metriche configurate, ordinare i bucket, restituire entità rappresentative e creare bucket secondari. Ogni
AggregationBucketinresult.agg_bucketsesponekey,count,metrics,hitsesub_groups. Quando l’aggregazione di ricerca è abilitata, il normale elenco dei risultati di ricerca è vuoto.
Nel diagramma, TopHits.size=4 fornisce un budget di candidati per chiave pari a quattro, quindi i quattro candidati del Marchio A conservati generano count: 4. La scheda completa del Marchio A mostra solo due dei quattro risultati rappresentativi restituiti per mantenere la figura compatta.
Con « sub_aggregation », Milvus ripete i passaggi 2 e 3 all’interno di ciascun bucket padre. Le variazioni nel recall della rete neurale artificiale (ANN) o nel budget di candidati per chiave possono modificare il numero di bucket, le metriche, l’ordinamento, i risultati e i risultati annidati.
Limiti
Prima di utilizzare l’aggregazione di ricerca, tenere presente i seguenti limiti:
Aggregazioni annidate: una richiesta può contenere un’aggregazione di ricerca radice (
SearchAggregation) e fino a tre livelli di aggregazione di ricerca secondaria (sub_aggregation) annidati, per un massimo di quattro livelli in totale. A tutti i livelli, è possibile utilizzare al massimo 10 campi per creare le chiavi dei bucket.Campi utilizzati per creare le chiavi di bucket:
SearchAggregation.fieldssupporta campi booleani, interi,VARCHAReTIMESTAMPTZ. Non supporta campiFLOAT,DOUBLE,ARRAY,JSON,GEOMETRY,TEXT, vettoriali o dinamici.Campi metrici:
countaccetta"*"o qualsiasi campo nonJSONe non dinamico, e ignora i valoriNULLquando viene specificato un campo.sumeavgaccettano campi interi e in virgola mobile.minemaxaccettano inoltre campi stringa eTIMESTAMPTZ.Campi di ordinamento dei Top Hits:
TopHits.sortaccetta campi comparabili di tipo booleano, intero, a virgola mobile, stringa eTIMESTAMPTZ, oltre a_score. Non supportaARRAY,JSON,GEOMETRY, né campi vettoriali o dinamici.Budget dei candidati: il valore più grande di `
TopHits.size` in qualsiasi punto dell’albero di aggregazione corrisponde anche al numero di candidati conservati per ogni chiave composita completa. Se nessun livello configura `top_hits`, Milvus conserva un candidato per ogni chiave. Il `count` del bucket e le metriche vengono calcolati a partire da questi candidati conservati, pertanto la modifica di `TopHits.size` può alterarli.Campi del bucket nullabili: un valore
NULLcostituisce una chiave di bucket a sé stante. Per escludere il bucket nullo, aggiungere un filtro comebrand is not nullalla richiesta di ricerca.Campi ripetuti: lo stesso campo non può comparire in più di un elenco di
SearchAggregation.fields. Ad esempio, se l’aggregazione radice utilizzafields=["category"], unsub_aggregationannidato non può utilizzare anchefields=["category"].Combinazioni non supportate: l’aggregazione di ricerca non può essere combinata con un `
offset` diverso da zero, iteratori di ricerca, ricerca ibrida, un evidenziatore o ricerca raggruppata. Un valore di primo livello `offset` pari a `0` equivale all’omissione del parametro. Nelle richieste di ricerca REST v2, `searchAggregation` e `ids` non possono essere specificati insieme.Voci restituite: per impostazione predefinita, Milvus rifiuta una richiesta di aggregazione di ricerca quando il numero massimo calcolato di voci di risultato supera 10.000. Questa soglia è controllata da
proxy.maxSearchAggregationResultEntries. Impostare il valore di configurazione su0o su un numero negativo per disabilitare questo controllo.Milvus calcola questo valore massimo come segue:
number of query vectors × product of the effective search_size at every aggregation level × largest TopHits.size at any levelPer questo calcolo lato server, il valore effettivo di `
search_size` a un livello è il valore esplicitamente configurato in `search_size`, oppure il valore di `size` di quel livello quando `search_size` è omesso. L’API PyMilvus utilizzata in questa guida attualmente non espone `search_size`, pertanto le richieste PyMilvus utilizzano il valore di `size` di ciascun livello per questo calcolo. Utilizzare1come ultimo fattore quando nessun livello configuraTopHits. Ad esempio, un vettore di query, 10 bucket radice, cinque bucket figli per ogni bucket radice e due hit per ogni bucket figlio producono un massimo calcolato pari a:1 × 10 × 5 × 2 = 100
Utilizza l’aggregazione di ricerca
Scegli un esempio in base a ciò che desideri ottenere:
| Vai a | Descrizione | Impostazioni chiave |
|---|---|---|
| Confronta e ordina i bucket | Calcola le statistiche per ogni bucket per confrontarli, quindi ordina i bucket restituiti in base a metriche, conteggi o chiavi. | fields, size, metrics, order |
| Mostra risultati rappresentativi da ciascun bucket | Restituisci un numero limitato di entità da ciascun bucket e ordina tali entità in modo indipendente in base ai campi scalari o al punteggio vettoriale. | top_hits, TopHits.size, TopHits.sort |
| Raggruppare i risultati su più livelli | Organizza i risultati in livelli di bucket padre e figlio per analizzare più dimensioni in sequenza. | sub_aggregation |
Gli esempi riportati di seguito utilizzano una raccolta di prodotti con campi relativi a marchio, categoria, colore, prezzo e valutazione. Tutti i nomi dei marchi, i nomi dei prodotti, i prezzi, le valutazioni e i risultati di ricerca sono dati di esempio sintetici. Espandi la sezione seguente per creare la raccolta e definire le variabili di ricerca condivise.
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": {},
}
La configurazione sopra riportata imposta COSINE sia per l’indice vettoriale che per i parametri di ricerca. Pertanto, gli esempi successivi utilizzano {"_score": "desc"} per posizionare per prime le somiglianze coseno più elevate. Per una metrica di distanza come L2, utilizzare {"_score": "asc"}.
Confronto e ordinamento dei bucket
Utilizza questo modello quando devi confrontare gruppi di entità recuperate utilizzando statistiche calcolate e controllare l’ordine in cui vengono restituiti i bucket. In questo esempio, Milvus raggruppa i prodotti recuperati in base a brand, calcola le metriche di prezzo per ciascun bucket di marca e ordina i bucket in base al prezzo medio.
Se il tuo obiettivo è solo quello di migliorare la diversità dei risultati restituendo una o più entità per ogni valore di campo, utilizza invece la ricerca raggruppata.
La seguente configurazione crea fino a tre bucket per marchio, calcola le metriche per ciascun bucket e ordina i bucket in base al prezzo medio:
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"},
],
)
Passa l’oggetto al parametro ` search_aggregation ` di ` 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 è impostato, PyMilvus non restituisce risultati di entità ordinari in result[0]. Leggi invece la risposta relativa ai bucket da result.agg_buckets[0]. Il parametro output_fields controlla quali campi scalari compaiono in ciascuna mappatura AggregationHit.fields restituita; Milvus può comunque utilizzare campi di origine delle metriche e di ordinamento che non sono elencati in output_fields.
L'output seguente è stato acquisito dalla richiesta sopra riportata e serializzato in formato JSON per una maggiore leggibilità. PyMilvus restituisce oggetti ` AggregationBucket ` anziché JSON. Il valore ` key ` è sempre un elenco ordinato di componenti chiave, anche quando ` fields ` contiene un solo campo. Ciò preserva l'ordine dei campi per le chiavi composte.
[
{
"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": []
}
]
Per il singolo vettore di query in questa guida, leggere i bucket di primo livello restituiti da result.agg_buckets[0]. Ogni bucket espone i propri componenti della chiave ordinati, i candidati conservati count, i valori calcolati metrics, i valori rappresentativi hits e i bucket nidificati in sub_groups.
Leggere la configurazione come segue:
| Impostazione | Cosa controlla | In questo esempio |
|---|---|---|
fields | Come Milvus crea le chiavi dei bucket | Crea un bucket per ogni valore distinto di brand. |
size | Il numero massimo di bucket restituiti | Restituisce fino a tre bucket di marca. |
metrics | Le statistiche calcolate per ciascun bucket | Calcola il numero di prodotti, il prezzo medio e il prezzo minimo. |
order | Come Milvus ordina i bucket restituiti | Ordina in base al prezzo medio, quindi utilizza la chiave del bucket per risolvere i casi di parità. |
Milvus ignora l'limit quando è impostato search_aggregation. Utilizza il valore di root SearchAggregation.size per controllare il numero di bucket di primo livello.
Con queste impostazioni, Milvus restituisce i bucket del Marchio B, del Marchio A e del Marchio C in ordine decrescente di avg_price. Il criterio _key si applica solo quando i bucket hanno lo stesso prezzo medio. Poiché questa configurazione non definisce top_hits, l’elenco hits di ogni bucket è vuoto e il budget candidato per chiave è 1. I conteggi e le metriche visualizzati descrivono quindi un candidato conservato per ogni marchio. Configurare top_hits con un valore maggiore di TopHits.size quando l’aggregazione richiede una finestra di metriche per chiave più ampia.
Ogni voce di SearchAggregation.metrics associa un alias definito dall’utente a {operation: source}:
| Origine | Operazioni supportate | Comportamento |
|---|---|---|
Qualsiasi campo nonJSON e non dinamico | count | Conta i candidati mantenuti il cui campo di origine non è di tipo NULL. |
| Campo intero o in virgola mobile | sum, avg, min, max | Esegue il calcolo sui valori conservati non nulli. |
Campo stringa o TIMESTAMPTZ | min, max | Seleziona il valore conservato non nullo minimo o massimo. |
"*" | count | Conta ogni candidato conservato nel bucket. Il risultato corrisponde a bucket.count. |
_score | sum, avg, min, max | Aggrega i valori di similarità o distanza ANN per i candidati conservati. |
SearchAggregation.order Accetta le seguenti chiavi:
| Chiave di ordinamento | Significato |
|---|---|
| Alias di una metrica | Ordina in base a un valore calcolato in metrics allo stesso livello di aggregazione, ad esempio avg_price. |
_count | Ordina in base al numero di candidati conservati in ciascun bucket. |
_key | Ordina in base alla chiave del bucket anziché a un campo della collezione denominato _key. |
Ogni voce di ` order ` associa una chiave a ` "asc" ` o ` "desc"`. Milvus valuta più voci dalla prima all’ultima. Se si omette ` order`, Milvus mantiene l’ordine di individuazione dei bucket dall’insieme dei candidati conservati.
Per ordinare i bucket in base alla qualità della corrispondenza vettoriale, calcolare innanzitutto una metrica a livello di bucket da _score, quindi utilizzare l’alias della metrica in order. Non è possibile utilizzare direttamente _score come chiave di ordinamento dei bucket poiché ogni bucket può contenere più punteggi di entità. Ad esempio, con COSINE o IP:
aggregation = SearchAggregation(
fields=["brand"],
size=3,
metrics={"max_score": {"max": "_score"}},
order=[{"max_score": "desc"}],
)
Con L2, calcolare il valore minimo di _score e ordinare l’alias della metrica in ordine crescente, in modo che i bucket con la distanza minima vengano visualizzati per primi.
Per creare una chiave di bucket composita, passare più nomi di campo nello stesso elenco:
aggregation = SearchAggregation(
# Combine brand and color to form a composite bucket key.
fields=["brand", "color"],
size=6,
)
Questa configurazione può produrre chiavi come (Brand A, black), (Brand A, blue) e (Brand B, white). Due entità condividono un bucket solo quando entrambi i valori corrispondono. Milvus mantiene l’ordine dell’elenco, quindi brand è il primo componente della chiave e color è il secondo. Quando si utilizza _key in order, Milvus confronta i componenti della chiave composita nello stesso ordine. Passare più stringhe in un unico elenco piatto; gli elenchi annidati non sono supportati.
size=6 è il numero massimo di bucket compositi restituiti a questo livello di aggregazione. I dati di esempio contengono cinque combinazioni distinte di marchio e colore, quindi è possibile restituirle tutte e cinque. Nel limite delle voci restituite, questa richiesta contribuisce con 1 query vector × 6 buckets × 1 = 6 voci di risultato configurate.
Più campi in un unico elenco SearchAggregation.fields creano una chiave di bucket composita a quel livello di aggregazione. Per creare una gerarchia di bucket padre-figlio, utilizzare un'aggregazione annidata.
Gli esempi che seguono ridefinisc aggregation. Passare l’oggetto aggiornato allo stesso parametro search_aggregation ed eseguire nuovamente la chiamata di ricerca.
Mostra risultati rappresentativi da ciascun bucket
Includere entità rappresentative quando l’applicazione deve mostrare prodotti effettivi da ciascun bucket. In questo esempio, Milvus restituisce fino a due prodotti da ciascun bucket di marca, ordinati per valutazione e poi per punteggio vettoriale.
Configurare TopHits come segue:
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"},
],
),
)
Il seguente bucket del marchio A è stato estratto dalla richiesta sopra riportata e serializzato in formato JSON per facilitarne la lettura.
{
"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": []
}
| Parametro | Scopo |
|---|---|
top_hits | Opzionale. Configura le entità rappresentative per questo livello di aggregazione. Se omesso, " bucket.hits " risulta vuoto e il budget candidato per chiave viene impostato di default a uno. |
TopHits.size | Restituisce fino a due entità rappresentative da ciascun bucket selezionato e imposta il budget candidato per chiave a due per l'intero albero di aggregazione. |
TopHits.sort | Ordina le entità all’interno di ciascun bucket utilizzando i criteri elencati. |
Configurare ` top_hits ` quando l’applicazione necessita di entità rappresentative o quando i conteggi e le metriche richiedono una finestra di candidati per chiave più ampia. Un valore maggiore di ` TopHits.size ` aumenta sia il budget dei candidati sia il calcolo del numero massimo di voci restituite in `Limits`.
SearchAggregation.order Ordina i bucket, mentre l’opzione « TopHits.sort » ordina le entità conservate all’interno di ciascun bucket. L’ordine di ordinamento non modifica quali candidati sono stati conservati per l’ count e le metriche. L’opzione « TopHits.sort » accetta nomi di campi scalari comparabili supportati e il campo integrato « _score », che rappresenta la somiglianza o la distanza ANN. Milvus valuta le voci « sort » dalla prima all’ultima. In questo esempio, ordina i prodotti in base a rating dal valore più alto a quello più basso e utilizza _score solo quando due valutazioni sono uguali. Poiché la configurazione utilizza COSINE, l’ordinamento decrescente _score posiziona per primo il prodotto più simile.
I campi utilizzati da metrics o TopHits.sort non devono necessariamente comparire in output_fields. Milvus recupera tali campi internamente, ma solo i campi esplicitamente elencati in output_fields vengono inclusi nella mappatura fields di ciascun risultato restituito. Le chiavi primarie e i punteggi vettoriali rimangono disponibili tramite AggregationHit.pk e AggregationHit.score.
Ogni AggregationHit restituito espone la propria chiave primaria in pk, il punteggio vettoriale in score e i campi di output richiesti in fields.
Raggruppamento dei risultati su più livelli
Utilizzare l’aggregazione annidata quando è necessario un livello di bucket all’interno di un altro. In questo esempio, Milvus crea prima i bucket di categoria, quindi crea i bucket di marchio all’interno di ciascuna categoria.
L’aggregazione figlia riceve solo le entità assegnate al proprio bucket padre. fields controlla la chiave del bucket a ciascun livello di aggregazione, mentre sub_aggregation crea la gerarchia padre-figlio.
La configurazione riportata di seguito crea un bucket di categoria con la chiave (running_shoes). All’interno di quel bucket padre, l’aggregazione figlia crea bucket di marchio separati con chiavi quali (Brand A), (Brand B) e (Brand C).
Parent bucket key:
(running_shoes)
Child bucket keys:
├── (Brand A)
├── (Brand B)
└── (Brand C)
Ogni livello può utilizzare più campi in modo indipendente. Ad esempio, l’utilizzo di fields=["brand", "color"] nell’aggregazione figlia creerebbe chiavi figlie composte come (Brand A, black).
La seguente configurazione implementa questa gerarchia:
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"}],
),
),
)
Il seguente estratto serializzato mostra il bucket padre running_shoes e il suo bucket figlio Brand B. I bucket figli Brand A e Brand C sono stati omessi per brevità.
{
"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": []
}
]
}
Il risultato visualizzato rappresenta il percorso del bucket (running_shoes) → (Brand B), non una singola chiave composita del bucket (running_shoes, Brand B).
Milvus seleziona innanzitutto fino a due bucket di categoria, ordinati in base a product_count. Successivamente esegue sub_aggregation in modo indipendente all’interno di ciascuna categoria selezionata e restituisce fino a tre bucket di marchio, ordinati in base a avg_rating.
Nell’output sopra riportato:
- Il bucket radice
running_shoescontiene quattro candidati selezionati tra le sue chiavi composite figlie. I suoimetricscontengono i valori di livello radiceavg_priceeproduct_count. - L'elenco
sub_groupsdel bucket radice contiene i bucket secondari relativi ai marchi. Il bucket "Brand B" visualizzato contiene un candidato conservato e i propri valoriavg_ratingebrand_count. - L’elenco
hitsdel bucket radice è vuoto perché l’aggregazione radice non configuratop_hits. Il bucket figlio del marchio B contiene un risultato rappresentativo perchétop_hitsè configurato insub_aggregation.
Domande frequenti
Quanto sono accurati i conteggi e le metriche dei bucket?
L’aggregazione di ricerca riassume i candidati ANN conservati. Non esegue un’aggregazione completa della raccolta.
La conservazione dei candidati prevede due fasi di approssimazione. La ricerca ANN può omettere entità rilevanti della collezione, mentre la fase di raggruppamento conserva al massimo i candidati più grandi TopHits.size per ciascuna chiave composita completa. Se nessun livello configura top_hits, questo limite per chiave è pari a uno.
Ad esempio, supponiamo che una collezione contenga 5.000 prodotti del Marchio A e che molti siano rilevanti per la query vettoriale. Se l’aggregazione utilizza ` TopHits(size=4)`, il bucket del Marchio A può conservare al massimo quattro candidati per una chiave composita completa. Il suo ` count ` e le metriche descrivono quei candidati conservati, non tutti i prodotti rilevanti del Marchio A e non tutte le 5.000 entità della collezione.
L’approssimazione è particolarmente rilevante quando l’ order utilizza un alias di metrica. Le variazioni nel recall della ricerca possono modificare i valori delle metriche e, di conseguenza, determinare quali bucket rientrano nell’ SearchAggregation.size. L’aggregazione annidata può amplificare questo effetto poiché ogni livello figlio opera sulle entità disponibili nel proprio bucket padre.
Se sono necessarie statistiche esatte su ogni entità corrispondente, utilizzare un flusso di lavoro di aggregazione con query esatta anziché l’aggregazione di ricerca.
In che modo l’aggregazione di ricerca differisce dalla ricerca per raggruppamento?
Scegli in base alla forma principale dei risultati dell’applicazione:
| Esigenza principale | Preferire | Risposta da utilizzare |
|---|---|---|
| Restituisce un elenco standard di entità ordinato per rilevanza con un minor numero di valori ripetuti in un campo di raggruppamento | Ricerca raggruppata | Risultati di ricerca piatti per ciascun vettore di query |
| Esamina o confronta i gruppi come bucket, con chiavi, conteggi, metriche, ordinamento, risultati rappresentativi o bucket secondari | Aggregazione della ricerca | AggregationBucket oggetti in result.agg_buckets |
Anche quando l’aggregazione di ricerca configura top_hits, la sua risposta principale rimane un albero di bucket. La ricerca raggruppata rimane utile quando l’applicazione elabora già risultati di ricerca ordinari e mira principalmente alla diversità dei risultati.
Le API si escludono a vicenda. PyMilvus genera un'eccezione di tipo ` ParamError ` quando ` search_aggregation ` viene combinato con ` group_by_field ` o ` group_by_fields ` nella stessa richiesta.