Spring til indhold

Vektorsøgning

søgning efter vektorer, der ligger nærmest en forespørgsel

  • Constellations, galaxy, stars
    Foto: StockSnap / Pixabay
  • Map, navigation, compass
    Foto: vialevo / Pixabay

Brug begrebet i en beslutning

Brug »Hvad er vektorsøgning?« i en konkret beslutning. Vi kan knytte begrebet til det system, du bygger eller køber. Jeres data samlet, hvor AI-agenter kan nå dem, med én udgave af hver kunde, uden at nogen ser mere, end de må, og med hvert svar sporet tilbage til kilden.

Se vores ydelser Kontakt os

Undersøg antagelserne bag ordet

Brug forklaringen og det tilknyttede arbejde til at formulere spørgsmål til dit projekt. Vi kan undersøge antagelserne sammen, før et værktøj vælges. Har gjort geodatapipelines 50 gange hurtigere — 50x hurtigere geografiske datapipelines

Har gjort geodatapipelines 50 gange hurtigere Kontakt os

Hvad det er

Vektorsøgning finder de lagrede elementer, hvis vektorer ligger tættest på vektoren for en forespørgsel. På engelsk hedder det vector search. En vektor er her en liste af tal med fast længde, som en embeddingmodel danner ud fra et stykke tekst, et billede eller en produktpost. Modellen er trænet, så elementer med beslægtet indhold får vektorer, der ligger tæt på hinanden, og derfor kan et spørgsmål og det afsnit, der besvarer det, ligge tæt sammen, selv om de ikke har et eneste ord til fælles.

»Tættest« kræver et mål. pgvector, den PostgreSQL-udvidelse som artiklens eksempler bygger på, understøtter seks: L2-afstand (euklidisk afstand), indre produkt, cosinusafstand og L1-afstand samt Hamming- og Jaccard-afstand til binære vektorer. Embeddingmodellens egen dokumentation oplyser, hvilket mål dens vektorer er beregnet til. For vektorer, der er normaliseret til længden 1, giver cosinusafstand og indre produkt naboerne i samme rækkefølge, og her anbefaler pgvector indre produkt, fordi det giver den bedste ydelse.

Der er to måder at besvare spørgsmålet på. Eksakt søgning sammenligner forespørgslen med hver eneste lagrede vektor og returnerer de sande nærmeste naboer. Det gør pgvector som standard, og dokumentationen beskriver det som perfekt recall, det vil sige at alle de sande naboer kommer med. Approksimativ søgning bruger et indeks, der kun besøger en del af dataene, og bytter noget recall for fart: de fleste af de sande naboer kommer med, men der er ingen garanti for dem alle. Derfor advarer pgvector om, at et approksimativt indeks i modsætning til et almindeligt indeks ændrer det, en forespørgsel returnerer.

pgvector har to typer approksimativt indeks. HNSW bygger en graf i flere lag, en metode som Malkov og Yashunin første gang offentliggjorde i 2016: hvert lag rummer en delmængde af laget nedenunder, en søgning begynder i det lille øverste lag og arbejder sig ned til det fulde, og deres artikel rapporterer, at søgningens omkostning vokser logaritmisk. IVFFlat deler vektorerne op i lister og søger kun i de lister, der ligger nærmest forespørgslen.

Hvorfor det betyder noget

Fuldtekstsøgning matcher ord. En kunde, der skriver »skærmen er helt sort«, finder ikke manualens afsnit med overskriften »displayet tænder ikke«, fordi de to ikke deler et eneste ord, heller ikke når endelserne er skåret af. Vektorsøgning sammenligner betydning, sådan som embeddingmodellen har opfanget den, så klagen og afsnittet kan lande tæt på hinanden. Samme idé virker ud over tekst: et billede, der ligner dette, en supportsag, der ligner en allerede løst, et produkt, der ligner det i kurven.

Vektorsøgning er også én måde at klare hentningen på i retrieval-augmented generation, hvor en stor sprogmodel svarer ud fra tekstafsnit, der er hentet til spørgsmålet. Spørgsmålet laves om til en vektor med den samme model som afsnittene, og de nærmeste afsnit sendes med i prompten. Svaret kan aldrig blive bedre end det, søgningen fandt, så søgningen fortjener den samme omhu som modellen.

At beholde vektorerne i den database, man allerede kører, har en praktisk side, og pgvector indleder sin dokumentation med netop det argument. Vektorerne får de samme transaktioner, den samme point-in-time recovery og de samme joins som alle andre kolonner, og fordi pgvector skriver til write-ahead-loggen, følger de også med ved replikering. Et filter på kunde, dato eller rettigheder er en almindelig WHERE-betingelse på den samme række, og et slettet dokument holder op med at blive fundet i samme øjeblik, som transaktionen bliver committet. Et separat vektorlager er et system mere, der skal fyldes og holdes i takt med det første.

Et team bør også vide, hvad vektorsøgning ikke gør. Den rangerer efter nærhed, ikke efter sandhed. Det nærmeste afsnit er det, der ligner spørgsmålet mest; det kan stadig være forældet, forkert eller stamme fra et dokument, læseren ikke må se. Nogle spørgsmål står og falder med et bestemt ord, for eksempel et navn, et varenummer eller en fejlkode, og pgvectors dokumentation foreslår at bruge vektorsøgning sammen med PostgreSQL’s fuldtekstsøgning. Den kombination kaldes hybrid søgning.

Sådan ser det ud i praksis

pgvector, der i oktober 2026 er i version 0.8.7, understøtter PostgreSQL 13 og nyere. Udvidelsen aktiveres én gang i hver database, og derefter får tabellen en kolonne af typen vector med det antal dimensioner, modellen leverer:

CREATE EXTENSION vector;

CREATE TABLE passages (
    id        bigserial PRIMARY KEY,
    source    text NOT NULL,
    body      text NOT NULL,
    embedding vector(3)
);

CREATE INDEX ON passages USING hnsw (embedding vector_cosine_ops);

Tre dimensioner holder eksemplet til at læse; en rigtig model leverer langt flere, og kolonnen angiver præcis det tal, modellen leverer. Programmet beregner hver embedding med modellen og indsætter den ved siden af den tekst, den kom fra. Indekset hører til én bestemt afstand: vector_cosine_ops betjener forespørgsler, der sorteres efter cosinusafstand, og en forespørgsel, der sorteres efter L2-afstand, kræver et ekstra indeks bygget med vector_l2_ops. HNSW har intet træningstrin, så indekset kan oprettes på en tabel uden rækker.

Forespørgslen laver spørgsmålet om til en vektor med samme model og beder om de nærmeste afsnit:

SELECT id, source, body
FROM   passages
ORDER  BY embedding <=> $1
LIMIT  5;

<=> er cosinusafstand, og $1 er forespørgslens vektor, sendt som parameter. To detaljer gør det muligt for PostgreSQL at bruge indekset: forespørgslen har både ORDER BY og LIMIT, og ORDER BY står på selve afstandsoperatoren i stigende rækkefølge. En lighedsscore til visning, 1 - (embedding <=> $1), hører hjemme i select-listen. De øvrige operatorer er <-> for L2-afstand, <+> for L1 og <#> for indre produkt. Den sidste returnerer det negative indre produkt, fordi PostgreSQL kun scanner et indeks på en operator i stigende rækkefølge.

HNSW-indekset har to byggeparametre: m, det største antal forbindelser pr. lag, 16 som standard, og ef_construction, størrelsen på kandidatlisten under opbygningen, 64 som standard. Når der søges, bestemmer hnsw.ef_search størrelsen på kandidatlisten, 40 som standard. En højere værdi giver bedre recall på bekostning af hastigheden, og SET LOCAL inde i en transaktion hæver den for én forespørgsel alene. Vil man vide, hvad indekset koster i recall, kører man den samme forespørgsel i en transaktion med SET LOCAL enable_indexscan = off, som giver det eksakte svar, og sammenligner de to lister.

Virksomhedens arbejde med skræddersyede AI-agenter lægger agentens hukommelse om tidligere sager i kundens egen database frem for i en leverandørs chathistorik. En tabel som passages er én form, sådan en hukommelse kan have: når en ny sag kommer ind, er de tidligere sager, der ligner den mest, kun én forespørgsel væk, i den samme database og under de samme rettigheder som resten af dataene.

Hybrid søgning kører begge søgninger og fletter de to lister. pgvectors dokumentation nævner Reciprocal Rank Fusion fra en artikel fra 2009 af Cormack, Clarke og Büttcher: hvert dokument får 1 / (k + rang) for hver liste, det optræder i, og pointene lægges sammen. Forfatterne fastsatte k til 60, og deres indledende forsøg viste, at 60 var »near-optimal, but that the choice was not critical«. Med en tsvector-kolonne search_vec i samme tabel, bygget som til fuldtekstsøgning, ser den flettede forespørgsel sådan ud:

WITH semantic AS (
    SELECT id, row_number() OVER (ORDER BY dist) AS r
    FROM  (SELECT id, embedding <=> $1 AS dist
           FROM   passages
           ORDER  BY dist
           LIMIT  20) AS nearest
),
keyword AS (
    SELECT id, row_number() OVER (ORDER BY score DESC) AS r
    FROM  (SELECT id, ts_rank_cd(search_vec, query) AS score
           FROM   passages, plainto_tsquery('danish', $2) AS query
           WHERE  search_vec @@ query
           ORDER  BY score DESC
           LIMIT  20) AS matches
)
SELECT id,
       coalesce(1.0 / (60 + s.r), 0)
     + coalesce(1.0 / (60 + k.r), 0) AS rrf
FROM   semantic AS s
FULL   JOIN keyword AS k USING (id)
ORDER  BY rrf DESC
LIMIT  5;

Hver søgning beholder sine egne 20 bedste og nummererer dem fra 1. Et afsnit, som begge søgninger placerer højt, får to andele og stiger til tops; et afsnit, som kun den ene søgning finder, beholder én andel. Fletningen bruger rang frem for score, fordi en cosinusafstand og en tekstrang ligger på skalaer, der ikke kan sammenlignes. Sproget i plainto_tsquery skal være det samme som i kolonnen, her danish. pgvector nævner en cross-encoder som den anden måde at kombinere listerne på.

Hvor det går galt

Færre rækker, end LIMIT bad om. Med et approksimativt indeks anvendes WHERE-betingelsen først efter indeksscanningen. pgvector viser regnestykket: hvis en betingelse matcher 10 % af rækkerne, giver et HNSW-indeks med standardværdien 40 for hnsw.ef_search i gennemsnit kun omkring 4 rækker. Siden version 0.8.0 scanner iterative indeksscanninger mere af indekset, indtil nok rækker er kommet igennem filteret. Slå dem til med SET hnsw.iterative_scan = strict_order, eller med relaxed_order for bedre recall med resultater, der står lidt ude af rækkefølge. En HNSW-scanning stopper ved hnsw.max_scan_tuples, 20.000 som standard. Har filteret kun få forskellige værdier, virker et partielt indeks pr. værdi også.

En forespørgsel, der aldrig rører indekset. ORDER BY 1 - (embedding <=> $1) DESC sorterer efter et udtryk, og en forespørgsel uden LIMIT beder om alt, så begge læser hver eneste række. Et indeks bygget med vector_l2_ops gør intet for en forespørgsel, der sorteres efter <=>. Sortér efter selve operatoren, stigende og med LIMIT, byg ét indeks for hver afstand, der søges med, og tjek planen med EXPLAIN (ANALYZE, BUFFERS).

Et IVFFlat-indeks bygget for tidligt. IVFFlat kører k-means over de rækker, der findes, når indekset bygges, og deler vektorerne op i lister ud fra resultatet. Et indeks, der er oprettet med for lidt data til sit antal lister, returnerer færre rækker, end forespørgslen bad om, og pgvectors råd er at droppe det, indtil tabellen rummer flere data. Indlæs dataene først, og byg indekset bagefter. pgvector foreslår at begynde med rækker / 1000 lister op til en million rækker og kvadratroden af antallet af rækker derover, og at sætte probes, der som standard er 1, til kvadratroden af antallet af lister. HNSW har intet tilsvarende træningstrin.

Rækker, der aldrig bliver fundet. NULL-vektorer kommer ikke med i indekset, og det gør nulvektorer heller ikke under cosinusafstand, for de har ingen retning at sammenligne. En række, der står uden embedding, er usynlig for en indekseret søgning. Tilføj NOT NULL, når indlæsningen er pålidelig, og lad et fast job tælle de rækker, der stadig mangler en embedding.

Vektorer fra to modeller i én kolonne. To embeddingmodeller, eller to versioner af den samme, placerer den samme tekst forskellige steder, og deres vektorer kan ikke sammenlignes, selv når antallet af dimensioner er det samme. Lav spørgsmålets vektor med den model, der lavede afsnittenes, gem modellens navn i en kolonne, og beregn alle vektorer igen, når modellen skifter. Til en kolonne med vektorer i flere størrelser viser pgvector et udtryksindeks med en betingelse for hver model, WHERE (model_id = 123).

For mange dimensioner til indekset. Typen vector gemmer op til 16.000 dimensioner, men HNSW og IVFFlat indekserer højst 2.000. Indeksér en cast til halfvec for op til 4.000, brug binær kvantisering for op til 64.000 og rangér den korte liste igen efter de fulde vektorer, eller indeksér en delvektor, når modellen understøtter det.

Én kundes vektorer gør en andens søgning langsommere. pgvector advarer om, at når flere kunder deler et approksimativt indeks, kan én kundes vektorer påvirke recall og hastighed for de andre. Partitionér tabellen efter kunde med listepartitionering, eller giv hver kunde sin egen tabel.

En indeksopbygning, der blokerer programmet. HNSW bygges langt hurtigere, når grafen kan ligge i maintenance_work_mem, og pgvector udskriver en meddelelse, når den ikke længere kan. At sætte den hukommelse så højt, at serveren løber tør, giver sin egen nedetid. På et system i drift bygger man med CREATE INDEX CONCURRENTLY, som ikke blokerer skrivninger.

Afsnit, læseren ikke må se. En søgning over alle afsnit kan give en sprogmodel tekst fra et dokument, brugeren ikke har ret til at læse, og modellen kan citere den. Læg rettighedsbetingelsen i den samme WHERE-betingelse som søgningen, så sådan en række aldrig forlader databasen, og slå iterative scanninger til, så filteret ikke efterlader prompten med for få afsnit.

En afstand opfattet som vished. En cosinusafstand på 0,2 siger, at et afsnit ligger nærmere end et på 0,4, ikke at det besvarer spørgsmålet. En tærskel, der er indstillet til én model, siger intet om den næste. Sortér efter afstand, begræns med LIMIT, og bedøm søgningen på et sæt rigtige spørgsmål, hvor man kender de rigtige afsnit på forhånd.

Læs mere

Ordliste

Vælg ud fra dine faktiske vilkår

Medbring et repræsentativt datasæt, de spørgsmål det skal besvare, og den aktuelle flaskehals. Vi kan aftale målinger af kvalitet, gennemløb og gendannelse.

Se, hvad det koster Kontakt os

Gør begreberne praktiske

Spørg, hvordan »Hvad er vektorsøgning?« gælder i din organisation. Et konkret eksempel fra dit nuværende system er nok til at begynde samtalen.

Se vores ydelser
welcome@engineer.company +45 50 10 61 84 København, Danmark
QR-kode til Vektorsøgning
Tag denne side med dighttps://engineer.company/da/glossary/vector-search/