pgvector : la ricerca vettoriale in PostgreSQL
pgvector è un'estensione open source di PostgreSQL (licenza PostgreSQL, permissiva) che aggiunge l'archiviazione e la ricerca di vettori a un database che già amministri, con colonne indicizzabili fino a 2.000 dimensioni (4.000 in mezza precisione). Per un corpus locale di alcune centinaia di migliaia di frammenti, significa un servizio in meno da gestire e filtri SQL che funzionano, senza una sincronizzazione da mantenere con i tuoi dati relazionali.
pgvector è un'estensione di PostgreSQL che aggiunge l'archiviazione e la ricerca di vettori a un database che già amministri. Per la maggior parte dei progetti di ricerca documentale locale, significa un servizio in meno da tenere in esecuzione, un backup in meno da organizzare e filtri SQL che funzionano davvero — anche per i diritti di accesso. Il progetto, mantenuto sotto licenza PostgreSQL e ospitato su GitHub, contava più di 23.000 stelle a fine settembre 2026, alla versione 0.8.6, compatibile con PostgreSQL 13 e versioni successive.
#Argomento: non aggiungere un servizio
Un'installazione locale per la gestione dei documenti esegue già un server per il modello, una fase di codifica e un sistema di archiviazione dei documenti. Aggiungere un database vettoriale dedicato significa avere un container in più, una porta in più, un backup in più e un altro elemento che può perdere la sincronizzazione con i tuoi dati relazionali quando viene eliminato un documento.
Se PostgreSQL è già presente — e in un'applicazione aziendale lo è quasi sempre — pgvector elimina tutta questa categoria di problemi. I tuoi segmenti di testo risiedono in una tabella accanto ai documenti da cui provengono, con chiavi esterne che ne mantengono la coerenza, e una cancellazione si propaga come ti aspetti, senza dover scrivere né monitorare un'attività di pulizia separata. Il progetto aggiunge inoltre la ricerca esatta e approssimata, i vettori a precisione singola, a mezza precisione, binari e sparsi, cinque distanze (L2, prodotto scalare, coseno, L1, Hamming, Jaccard) ed eredita gratuitamente la conformità ACID, il ripristino a un punto nel tempo e le join di PostgreSQL.
#Come funziona in pratica
I tuoi documenti, la tua IA: un RAG locale affidabile sui tuoi PDF, sulle tue note e sulle tue email — senza inviare nulla nel cloud.
- Spazio online a vita
- PDF + file
- Aggiornamenti a vita
Salvi una colonna di vettori accanto alle tue colonne abituali. Una query ordina le righe in base alla distanza dal vettore della domanda e restituisce quelle più vicine. Tre operatori di distanza coprono i casi comuni, e quello che scegli deve corrispondere alla convenzione del modello di embedding: è la causa più frequente di risultati mediocri che passano inosservati. Per i vettori normalizzati a lunghezza 1 (come quelli di OpenAI e della maggior parte dei modelli di embedding recenti), il prodotto scalare è il più veloce da calcolare e dà lo stesso ordinamento del coseno.
| Elemento | Cos'è | Da monitorare |
|---|---|---|
| Colonna vettoriale | Un array di float a dimensione fissa | La dimensione deriva dal modello di embedding e non cambia senza ricodificare tutto |
| Operatore di distanza | Coseno, prodotto scalare o distanza euclidea (L2) | Deve corrispondere al modello |
| Indice HNSW | Indice basato su un grafo, query rapide | Costruzione lenta e con un elevato consumo di memoria; la scelta predefinita ragionevole dalla versione 0.5 |
| Indice IVFFlat | Indice basato su partizioni, poco costoso da costruire | Da creare una volta che sono presenti dati rappresentativi |
| Nessun indice | Scansione esatta di tutte le righe | Del tutto fattibile fino a qualche decina di migliaia di righe |
#SQL minimo per iniziare
- 01Attivare l'estensioneCREATE EXTENSION IF NOT EXISTS vector; — un'unica istruzione, da eseguire una volta per ogni database.
- 02Aggiungere la colonnaALTER TABLE chunks ADD COLUMN embedding vector(1024); — la dimensione deve corrispondere esattamente a quella del modello di embedding utilizzato.
- 03Caricare i dati prima di indicizzarliUn caricamento in massa tramite COPY è più veloce senza un indice già esistente; crea l'indice quando è presente una quantità rappresentativa di righe.
- 04Creare l'indiceCREATE INDEX CONCURRENTLY ON chunks USING hnsw (embedding vector_cosine_ops); — l'opzione CONCURRENTLY evita di bloccare le scritture durante la costruzione dell'indice, che richiede molto tempo su una tabella di grandi dimensioni.
- 05InterrogareSELECT contenu FROM chunks WHERE document_id IN (SELECT id FROM documents WHERE utilisateur_autorise($1)) ORDER BY embedding <=> $2 LIMIT 5; — filtro di autorizzazione e ordinamento per similarità nella stessa query.
#Le limitazioni di dimensione, in pratica
pgvector definisce quattro tipi di colonne, ciascuno con il proprio limite di dimensioni indicizzabili. Il tipo vector standard (precisione singola, 4 byte per elemento) è indicizzabile fino a 2 000 dimensioni, il che copre la maggior parte dei modelli di embedding open source comuni (da 384 a 1 024 dimensioni). Un modello più ampio come text-embedding-3-large di OpenAI, con 3 072 dimensioni per impostazione predefinita, supera questo limite: la soluzione documentata è ridurre la dimensionalità durante la generazione dell'embedding (l'API lo consente) oppure passare al tipo halfvec, che memorizza a mezza precisione (2 byte per elemento, metà dello spazio) ed è indicizzabile fino a 4 000 dimensioni. Il tipo bit (vettori binari, distanze di Hamming o Jaccard) arriva a 64 000 dimensioni indicizzabili, e sparsevec (vettori sparsi) a 1 000 elementi non nulli indicizzati — oltre questi limiti, PostgreSQL memorizza comunque la colonna (fino a 16 000 dimensioni per vector, halfvec e sparsevec) ma senza poterla indicizzare, tornando quindi a una scansione esatta.
#Il filtraggio e i diritti di accesso
Una domanda reale raramente riguarda l'intero corpus: si vogliono i passaggi di questo servizio, successivi a questa data, nei documenti che questo utente ha il diritto di leggere. In un database vettoriale dedicato, si tratta di un filtro sui metadati con la sua sintassi e i suoi casi limite. In PostgreSQL, si tratta di una clausola WHERE affiancata a un ordinamento per similarità, con un collegamento alla tua tabella degli utenti se necessario.
Un'insidia documentata dal progetto stesso merita di essere conosciuta prima di scoprirla in produzione: con un indice approssimativo (HNSW o IVFFlat), il filtro viene applicato dopo la scansione dell'indice, non prima. Se una condizione seleziona solo il 10 % delle righe e il parametro predefinito hnsw.ef_search vale 40, vengono restituite in media solo 4 righe, non le dieci richieste. La soluzione ufficiale, disponibile dalla versione 0.8.0, si chiama scansione iterativa dell'indice (SET hnsw.iterative_scan = strict_order) e riavvia automaticamente la scansione fino a trovare abbastanza risultati, anziché restituire un insieme troncato senza segnalarlo.
#I limiti
- La memoria su larga scala
- Milioni di vettori a precisione piena occupano molto spazio; halfvec e la quantizzazione binaria riducono l'ingombro, ma i motori dedicati spingono nativamente la compressione ancora oltre. È la differenza più marcata.
- Tempo di costruzione dell'indice
- Costruire un indice HNSW su una tabella molto grande richiede tempo e molte risorse; in produzione, farlo con CREATE INDEX CONCURRENTLY evita di bloccare le scritture durante l'operazione.
- La contesa delle risorse
- Eseguire ricerche vettoriali pesanti insieme al tuo carico transazionale significa far gestire entrambi allo stesso server. Le repliche di lettura aiutano; separare i ruoli aiuta ancora di più.
- La dimensione dei vettori
- I vettori indicizzati hanno un limite in base al loro tipo (2.000 per vector, 4.000 per halfvec). I modelli comuni rientrano nei limiti; un modello con dimensionalità molto elevata deve essere ridotto o quantizzato.
- La ricerca ibrida
- PostgreSQL supporta la ricerca full-text (tsvector) e puoi combinarla con la distanza vettoriale, ma spetta a te rendere il tutto agevole da usare: devi eseguire le due query separatamente e poi fondere le classifiche, per esempio con una fusione dei ranghi reciproci (Reciprocal Rank Fusion), anziché ottenere un punteggio ibrido nativo in un'unica query.
- La scalabilità orizzontale
- Per andare oltre un singolo server, il percorso documentato prevede repliche PostgreSQL di sola lettura oppure uno strumento di distribuzione come Citus o PgDog — un componente in più, contrariamente all'argomento iniziale.
#pgvector o un database dedicato
La domanda non è quale sia oggettivamente migliore, ma quale corrisponda alla tua situazione attuale. pgvector è la scelta vincente quando PostgreSQL è già la fonte di riferimento dell'applicazione: fatturazione, account, documenti sorgente. Un motore dedicato è la scelta vincente quando il volume di vettori o il numero di richieste per unità di tempo supera ciò che un singolo server transazionale può gestire senza compromettere il resto dell'applicazione, oppure quando il team preferisce isolare il componente IA dal resto del sistema informativo per ragioni operative anziché di pura prestazione.
| Situazione | Scelta |
|---|---|
| PostgreSQL già in uso, meno di qualche centinaio di migliaia di segmenti | pgvector, comodamente |
| I vettori devono restare coerenti con dati relazionali | pgvector: le transazioni lo fanno gratuitamente |
| Filtraggio granulare basato sulle autorizzazioni esistenti | pgvector |
| Modello di embedding con più di 4.000 dimensioni senza riduzione possibile | Verificare il tipo sparsevec o un database dedicato progettato per questo caso |
| Milioni di vettori, molte richieste | Un motore dedicato (Qdrant, Milvus) |
| Prototipo in un notebook | Uno qualsiasi, questa scelta è reversibile |
- Qdrant: la base vettoriale dedicata
- Milvus, quando il volume supera quanto pgvector può gestire
- FAISS: la libreria dietro la ricerca vettoriale
- Costruire la catena RAG completa
- Scegliere il modello di embedding
- Il kit RAG locale QuelLLM: tutti i componenti in una pagina
- Fonte: repository ufficiale pgvector su GitHub
- Fonte: documentazione degli indici e dei tipi pgvector
- Fonte: guida di scalabilità pgvector
#FAQ
pgvector è abbastanza veloce per il RAG?+
pgvector o Qdrant?+
Quale indice scegliere, HNSW o IVFFlat?+
Posso filtrare per metadati?+
Che succede se cambio il modello di embedding?+
Il mio modello di embedding ha più di 2.000 dimensioni, cosa fare?+
Come diagnosticare una query vettoriale lenta?+
Un feedback, un errore, una precisazione? Facci sapere, così la guida migliora per tutti.