Lesson 18 / 25

pgvector for Embeddings

Similarity search inside Postgres.

Vectors next to your data

The pgvector extension adds a vector column type and distance operators: <-> (Euclidean), <#> (negative inner product) and <=> (cosine distance). Store an embedding per document produced by an embedding model, add an HNSW index for fast approximate search, and wrap the nearest-neighbour query in a function you call with rpc(). Because it is plain SQL, you can combine similarity with normal filters and RLS.

A documents table and a match function

SQL; dimensions must match your model.

create extension if not exists vector with schema extensions;

create table public.documents (
  id bigint generated always as identity primary key,
  content text not null,
  embedding extensions.vector(1536)
);

create index on public.documents
  using hnsw (embedding extensions.vector_cosine_ops);

create or replace function public.match_documents(query_embedding extensions.vector(1536), match_count int)
returns table (id bigint, content text, similarity float)
language sql stable
set search_path = public, extensions
as $$
  select d.id, d.content, 1 - (d.embedding <=> query_embedding) as similarity
  from public.documents d
  order by d.embedding <=> query_embedding
  limit match_count;
$$;

-- client: supabase.rpc('match_documents', { query_embedding: vec, match_count: 5 })

Match dimensions and distance to the model

The vector size must equal the embedding model's output, and the index operator class should match the distance you query with.

Quick check: Which pgvector operator gives cosine distance?

  • <=>
  • <->
  • <#>
  • @>
Answer

<=> — <-> is Euclidean, <#> is negative inner product.