Porównanie rozszerzeń pgvector, pgvectorscale i VectorChord do wyszukiwania wektorowego w PostgreSQL
Wyszukiwanie wektorowe przekształca tekst w liczbowe embeddingi i znajduje dokumenty podobne pod względem znaczenia za pomocą metryk bliskości. Embeddingi słów o podobnym znaczeniu grupują się w przestrzeni N-wymiarowej. Klasyczny przykład: King - Man + Woman ≈ Queen pokazuje analogię wektorową.
Główne metryki:
- Podobieństwo kosinusowe: kąt między wektorami, znormalizowane wektory dają równoważność z odległością euklidesową.
- Odległość euklidesowa: prosta odległość między punktami.
Rozszerzenia PostgreSQL realizują wyszukiwanie ANN (przybliżony najbliższy sąsiad) z indeksami IVFFlat, HNSW i specjalistycznymi algorytmami.
Rozszerzenia do wyszukiwania wektorowego
pgvector
Otwarte rozszerzenie napisane w języku C z typem vector. Obsługuje podobieństwo kosinusowe, L2 oraz iloczyn skalarny. Indeksy:
- IVFFlat: klasteryzacja wektorów.
- HNSW: hierarchiczny graf, surowe wyszukiwanie od góry do dołu.
Wymaga pełnego załadowania indeksu do pamięci RAM.
pgvectorscale
Nadbudowa nad pgvector napisana w Rust (PGRX). Indeks StreamingDiskANN (adaptacja DiskANN) przechowuje dane na SSD, z niskim obciążeniem pamięci RAM. Kompresja SBQ (Statistical Binary Quantization).
Zgłoszony wzrost wydajności: 16-krotny przyrost przepustowości dla 50M wektorów o wymiarze 768.
pgvecto.rs
Całkowicie napisane w Rust, obsługa binary/FP16/INT8, wymiar do 65535. Algorytm VBASE zoptymalizowany pod zapytania hybrydowe (wektor + filtry + JOIN).
VectorChord
Aktywna alternatywa dla pgvecto.rs od TensorChord. Kompresja RaBitQ (Randomized Binary Quantization) + ponowne uporządkowanie. Przechowuje 26 razy więcej danych przy tej samej kosztowności.
Wszystkie korzystają ze standardowego typu vector, migracje są kompatybilne.
Konfiguracja infrastruktury testowej
Wdrożenie przez Docker Compose dla trzech baz danych:
- pgvectorscale (timescale/timescaledb-ha:pg18):
services:
postgres:
image: timescale/timescaledb-ha:pg18
ports:
- "5432:5432"
volumes:
- pgdata:/home/postgres/pgdata
- ./db_init_pgv:/docker-entrypoint-initdb.d
Inicjalizacja:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS vectorscale;
- VectorChord (tensorchord/vchord-postgres:pg18-v1.1.1):
CREATE EXTENSION IF NOT EXISTS vchord CASCADE;
Makefile do zarządzania:
COMPOSE := docker compose
PGV_FILE := docker-compose-pgv.yml
PGVS_FILE := docker-compose-pgvs.yml
VC_FILE := docker-compose-vc.yml
up-pgv:
$(COMPOSE) -f $(PGV_FILE) up --build -d
up-pgvs:
$(COMPOSE) -f $(PGVS_FILE) up --build -d
up-vc:
$(COMPOSE) -f $(VC_FILE) up --build -d
up: up-pgv up-pgvs up-vc
Unikalne nazwy usług i porty są wymagane.
Rozszerzenie repozytorium dla operacji bulk
Metoda bulk_create w BaseRepository:
async def bulk_create(self, schemas: list[CreateSchemaType]) -> list[ModelType]:
instances = [
self.model(**self._normalize_embedding_format(schema.model_dump()))
for schema in schemas
]
self.session.add_all(instances)
await self.session.flush()
return instances
Schemat BulkCreateRequest:
class BulkCreateRequest(BaseModel):
documents: Annotated[
list[DocumentCreate],
Field(..., description='Lista dokumentów do utworzenia', min_length=1, max_length=500)
]
Endpoint:
@router.post('/bulk', response_model=list[DocumentResponse], status_code=status.HTTP_201_CREATED)
async def bulk_create_documents(request: BulkCreateRequest):
async with transaction() as session:
repo = DocumentRepository(session)
created_docs = await repo.bulk_create(request.documents)
return created_docs
Przygotowanie do benchmarków
Zbiór danych: ag_news z Hugging Face (tytuły → embeddingi, category → metadane). Cel: 1 milion rekordów.
Zależności:
uv add --dev datasets ollama aiohttp tqdm
Składniki testu:
- Ładowanie partiami z datasets
- Generowanie embeddingów przez ollama
- Wczytywanie masowe do bazy danych
- Pomiar opóźnienia wyszukiwania
Struktura klasy testowej została zaimplementowana do równoległego porównania wszystkich rozszerzeń.
Co jest ważne
- Kompatybilność: wszystkie rozszerzenia używają typu
vector, kod jest przenośny. - Skalowanie: pgvectorscale i VectorChord działają z dyskiem, pgvector wymaga RAM.
- Kompresja: RaBitQ (26-krotna gęstość), SBQ dla dużych zbiorów danych.
- Wyszukiwanie hybrydowe: VBASE w pgvecto.rs do filtrów + JOIN.
- Wydajność: StreamingDiskANN daje 16-krotny wzrost przy 50M+ wektorach.
— Editorial Team
Brak komentarzy.