Come utilizzare la ricerca spaziale e vettoriale ibrida con Milvus

  • Engineering
March 18, 2026
Alden

Una query come "trovare ristoranti romantici nel raggio di 3 km" sembra semplice. Non lo Γ¨, perchΓ© combina il filtraggio della posizione e la ricerca semantica. La maggior parte dei sistemi deve dividere questa query su due database, il che significa sincronizzare i dati, unire i risultati nel codice e aumentare la latenza.

Milvus 2.6.4 elimina questa suddivisione. Con un tipo di dati nativo GEOMETRY e un indice R-Tree, Milvus puΓ² applicare vincoli di localizzazione e semantici in un'unica query. Questo rende la ricerca spaziale e semantica ibrida molto piΓΉ semplice ed efficiente.

Questo articolo spiega perchΓ© questa modifica era necessaria, come GEOMETRY e R-Tree funzionano all'interno di Milvus, quali vantaggi prestazionali ci si puΓ² aspettare e come configurarli con l'SDK Python.

Query come "ristoranti romantici nel raggio di 3 km" sono difficili da gestire per due motivi:

  • Il termine "romantico" richiede una ricerca semantica. Il sistema deve vettorializzare le recensioni e i tag dei ristoranti, quindi trovare le corrispondenze in base alla somiglianza nello spazio di incorporazione. Questo funziona solo in un database vettoriale.
  • "Entro 3 km" richiede un filtro spaziale. I risultati devono essere limitati a "entro 3 km dall'utente" o, talvolta, "all'interno di uno specifico poligono o confine amministrativo".

In un'architettura tradizionale, soddisfare entrambe le esigenze significava di solito gestire due sistemi affiancati:

  • PostGIS / Elasticsearch per il geofencing, il calcolo delle distanze e il filtraggio spaziale.
  • Un database vettoriale per la ricerca approssimativa dei vicini (ANN) sugli embeddings.

Questo design "a due database" crea tre problemi pratici:

  • Sincronizzazione dolorosa dei dati. Se un ristorante cambia indirizzo, Γ¨ necessario aggiornare sia il sistema geo che il database vettoriale. La mancanza di un aggiornamento produce risultati incoerenti.
  • Maggiore latenza. L'applicazione deve chiamare due sistemi e unire i loro risultati, aggiungendo giri di rete e tempo di elaborazione.
  • Filtraggio inefficiente. Se il sistema eseguiva prima la ricerca vettoriale, spesso restituiva molti risultati che erano lontani dall'utente e dovevano essere scartati in seguito. Se si applicava prima il filtraggio della posizione, l'insieme rimanente era ancora grande, quindi la fase di ricerca vettoriale era ancora costosa.

Milvus 2.6.4 ha risolto questo problema aggiungendo il supporto della geometria spaziale direttamente al database vettoriale. La ricerca semantica e il filtraggio della posizione sono ora eseguiti nella stessa query. Con tutto in un unico sistema, la ricerca ibrida Γ¨ piΓΉ veloce e piΓΉ facile da gestire.

Cosa aggiunge GEOMETRY a Milvus

Milvus 2.6 introduce un tipo di campo scalare chiamato DataType.GEOMETRY. Invece di memorizzare le localitΓ  come numeri separati di longitudine e latitudine, Milvus ora memorizza oggetti geometrici: punti, linee e poligoni. Quesiti come "questo punto Γ¨ all'interno di una regione?" o "Γ¨ entro X metri?" diventano operazioni native. Non c'Γ¨ piΓΉ bisogno di costruire workaround sulle coordinate grezze.

L'implementazione segue lostandard OpenGIS Simple Features Access, quindi funziona con la maggior parte degli strumenti geospaziali esistenti. I dati geometrici sono memorizzati e interrogati utilizzando WKT (Well-Known Text), un formato di testo standard leggibile dall'uomo e analizzabile dai programmi.

Tipi di geometria supportati:

  • PUNTO: una singola posizione, come l'indirizzo di un negozio o la posizione in tempo reale di un veicolo.
  • LINEA: una linea, come la linea centrale di una strada o un percorso di movimento.
  • POLIGONO: un'area, come un confine amministrativo o un geofence.
  • Tipi di raccolta: MULTIPOINT, MULTILINESTRING, MULTIPOLYGON e GEOMETRYCOLLECTION.

Supporta inoltre gli operatori spaziali standard, tra cui:

  • Relazioni spaziali: contenimento (ST_CONTAINS, ST_WITHIN), intersezione (ST_INTERSECTS, ST_CROSSES) e contatto (ST_TOUCHES).
  • Operazioni di distanza: calcolo delle distanze tra le geometrie (ST_DISTANCE) e filtraggio degli oggetti entro una determinata distanza (ST_DWITHIN).

Come funziona l'indicizzazione R-Tree in Milvus

Il supporto per la GEOMETRIA Γ¨ integrato nel motore di interrogazione di Milvus, non solo esposto come funzione API. I dati ISpatial vengono indicizzati ed elaborati direttamente all'interno del motore utilizzando l'indice R-Tree (Rectangle Tree).

Un R-Tree raggruppa gli oggetti vicini utilizzando i rettangoli minimi di delimitazione (MBR). Durante l'interrogazione, il motore salta le grandi regioni che non si sovrappongono alla geometria dell'interrogazione ed esegue controlli dettagliati solo su un piccolo insieme di candidati. Questo Γ¨ molto piΓΉ veloce della scansione di ogni oggetto.

Come Milvus costruisce l'albero R

La costruzione dell'albero R avviene per livelli:

LivelloCosa fa MilvusAnalogia intuitiva
Livello della fogliaPer ogni oggetto geometrico (punto, linea o poligono), Milvus calcola il suo rettangolo minimo di delimitazione (MBR) e lo memorizza come nodo foglia.Avvolge ogni oggetto in un riquadro trasparente che gli si adatta esattamente.
Livelli intermediI nodi foglia vicini vengono raggruppati (in genere 50-100 alla volta) e viene creato un MBR genitore piΓΉ grande per coprirli tutti.Mettere i pacchi dello stesso quartiere in un'unica cassa di consegna.
Livello radiceQuesto raggruppamento continua verso l'alto fino a quando tutti i dati sono coperti da un unico MBR principale.Caricamento di tutte le casse su un unico camion a lunga percorrenza.

Con questa struttura, la complessitΓ  delle interrogazioni spaziali passa da una scansione completa O(n) a O(log n). In pratica, le interrogazioni su milioni di record possono passare da centinaia di millisecondi a pochi millisecondi, senza perdere in precisione.

Come vengono eseguite le query: Filtraggio in due fasi

Per bilanciare velocitΓ  e correttezza, Milvus utilizza una strategia di filtraggio a due fasi:

  • Filtro grezzo: l'indice R-Tree controlla innanzitutto se il rettangolo di delimitazione della query si sovrappone ad altri rettangoli di delimitazione presenti nell'indice. In questo modo si rimuove rapidamente la maggior parte dei dati non correlati e si mantiene solo un piccolo insieme di candidati. PoichΓ© questi rettangoli sono forme semplici, il controllo Γ¨ molto veloce, ma puΓ² includere alcuni risultati che non corrispondono effettivamente.
  • Filtro fine: i candidati rimanenti vengono controllati con GEOS, la stessa libreria geometrica utilizzata da sistemi come PostGIS. GEOS esegue calcoli geometrici esatti, ad esempio se le forme si intersecano o se una contiene l'altra, per produrre risultati finali corretti.

Milvus accetta dati geometrici in formato WKT (Well-Known Text) ma li memorizza internamente come WKB (Well-Known Binary). Il formato WKB Γ¨ piΓΉ compatto, il che riduce la memorizzazione e migliora l'I/O. I campi GEOMETRY supportano anche la memorizzazione in memory-mapped (mmap), in modo che i grandi insiemi di dati spaziali non debbano stare interamente nella RAM.

Miglioramenti delle prestazioni con R-Tree

La latenza delle query rimane invariata con la crescita dei dati.

Senza un indice R-Tree, il tempo di interrogazione scala linearmente con la dimensione dei dati: un numero di dati 10 volte superiore significa query circa 10 volte piΓΉ lente.

Con R-Tree, il tempo di interrogazione cresce in modo logaritmico. Su set di dati con milioni di record, il filtraggio spaziale puΓ² essere da decine a centinaia di volte piΓΉ veloce di una scansione completa.

La precisione non viene sacrificata per la velocitΓ 

L'R-Tree restringe i candidati in base al riquadro di delimitazione, quindi GEOS controlla ciascuno di essi con la matematica della geometria esatta. Tutto ciΓ² che sembra corrispondere, ma in realtΓ  non rientra nell'area di ricerca, viene eliminato nel secondo passaggio.

Il rendimento della ricerca ibrida migliora

L'R-Tree rimuove prima i record al di fuori dell'area di destinazione. Milvus esegue quindi la similaritΓ  vettoriale (L2, IP o coseno) solo sui candidati rimanenti. Un minor numero di candidati significa un costo di ricerca inferiore e un aumento delle query al secondo (QPS).

Per iniziare: GEOMETRIA con l'SDK Python

Definire la collezione e creare gli indici

Per prima cosa, definire un campo DataType.GEOMETRY nello schema della collezione. Questo permette a Milvus di memorizzare e interrogare i dati geometrici.

from pymilvus import MilvusClient, DataType  
import numpy as np  
# Connect to Milvus  
milvus_client = MilvusClient("[http://localhost:19530](http://localhost:19530)")  
collection_name = "lb_service_demo"  
dim = 128  
# 1. Define schema  
schema = milvus_client.create_schema(enable_dynamic_field=True)  
schema.add_field("id", DataType.INT64, is_primary=True)  
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=dim)  
schema.add_field("location", DataType.GEOMETRY)  # Define geometry field  
schema.add_field("poi_name", DataType.VARCHAR, max_length=128)  
# 2. Create index parameters  
index_params = milvus_client.prepare_index_params()  
# Create an index for the vector field (e.g., IVF_FLAT)  
index_params.add_index(  
   field_name="vector",  
   index_type="IVF_FLAT",  
   metric_type="L2",  
   params={"nlist": 128}  
)  
# Create an R-Tree index for the geometry field (key step)  
index_params.add_index(  
   field_name="location",  
   index_type="RTREE"  # Specify the index type as RTREE  
)  
# 3. Create collection  
if milvus_client.has_collection(collection_name):  
   milvus_client.drop_collection(collection_name)  
milvus_client.create_collection(  
   collection_name=collection_name,  
   schema=schema,  
   index_params=index_params,  # Create the collection with indexes attached  
   consistency_level="Strong"  
)  
print(f"Collection {collection_name} created with R-Tree index.")  

Inserire i dati

Quando si inseriscono i dati, i valori geometrici devono essere in formato WKT (Well-Known Text). Ogni record include la geometria, il vettore e altri campi.

# Mock data: random POIs in a region of Beijing  
data = []  
# Example WKT: POINT(longitude latitude)  
geo_points = [  
   "POINT(116.4074 39.9042)",  # Near the Forbidden City  
   "POINT(116.4600 39.9140)",  # Near Guomao  
   "POINT(116.3200 39.9900)",  # Near Tsinghua University  
]  
for i, wkt in enumerate(geo_points):  
   vec = np.random.random(dim).tolist()  
   data.append({  
       "id": i,  
       "vector": vec,  
       "location": wkt,  
       "poi_name": f"POI_{i}"  
   })  
res = milvus_client.insert(collection_name=collection_name, data=data)  
print(f"Inserted {res['insert_count']} entities.")  

Esecuzione di una query spaziale-vettoriale ibrida (esempio)

Scenario: trovare i 3 POI piΓΉ simili nello spazio vettoriale e situati entro 2 chilometri da un determinato punto, ad esempio la posizione dell'utente.

Utilizzare l'operatore ST_DWITHIN per applicare il filtro della distanza. Il valore della distanza Γ¨ specificato in metri.

# Load the collection into memory  
milvus_client.load_collection(collection_name)  
# User location (WKT)  
user_loc_wkt = "POINT(116.4070 39.9040)"  
search_vec = np.random.random(dim).tolist()  
# Build the filter expression: use ST_DWITHIN for a 2000-meter radius filter  
filter_expr = f"ST_DWITHIN(location, '{user_loc_wkt}', 2000)"  
# Execute the search  
search_res = milvus_client.search(  
   collection_name=collection_name,  
   data=[search_vec],  
   filter=filter_expr,  # Inject geometry filter  
   limit=3,  
   output_fields=["poi_name", "location"]  
)  
print("Search Results:")  
for hits in search_res:  
   for hit in hits:  
       print(f"ID: {hit['id']}, Score: {hit['distance']:.4f}, Name: {hit['entity']['poi_name']}")  

Suggerimenti per l'uso in produzione

  • Creare sempre un indice R-Tree sui campi GEOMETRIA. Per i set di dati che superano le 10.000 entitΓ , i filtri spaziali senza un indice RTREE passano a una scansione completa e le prestazioni diminuiscono drasticamente.
  • Utilizzare un sistema di coordinate coerente. Tutti i dati di localizzazione devono utilizzare lo stesso sistema (ad esempio, WGS84). La commistione dei sistemi di coordinate non consente di calcolare la distanza e il contenimento.
  • Scegliere l'operatore spaziale giusto per la query. ST_DWITHIN per ricerche "entro X metri". ST_CONTAINS o ST_WITHIN per i controlli di geofencing e contenimento.
  • I valori geometrici NULL vengono gestiti automaticamente. Se il campo GEOMETRY Γ¨ nullo (nullable=True), Milvus salta i valori nulli durante le interrogazioni spaziali. Non Γ¨ necessaria alcuna logica di filtraggio aggiuntiva.

Requisiti per la distribuzione

Per utilizzare queste funzioni in produzione, assicurarsi che l'ambiente soddisfi i seguenti requisiti.

1. Versione di Milvus

È necessario eseguire Milvus 2.6.4 o versione successiva. Le versioni precedenti non supportano DataType.GEOMETRY o il tipo di indice RTREE.

2. Versioni SDK

  • PyMilvus: aggiornare alla versione piΓΉ recente (si consiglia la serie 2.6.x ). È necessario per la corretta serializzazione di WKT e per il passaggio dei parametri dell'indice RTREE.
  • SDK Java / Go / Node: controllare le note di rilascio di ciascun SDK e verificare che siano allineate alle definizioni del proto 2.6.4.

3. Librerie geometriche integrate

Il server Milvus include giΓ  Boost.Geometry e GEOS, quindi non Γ¨ necessario installare queste librerie.

4. Uso della memoria e pianificazione della capacitΓ 

Gli indici R-Tree utilizzano molta memoria. Quando si pianifica la capacitΓ , occorre tenere conto degli indici geometrici e di quelli vettoriali come HNSW o IVF. Il campo GEOMETRY supporta la memorizzazione memory-mapped (mmap), che puΓ² ridurre l'uso della memoria mantenendo parte dei dati su disco.

Conclusione

La ricerca semantica basata sulla posizione ha bisogno di qualcosa di piΓΉ che imbullonare un filtro geografico a una query vettoriale. Richiede tipi di dati spaziali integrati, indici adeguati e un motore di query in grado di gestire insieme posizione e vettori.

Milvus 2.6.4 risolve questo problema con campi GEOMETRIA nativi e indici R-Tree. Il filtraggio spaziale e la ricerca vettoriale vengono eseguiti in un'unica query, su un unico archivio di dati. L'R-Tree gestisce una rapida potatura spaziale, mentre GEOS garantisce risultati esatti.

Per le applicazioni che necessitano di un recupero consapevole della posizione, questo elimina la complessitΓ  di gestire e sincronizzare due sistemi separati.

Se state lavorando a una ricerca spaziale e vettoriale ibrida o consapevole della posizione, ci piacerebbe conoscere la vostra esperienza.

Avete domande su Milvus? Unitevi al nostro canale Slack o prenotate una sessione di 20 minuti di Milvus Office Hours.

    Try Managed Milvus for Free

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

    Get Started

    Like the article? Spread the word

    Continua a Leggere