pgvector: Přeměňte PostgreSQL na vektorovou databázi
V roce 2026 se mantra komunity stala jasnou: „Stačí použít Postgres“. Snowflake získal Crunchy Data za 250 milionů dolarů, Databricks investoval 1 miliarda na Neonu a Supabase dosáhla ocenění 5 miliard. PostgreSQL ne a více jen relační databáze: with pgvector, stává se vektorovou databází úplné, schopné spravovat vkládání, vyhledávání podobností a operace AI bez přidávání jediná služba do vašeho zásobníku.
Pokud již PostgreSQL používáte (a statisticky ano), nepotřebujete Pinecone, Qdrant nebo Weaviate, abyste mohli začít s vyhledáváním vektorů. V tomto článku budeme stavět kompletní systém pro vyhledávání vektorů od nuly: od instalace pgvector až po vytváření optimalizovaných indexů prostřednictvím generování vložení a integrace s LangChain.
Přehled série
| # | Položka | Soustředit |
|---|---|---|
| 1 | Jste zde - pgvector | Instalace, operátoři, indexace |
| 2 | Vložení do hloubky | Modely, dělení, rozměry |
| 3 | RAG s PostgreSQL | End-to-end potrubí RAG |
| 4 | Hybridní vyhledávání | Vektory + fulltextové vyhledávání |
| 5 | Škálování pgvector | Rozdělení, dělení, výkon |
| 6 | pgvector ve výrobě | Monitoring, zálohování, CI/CD |
Co se naučíte
- Co je pgvector a proč je nejdůležitějším rozšířením PostgreSQL roku 2026
- Jak nainstalovat pgvector na Linux, Docker a spravované služby (Supabase, Neon, AWS RDS)
- Jak vytvořit tabulky s vektorovými sloupci a vložit vložení
- Tři operátory vzdálenosti: kosinus, L2 a vnitřní produkt
- Jak spouštět efektivní vyhledávací dotazy podobnosti
- Jak generovat vložení pomocí Pythonu (OpenAI a Sentence Transformers)
- HNSW vs IVFFlat: který index zvolit a jak jej nakonfigurovat
- Benchmark pgvector vs vyhrazené vektorové databáze
- Kompletní end-to-end příklad s Pythonem
- Integrace s LangChain pro systémy RAG
1. Trend „Just Use Postgres“ v roce 2026
Svět umělé inteligence po léta tlačí na specializované vektorové databáze: Pinecone, Weaviate, Qdrant, Milvus. Zdálo se, že každý projekt RAG vyžaduje novou službu, kterou bude spravovat, monitorovat a platit. V letech 2025-2026 se ale něco radikálně změnilo.
Komunita pochopila, že i vektory nejsou typem databáze, ale a datový typ. Stejně jako PostgreSQL spravuje JSON, pole, geometrie a texty s fulltextovým vyhledáváním si poradí i s vysokorozměrnými vektory. Rozšíření, které to vše umožňuje, říká se pgvector.
proč „Just Use Postgres“ v roce 2026
| Faktor | Vyhrazená vektorová databáze | PostgreSQL + pgvector |
|---|---|---|
| Infrastruktura | Nová služba ke správě | Rozšíření do stávající DB |
| Náklady | Samostatný tarif (borová šiška od 70 $ měsíčně) | Zahrnuto v ceně PostgreSQL |
| Konzistence dat | Je vyžadována synchronizace mezi databázemi | Nativní ACID transakce |
| Dotazy | Proprietární API | Standardní SQL + JOIN, WHERE, GROUP BY |
| Zálohy | Samostatný systém | pg_dump zahrnuje vše |
| Tým | Požadují se specifické dovednosti | Každý, kdo zná SQL |
Klíčovou výhodou je provozní jednoduchost. S pgvector, vaše vložení žijí ve stejné tabulce jako vaše relační data. Můžete PŘIPOJIT vektory a metadata, používejte klauzuli WHERE pro filtrování a mají transakční konzistenci. Žádné externí služby od synchronizace, žádná různá rozhraní API, která byste se měli učit.
2. Co je pgvector
pgvector a open-source rozšíření pro PostgreSQL, které přidává podporu nativní pro vysokorozměrné vektory a podobnostní vyhledávání. Vytvořil Andrew Kane v roce 2021 a rychle se stal nejstahovanějším rozšířením PostgreSQL pro případy použití AI/ML.
Pomocí pgvector můžete:
- Uložte vektory (vložení) jako nativní datový typ do sloupce tabulky
- Provádějte podobnostní vyhledávání pomocí tří různých metrik vzdálenosti
- Vytvářejte specializované indexy (HNSW a IVFFlat) pro rychlé vyhledávání
- Kombinujte vektorové vyhledávání se vším, co PostgreSQL nabízí: JOINy, transakce, spouštěče, materializované pohledy
pgvector v číslech (2026)
| Metrický | Hodnota |
|---|---|
| Aktuální verze | 0.8.0+ (s iterativním prohledáváním indexů) |
| Max. velikost nosiče | 16 000 |
| Typy indexů | HNSW, IVFFlat |
| Vektorové typy | vektor, halfvec, sparsevec, bit |
| Metriky vzdálenosti | Kosin, L2 (euklidovský), vnitřní produkt |
| Podporováno | AWS RDS, Supabase, Neon, Google Cloud SQL, Azure |
| Licence | PostgreSQL licence (open-source) |
Verze 0.8.0, vydaná v roce 2025, zavedla klíčovou funkci: gli iterativní indexové skenování. Tato funkce řeší problém přefiltrování, to znamená, když vektorový index nevrací dostatek výsledků, protože většina je vyřazen filtry WHERE. S iterativním skenováním pokračuje pgvector v prozkoumávání indexu dokud nenajdete dostatek výsledků, které odpovídají filtrům, čímž se výrazně zlepší kvalita filtrovaných dotazů.
3. Instalace pgvector
pgvector se instaluje různými způsoby v závislosti na vašem prostředí. Podívejme se na tři přístupy ty hlavní: nativní instalace na Linux, Docker a spravované služby.
3.1 Instalace na Ubuntu/Debian
# Prerequisiti: PostgreSQL 14+ già installato
sudo apt-get update
sudo apt-get install -y postgresql-server-dev-16
# Clona e compila pgvector
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install
# Abilita l'estensione nel tuo database
sudo -u postgres psql -d il_tuo_database -c "CREATE EXTENSION vector;"
Pro PostgreSQL 17 nahraďte postgresql-server-dev-16 con
postgresql-server-dev-17. pgvector podporuje PostgreSQL od verze 13
v 17 hodin.
3.2 Instalace pomocí Dockeru
Nejrychlejší způsob, jak začít. Oficiální obrázek pgvector/pgvector
obsahuje PostgreSQL s předinstalovaným pgvector.
# docker-compose.yml
version: '3.8'
services:
postgres:
image: pgvector/pgvector:pg17
environment:
POSTGRES_DB: vectordb
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret_password
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
pgdata:
-- init.sql: eseguito automaticamente al primo avvio
CREATE EXTENSION IF NOT EXISTS vector;
# Avvio rapido senza docker-compose
docker run -d \
--name pgvector-db \
-e POSTGRES_DB=vectordb \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
pgvector/pgvector:pg17
# Connetti e abilita pgvector
docker exec -it pgvector-db psql -U postgres -d vectordb \
-c "CREATE EXTENSION vector;"
3.3 Spravované služby (nulové nastavení)
Pokud nechcete spravovat infrastrukturu, několik cloudových služeb nabízí PostgreSQL pgvector již povolen. To je ideální volba pro výrobu.
Spravované služby pomocí pgvector
| Servis | pgvector Zahrnuto | Plán zdarma | Poznámky |
|---|---|---|---|
| Superbase | Předinstalovaný | Ano (500 MB) | Dashboard UI, automatická REST API |
| Neon | Předinstalovaný | Ano (0,5 GB) | Bezserverové, pobočkové databáze |
| AWS RDS | Chcete-li být povoleny | No | pgvector 0.8.0 na Aurora PostgreSQL |
| Google Cloud SQL | Chcete-li být povoleny | No | podpora pgvector 0.8.0 |
| Azure Database | Chcete-li být povoleny | No | Flexibilní server s pgvector |
-- Su Supabase, pgvector e già disponibile.
-- Basta abilitare l'estensione:
CREATE EXTENSION IF NOT EXISTS vector;
-- Verifica l'installazione
SELECT extversion FROM pg_extension WHERE extname = 'vector';
-- Risultato: 0.8.0
4. Vytvořte tabulku s vektory
S nainstalovaným pgvector můžete přidat sloupce typu vector(n) k tvému
tabulky, kde n a rozměrnost vektoru. Hodnota n
Záleží na modelu vkládání, který používáte: OpenAI text-embedding-3-small vyrábí
1536 rozměrových vektorů, zatímco text-embedding-3-large jde až na 3072.
-- Abilita l'estensione (se non già fatto)
CREATE EXTENSION IF NOT EXISTS vector;
-- Tabella documenti per un sistema RAG
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
content TEXT NOT NULL,
source VARCHAR(255),
category VARCHAR(100),
embedding vector(1536),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Aggiungi un commento alla colonna per documentazione
COMMENT ON COLUMN documents.embedding IS
'Embedding generato con OpenAI text-embedding-3-small (1536 dim)';
Vložit dokumenty s vložením
Vkládání funguje jako normální INSERT a předává vektor jako řetězec hodnot oddělené čárkou v hranatých závorkách.
-- Inserimento singolo
INSERT INTO documents (title, content, source, embedding)
VALUES (
'Introduzione a PostgreSQL',
'PostgreSQL e un database relazionale open-source potente e affidabile...',
'docs/postgres-intro.md',
'[0.023, -0.045, 0.067, 0.089, -0.012, ...]' -- vettore a 1536 dimensioni
);
-- Inserimento multiplo (batch)
INSERT INTO documents (title, content, source, category, embedding)
VALUES
('Capitolo 1', 'Contenuto cap 1...', 'libro.pdf', 'tutorial',
'[0.11, -0.22, 0.33, ...]'),
('Capitolo 2', 'Contenuto cap 2...', 'libro.pdf', 'tutorial',
'[0.44, -0.55, 0.66, ...]'),
('FAQ', 'Domande frequenti...', 'faq.md', 'supporto',
'[-0.12, 0.34, -0.56, ...]');
Velikost vektoru
Rozměr zadaný v definici sloupce (vector(1536))
musí přesně odpovídat velikosti vložených prvků. Pokus
pro vložení 768rozměrného vektoru do sloupce vector(1536) způsobí
chyba. Vyberte velikost na základě šablony pro vkládání, kterou plánujete použít.
Rozměry oblíbených modelů vkládání
| Model | Poskytovatelé | Rozměry | Cena / 1 milion tokenu |
|---|---|---|---|
| text-embedding-3-small | OpenAI | 1536 | 0,02 USD |
| text-embedding-3-velký | OpenAI | 3072 | 0,13 USD |
| vše-MiniLM-L6-v2 | HuggingFace (zdarma) | 384 | Zdarma (místní) |
| all-mpnet-base-v2 | HuggingFace (zdarma) | 768 | Zdarma (místní) |
| plavba - 3 | Voyage AI | 1024 | 0,06 USD |
5. Operátoři na dálku
pgvector nabízí tři operátory pro výpočet vzdálenosti mezi vektory. Každý operátor odpovídá jiné matematické metrice a má specifické případy použití.
Tři operátoři pgvector
| Operátor | Metrický | Vzorec | Řazení | Use Case |
|---|---|---|---|---|
<=> |
Kosinusová vzdálenost | 1 - kosinusová_podobnost | ASC (0 = identické) | Text, normalizované vkládání |
<-> |
L2 (euklidovský) | sqrt(součet((a-b)^2)) | ASC (0 = identické) | Obrázky, prostorová data |
<#> |
Vnitřní produkt (zamítnuto) | -1 * dot_product | ASC (negativnější = podobnější) | Normalizované vektory, maximální výkon |
-- COSINE DISTANCE <=> (il più usato per testo)
-- Risultato: 0 = identici, 2 = opposti
SELECT title, content,
embedding <=> '[0.1, 0.2, ...]' AS cosine_distance
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]' ASC
LIMIT 5;
-- L2 (EUCLIDEA) <->
-- Risultato: 0 = identici, valori crescenti = più lontani
SELECT title, content,
embedding <-> '[0.1, 0.2, ...]' AS l2_distance
FROM documents
ORDER BY embedding <-> '[0.1, 0.2, ...]' ASC
LIMIT 5;
-- INNER PRODUCT (NEGATO) <#>
-- Risultato: valori più negativi = più simili
SELECT title, content,
(embedding <#> '[0.1, 0.2, ...]') * -1 AS similarity
FROM documents
ORDER BY embedding <#> '[0.1, 0.2, ...]' ASC
LIMIT 5;
Kterého operátora zvolit
Pro 90 % případů použití s textem a AI použijte <=> (kosinová vzdálenost).
Vkládání modelů, jako je OpenAI, vytváří normalizované vektory, což dělá
kosinusová vzdálenost a vnitřní ekvivalent produktu z hlediska výsledku. USA <->
(L2) pouze při práci s prostorovými daty nebo obrázky, kde záleží na velikosti vektoru.
Vnitřní produkt (<#>) a o něco rychlejší než kosinus, protože se vyhýbá
normalizace, ale pouze na již normalizovaných vektorech.
6. Podobnostní vyhledávací dotazy
Podobnostní vyhledávání je srdcem pgvectoru. Základní dotaz je jednoduchý: seřadit výsledky vzdáleností od vektoru dotazu a získat první K. Ale v produkci se dotazy stávají propracovanější díky kombinaci vektorového vyhledávání s SQL filtry.
6.1 Základní dotazy
-- Trova i 5 documenti più simili a un vettore query
SELECT
id,
title,
content,
1 - (embedding <=> $1) AS similarity -- $1 = vettore query
FROM documents
ORDER BY embedding <=> $1
LIMIT 5;
6.2 Dotazy s filtry (skutečná síla pgvectoru)
Zde pgvector září ve srovnání s vyhrazenými vektorovými databázemi. Hledání můžete kombinovat vektor s libovolnou klauzulí SQL: WHERE, JOIN, GROUP BY, poddotaz.
-- Filtra per categoria e soglia di similarità
SELECT
id, title, content,
1 - (embedding <=> $1) AS similarity
FROM documents
WHERE category = 'tutorial'
AND created_at > NOW() - INTERVAL '30 days'
ORDER BY embedding <=> $1
LIMIT 5;
-- JOIN con altre tabelle: trova documenti simili con info autore
SELECT
d.title,
d.content,
a.name AS author_name,
1 - (d.embedding <=> $1) AS similarity
FROM documents d
JOIN authors a ON d.author_id = a.id
WHERE a.verified = true
ORDER BY d.embedding <=> $1
LIMIT 10;
-- Esclusione: trova simili ma NON il documento stesso
SELECT
id, title,
1 - (embedding <=> (SELECT embedding FROM documents WHERE id = 42)) AS similarity
FROM documents
WHERE id != 42
ORDER BY embedding <=> (SELECT embedding FROM documents WHERE id = 42)
LIMIT 5;
6.3 Iterativní indexové skenování (pgvector 0.8.0)
Jednou z nejdůležitějších novinek verze 0.8.0 je podpora pro iterativní indexové skenování. Když zkombinujete vektorové vyhledávání s filtry WHERE omezující, index nemusí najít dostatek výsledků při prvním průchodu. Při iterativním skenování pokračuje pgvector ve skenování indexu, dokud není spokojen požadovaný LIMIT.
-- Abilita iterative scan per HNSW
SET hnsw.iterative_scan = relaxed_order; -- o strict_order
-- Imposta il limite massimo di tuple da scansionare
SET hnsw.max_scan_tuples = 20000;
-- Ora le query con filtri restrittivi funzionano correttamente
SELECT id, title,
1 - (embedding <=> $1) AS similarity
FROM documents
WHERE category = 'raro' -- categoria con pochi documenti
ORDER BY embedding <=> $1
LIMIT 10;
-- Senza iterative scan: potrebbe restituire 0-3 risultati
-- Con iterative scan: restituisce sempre fino a 10 risultati
-- Modalità disponibili:
-- off = comportamento tradizionale (default)
-- strict_order = mantiene l'ordine esatto delle distanze
-- relaxed_order = ordine approssimato (migliori performance)
Kdy použít iterativní skenování
- uvolněné_objednávky: ve většině případů nabízí nejlepší rovnováhu mezi výkonem a kvalitou
- přísné_pořadí: když je kritické přesné pořadí vzdáleností (např. pořadí výsledků pro uživatele)
- vypnuto: když nemáte žádné filtry WHERE nebo když filtry nejsou omezující
7. Generujte vložení pomocí Pythonu
Chcete-li zadat data do pgvector, musíte nejprve transformovat text na číselné vektory pomocí vkládací model. Podívejme se na dva přístupy: OpenAI API (placené, vysoce kvalitní) a Sentence Transformers (zdarma, místní).
7.1 S rozhraním OpenAI API
import openai
import psycopg2
from psycopg2.extras import execute_values
# Configura il client OpenAI
client = openai.OpenAI(api_key="sk-...")
def get_embedding(text: str, model: str = "text-embedding-3-small") -> list[float]:
"""Genera un embedding per un testo usando OpenAI."""
response = client.embeddings.create(
input=text,
model=model
)
return response.data[0].embedding # lista di 1536 float
# Connetti a PostgreSQL
conn = psycopg2.connect(
host="localhost",
database="vectordb",
user="admin",
password="secret_password"
)
cur = conn.cursor()
# Genera e inserisci embeddings
documents = [
("Introduzione a Python", "Python e un linguaggio di programmazione versatile..."),
("PostgreSQL Avanzato", "Le CTE ricorsive permettono di eseguire query gerarchiche..."),
("Docker per Sviluppatori", "I container Docker isolano le applicazioni..."),
]
for title, content in documents:
embedding = get_embedding(content)
cur.execute(
"INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s)",
(title, content, str(embedding))
)
conn.commit()
cur.close()
conn.close()
7.2 S převodníky vět (bezplatný a místní)
from sentence_transformers import SentenceTransformer
import psycopg2
import numpy as np
# Carica il modello (scaricato automaticamente la prima volta)
model = SentenceTransformer('all-MiniLM-L6-v2') # 384 dimensioni
# Genera embeddings per un batch di testi
texts = [
"Python e un linguaggio di programmazione versatile",
"Le CTE ricorsive permettono query gerarchiche in SQL",
"I container Docker isolano le applicazioni",
]
embeddings = model.encode(texts) # shape: (3, 384)
# Connetti e inserisci
conn = psycopg2.connect(
host="localhost", database="vectordb",
user="admin", password="secret_password"
)
cur = conn.cursor()
# NOTA: la colonna deve essere vector(384), non vector(1536)
for text, embedding in zip(texts, embeddings):
cur.execute(
"INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s)",
(text[:100], text, str(embedding.tolist()))
)
conn.commit()
cur.close()
conn.close()
OpenAI vs Sentence Transformers
| čekám | OpenAI API | Transformátory vět |
|---|---|---|
| Náklady | 0,02 $ / 1 milion tokenů | Uvolnit |
| kvalitní | Vynikající (nejmodernější) | Dobré (v mnoha případech dostačující) |
| Soukromí | Data byla odeslána do OpenAI | Vše místní, žádná data nevycházejí |
| Rychlost | ~100 ms na požadavek (síť) | ~10 ms pro text (s GPU) |
| Offline | Ne (vyžaduje internet) | Ano (po prvním stažení) |
| Rozměry | 1536 nebo 3072 | 384 nebo 768 (v závislosti na modelu) |
Zlaté pravidlo vkládání
Použijte to stejný model vkládání jak pro indexování dokumentů, tak pro
pro vygenerování vektoru dotazu. Vložení vytvořená pomocí různých modelů žijí v
různé vektorové prostory a nejsou srovnatelné. Pokud indexujete pomocí
text-embedding-3-small, musíte hledat se stejným modelem.
8. Indexování: HNSW vs IVFFlat
Bez indexu provádí pgvector sekvenční (brute force) porovnání skenování vektor dotazu s každým řádkem tabulky. To je 100% přesné, ale stává se to pomalé s velkými datovými sadami. Obětování indexů přibližného nejbližšího souseda (ANN). minimální procento přesnosti pro získání řádově rychlejšího vyhledávání.
8.1 Index HNSW
HNSW (Hierarchical Navigable Small World) vytváří víceúrovňový graf spojení mezi dopravci. A index doporučený pro většinu případů: rychlé čtení, dobrá přesnost a podporuje inkrementální vkládání bez rekonstrukce.
-- Indice HNSW con parametri di default
CREATE INDEX idx_documents_embedding_hnsw
ON documents
USING hnsw (embedding vector_cosine_ops);
-- Indice HNSW con parametri personalizzati
CREATE INDEX idx_documents_embedding_hnsw
ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (
m = 24, -- connessioni per nodo (default: 16, range: 2-100)
ef_construction = 128 -- candidati durante costruzione (default: 64, range: 4-1000)
);
-- Regola ef_search per le query (default: 40)
SET hnsw.ef_search = 100; -- più alto = più preciso ma più lento
Parametry HNSW: Průvodce konfigurací
| Parametr | Výchozí | Rozsah | Účinek | Poraďte |
|---|---|---|---|---|
m |
16 | 2–100 | Více připojení = přesnější, více paměti | 16-32 pro většinu případů |
ef_construction |
64 | 4–1000 | Vyšší = lepší index, pomalejší budování | 64–256 (jednorázové, vyplatí se zvýšit) |
ef_search |
40 | 1–1000 | Vyšší = přesnější, pomalejší vyhledávání | 40-200 na základě požadovaného kompromisu |
8.2 IVFFlat Index
IVFFlat (Inverted File with Flat komprese) rozděluje vektory do shluků a pouze prohledává v clusterech nejblíže dotazu. Staví se rychleji než HNSW, ale vyžaduje rekonstrukci, když přidáte spoustu nových dat. Ideální pro změnu datových sad zřídka.
-- IMPORTANTE: IVFFlat richiede dati nella tabella PRIMA di creare l'indice
-- (necessità di fare clustering k-means sui dati esistenti)
-- Indice IVFFlat
CREATE INDEX idx_documents_embedding_ivf
ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (
lists = 100 -- numero di cluster (default: 100)
);
-- Regola il numero di cluster da esplorare durante la ricerca
SET ivfflat.probes = 10; -- default: 1, consigliato: sqrt(lists)
-- Regola pratica per "lists":
-- rows < 1M: lists = rows / 1000
-- rows >= 1M: lists = sqrt(rows)
8.3 Operátoři podle typu vzdálenosti
Operátor zadaný při vytváření indexu se musí shodovat s operátorem používané v dotazech. Zde je kompletní mapa.
Mapové operátory a indexové třídy
| Vzdálenost | SQL operátor | Indexová třída (jejda) |
|---|---|---|
| Malé věci | <=> |
vector_cosine_ops |
| L2 (euklidovský) | <-> |
vector_l2_ops |
| Vnitřní produkt | <#> |
vector_ip_ops |
8.4 HNSW vs IVFFlat: který si vybrat
Srovnání HNSW vs IVFFlat
| čekám | HNSW | IVFFlat |
|---|---|---|
| Rychlost vyhledávání | Rychleji | Rychle |
| Přesnost (vyvolání) | ~95–99 % | ~90–98 % |
| Čas budování | Pomalý | Rychle |
| Paměť | Vysoký | Průměrný |
| Přírůstkové vkládání | Podporováno | Vyžadují REINDEX |
| Iterativní skenování | Ano (0.8.0) | Ano (0.8.0) |
| Ideální případ použití | Obecné použití, rostoucí data | Statické datové sady, rychlé sestavení |
Praktické rady
U většiny projektů, vyberte HNSW. A univerzálnější, podporuje přírůstkové vkládání bez přestavby a má verzi 0.8.0 pgvector výrazně zlepšil jeho výkon. Použijte IVFFlat pouze v případě, že čas konstrukce indexu a kritické (velmi velké datové sady načteny pouze jednou) o pokud máte přísná omezení paměti.
9. Výkon: pgvector vs vyhrazené vektorové databáze
Nejčastěji kladená otázka zní: "je pgvector dostatečně rychlý pro výrobu?". Odpověď v roce 2026 a jasno si, pro drtivou většinu případů použití. Podívejme se na čísla.
9.1 Srovnávací testy ve velkém měřítku
Benchmarky pgvectorscale (doplňkové rozšíření k pgvector vyvinuté společností Timescale) z 50 milionů dopravců vykazují působivé výsledky:
Referenční hodnota: 50 milionů vektorů při 99% obnově
| Systém | QPS (dotazy/s) | Odvolání | Poznámky |
|---|---|---|---|
| pgvectorscale | 471 | 99 % | 11,4x rychlejší než Qdrant |
| Qdrant | 41 | 99 % | Optimalizováno pro čistě vektorové vyhledávání |
9.2 Střední měřítko (1 milion vektorů)
Benchmark: 1M vektorů – propustnost
| Systém | Dotazy/sec | Vložky/sec | Spravované náklady |
|---|---|---|---|
| Borová šiška | ~5 000 | ~50 000 | Od 70 $/měsíc |
| Qdrant | ~4500 | ~45 000 | Vlastní hostování nebo cloud |
| pgvector | ~3000 | ~30 000 | Zahrnuto v ceně PG |
U 1M vektorů je pgvector mírně pomalejší v čisté propustnosti. Ale s ohledem že náklady jsou prakticky nulové (a již jsou zahrnuty ve vašem PostgreSQL), hlásí kvalita-cena a bezkonkurenční. Pro většinu webových aplikací 3000 dotazů za sekundu jsou více než dost.
Když pgvector NESTAČÍ
Zvažte vyhrazenou vektorovou databázi (Qdrant, Pinecone), když:
- Máte za sebou 50 milionů vektorů
- Potřebujete latence p99 pod i 5 ms
- Vaší pracovní zátěží je výhradně vektorové vyhledávání (žádná relační data)
- Potřebujete nativní distribuované sharding
Pro všechno ostatní je pgvector tou správnou volbou. Systém s 10 miliony vektorů s PostgreSQL již v zásobníku nevyžaduje žádnou další složitost.
10. Kompletní příklad: Knowledge Base s Pythonem
Pojďme si vše dát dohromady na praktickém příkladu. Vybudujeme znalostní základnu, která: indexuje dokumenty s vložením, umožňuje vyhledávání podobností a podporuje filtry podle kategorie.
"""
Knowledge Base con PostgreSQL + pgvector
Requisiti: pip install openai psycopg2-binary
"""
import openai
import psycopg2
from dataclasses import dataclass
# === Configurazione ===
OPENAI_API_KEY = "sk-..."
DB_CONFIG = {
"host": "localhost",
"database": "vectordb",
"user": "admin",
"password": "secret_password",
}
EMBEDDING_MODEL = "text-embedding-3-small"
EMBEDDING_DIM = 1536
@dataclass(frozen=True)
class SearchResult:
id: int
title: str
content: str
similarity: float
category: str
# === Funzioni di embedding ===
client = openai.OpenAI(api_key=OPENAI_API_KEY)
def get_embedding(text: str) -> list[float]:
"""Genera un embedding per un testo."""
response = client.embeddings.create(
input=text,
model=EMBEDDING_MODEL,
)
return response.data[0].embedding
def get_embeddings_batch(texts: list[str]) -> list[list[float]]:
"""Genera embeddings per un batch di testi (più efficiente)."""
response = client.embeddings.create(
input=texts,
model=EMBEDDING_MODEL,
)
return [item.embedding for item in response.data]
# === Setup del database ===
def setup_database() -> None:
"""Crea la tabella e gli indici."""
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
cur.execute("CREATE EXTENSION IF NOT EXISTS vector;")
cur.execute(f"""
CREATE TABLE IF NOT EXISTS kb_documents (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
content TEXT NOT NULL,
category VARCHAR(100) DEFAULT 'general',
embedding vector({EMBEDDING_DIM}),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
""")
cur.execute("""
CREATE INDEX IF NOT EXISTS idx_kb_embedding_hnsw
ON kb_documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 24, ef_construction = 128);
""")
cur.execute("""
CREATE INDEX IF NOT EXISTS idx_kb_category
ON kb_documents (category);
""")
conn.commit()
cur.close()
conn.close()
print("Database setup completato.")
# === Inserimento documenti ===
def insert_documents(
documents: list[dict],
batch_size: int = 50,
) -> None:
"""Inserisce documenti con embeddings generati automaticamente."""
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
for i in range(0, len(documents), batch_size):
batch = documents[i : i + batch_size]
texts = [doc["content"] for doc in batch]
embeddings = get_embeddings_batch(texts)
for doc, emb in zip(batch, embeddings):
cur.execute(
"""INSERT INTO kb_documents (title, content, category, embedding)
VALUES (%s, %s, %s, %s)""",
(doc["title"], doc["content"],
doc.get("category", "general"), str(emb)),
)
print(f"Inseriti {min(i + batch_size, len(documents))}/{len(documents)} documenti")
conn.commit()
cur.close()
conn.close()
# === Ricerca per similarità ===
def search(
query: str,
limit: int = 5,
category: str | None = None,
min_similarity: float = 0.3,
) -> list[SearchResult]:
"""Cerca documenti simili alla query."""
query_embedding = get_embedding(query)
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
# Abilita iterative scan per filtri restrittivi
cur.execute("SET hnsw.iterative_scan = relaxed_order;")
if category:
cur.execute(
"""SELECT id, title, content, category,
1 - (embedding <=> %s::vector) AS similarity
FROM kb_documents
WHERE category = %s
ORDER BY embedding <=> %s::vector
LIMIT %s""",
(str(query_embedding), category,
str(query_embedding), limit),
)
else:
cur.execute(
"""SELECT id, title, content, category,
1 - (embedding <=> %s::vector) AS similarity
FROM kb_documents
ORDER BY embedding <=> %s::vector
LIMIT %s""",
(str(query_embedding), str(query_embedding), limit),
)
results = [
SearchResult(
id=row[0], title=row[1], content=row[2],
category=row[3], similarity=row[4],
)
for row in cur.fetchall()
if row[4] >= min_similarity
]
cur.close()
conn.close()
return results
# === Main ===
if __name__ == "__main__":
# 1. Setup
setup_database()
# 2. Inserisci documenti di esempio
sample_docs = [
{
"title": "Introduzione a PostgreSQL",
"content": "PostgreSQL e un RDBMS open-source con supporto ACID completo.",
"category": "database",
},
{
"title": "Indici in PostgreSQL",
"content": "I B-tree sono il tipo di indice default. HNSW e usato per vettori.",
"category": "database",
},
{
"title": "Cos'è il RAG",
"content": "RAG combina retrieval e generation per risposte basate su documenti.",
"category": "ai",
},
{
"title": "Docker per Sviluppatori",
"content": "Docker isola le applicazioni in container leggeri e portabili.",
"category": "devops",
},
{
"title": "Embeddings e Vector Search",
"content": "Gli embeddings trasformano testo in vettori per la similarity search.",
"category": "ai",
},
]
insert_documents(sample_docs)
# 3. Cerca documenti
print("\n--- Ricerca: 'come funzionano i database vettoriali' ---")
results = search("come funzionano i database vettoriali", limit=3)
for r in results:
print(f" [{r.similarity:.3f}] {r.title} ({r.category})")
print("\n--- Ricerca filtrata per categoria 'ai' ---")
results = search("tutorial su PostgreSQL", limit=3, category="ai")
for r in results:
print(f" [{r.similarity:.3f}] {r.title} ({r.category})")
11. Integrace s LangChain
Pokud budujete systém RAG, LangChain nabízí přímou integraci s pgvector
prostřednictvím balíčku langchain-postgres. To vám umožní používat
PostgreSQL jako vektorový obchod bez ručního psaní SQL.
pip install langchain-postgres langchain-openai psycopg
from langchain_postgres import PGVector
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
# Configura il modello di embedding
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
openai_api_key="sk-...",
)
# NOTA: langchain-postgres usa psycopg3 (non psycopg2)
CONNECTION_STRING = "postgresql+psycopg://admin:secret@localhost:5432/vectordb"
# Crea il vector store
vector_store = PGVector(
embeddings=embeddings,
collection_name="langchain_docs",
connection=CONNECTION_STRING,
use_jsonb=True, # metadati JSONB per filtri efficienti
)
# Aggiungi documenti
docs = [
Document(
page_content="pgvector trasforma PostgreSQL in un vector database",
metadata={"source": "tutorial.md", "chapter": 1},
),
Document(
page_content="HNSW e l'indice consigliato per la maggior parte dei casi",
metadata={"source": "tutorial.md", "chapter": 2},
),
Document(
page_content="LangChain semplifica la costruzione di sistemi RAG",
metadata={"source": "guida-rag.md", "chapter": 1},
),
]
vector_store.add_documents(docs)
# Ricerca per similarità
results = vector_store.similarity_search(
"come creare un indice vettoriale",
k=3,
)
for doc in results:
print(f"[{doc.metadata['source']}] {doc.page_content[:80]}...")
# Ricerca con score
results_with_scores = vector_store.similarity_search_with_score(
"cos'è pgvector",
k=3,
)
for doc, score in results_with_scores:
print(f"[Score: {score:.4f}] {doc.page_content[:80]}...")
# Usa come retriever in una catena RAG
retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 5},
)
# Il retriever può essere usato direttamente nelle chain LangChain
relevant_docs = retriever.invoke("installazione pgvector docker")
Poznámka k psycopg3
Balíček langchain-postgres vyžaduje psychopg3 (ne psychopg2).
Připojovací řetězec musí mít formát postgresql+psycopg:// místo toho
z postgresql+psycopg2://. Pokud migrujete z langchain-community,
aktualizujte připojovací řetězec.
12. Nejlepší postupy pro pgvector ve výrobě
12.1 Velikost vektoru
Menší vektory zabírají méně místa, zrychlují indexy a snižují náklady.
OpenAI text-embedding-3-small (1536 dim) nabízí nejlepší hodnotu
kvalita-velikost pro většinu případů. Pokud dokážete tolerovat mírnou ztrátu
kvality, all-MiniLM-L6-v2 (384 dim) a skvělá svobodná volba.
12.2 Dávkové vložení
from psycopg2.extras import execute_values
# SBAGLIATO: un INSERT alla volta (lento)
for doc in documents:
cur.execute("INSERT INTO docs (content, embedding) VALUES (%s, %s)",
(doc.content, str(doc.embedding)))
# CORRETTO: batch insert con execute_values (10-50x più veloce)
data = [
(doc.content, str(doc.embedding))
for doc in documents
]
execute_values(
cur,
"INSERT INTO docs (content, embedding) VALUES %s",
data,
page_size=500, # righe per batch SQL
)
conn.commit()
12.3 Sdružování připojení
V produkci neotevírejte nové připojení PostgreSQL pro každý požadavek.
Použijte fond připojení jako PgBouncer nebo integrované sdružování
psycopg2.
from psycopg2 import pool
# Crea un pool di connessioni (all'avvio dell'applicazione)
connection_pool = pool.ThreadedConnectionPool(
minconn=5, # connessioni minime
maxconn=20, # connessioni massime
host="localhost",
database="vectordb",
user="admin",
password="secret_password",
)
# Usa una connessione dal pool
conn = connection_pool.getconn()
try:
cur = conn.cursor()
cur.execute("SELECT ... ORDER BY embedding <=> %s LIMIT 5", ...)
results = cur.fetchall()
cur.close()
finally:
connection_pool.putconn(conn) # restituisci al pool
12.4 Údržba
-- VACUUM per recuperare spazio dopo DELETE/UPDATE
VACUUM ANALYZE documents;
-- Ricostruisci l'indice IVFFlat dopo inserimenti massicci
REINDEX INDEX CONCURRENTLY idx_documents_embedding_ivf;
-- NOTA: HNSW non richiede REINDEX per nuovi inserimenti
-- Monitora la dimensione dell'indice
SELECT
indexname,
pg_size_pretty(pg_relation_size(indexname::regclass)) AS size
FROM pg_indexes
WHERE tablename = 'documents';
-- Verifica che l'indice venga usato
EXPLAIN ANALYZE
SELECT id, 1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 5;
-- Cerca "Index Scan using idx_..._hnsw" nell'output
Kontrolní seznam výroby
- Vytvořte index HNSW pomocí
m = 24eef_construction = 128 - Daň
ef_searchmezi 40 a 200 na základě kompromisu mezi latencí a přesností - Schopnost
hnsw.iterative_scan = relaxed_orderpokud používáte filtry WHERE - Použijte dávkovou vložku s
execute_valuespro masivní zatížení - Nastavení fondu připojení (PgBouncer nebo psycopg2.pool)
- Naplánovat
VACUUM ANALYZEperiodické - Monitorujte dotazy pomocí
EXPLAIN ANALYZEpro ověření použití indexu - USA
halfvecmístovectorušetřit 50 % místa (pokud je dostatečná přesnost float16)
Závěry
pgvector transformoval PostgreSQL z jednoduché relační databáze na platformu připravenou pro umělou inteligenci. S verzí 0.8.0 a jejím iterativním indexovým skenováním je mezera s vektorovými databázemi věnována se drasticky snížila au většiny projektů pod 10 milionů dopravců, není důvod přidávat do vašeho zásobníku samostatnou službu.
V tomto článku jste se naučili, jak nainstalovat pgvector, vytvářet tabulky s vektorovými sloupci, provádět podobnostní vyhledávání se třemi operátory vzdálenosti, generovat vložení pomocí Pythonu, nastavit indexy HNSW a IVFFlat a integrovat vše s LangChain. Viděli jste také benchmarky, které potvrzují výkonnost pgvectoru ve výrobě.
Nel další článek ponoříme se do nich hlouběji vložení: jak interně fungují, jak si vybrat správný model, chunking strategie pro dlouhé dokumenty a jak optimalizovat kvalitu vyhledávání. V třetí článek jednu postavíme Potrubí RAG dokončeno s PostgreSQL jako jediným backendem.
Další zdroje
- pgvector GitHub: github.com/pgvector/pgvector - Oficiální dokumentace a changelog
- pgvectorscale: github.com/timescale/pgvectorscale – Rozšíření o vylepšený výkon
- LangChain PGVector: python.langchain.com - oficiální integrace Pythonu
- Superbase Vector: supabase.com/docs/guides/ai - průvodce pgvector na Supabase
- Neon AI: neon.tech/docs/ai - pgvector na Neon serverless







