Demo, all content is generated
Question

pgvector: HNSW or IVFFlat index for 50k embeddings?

Open · 561 views · asked by chen_wei · edited

RAG app over our company handbook and support tickets. About 50k chunks, 1536 dimensions. Search takes ~900ms without an index. Claude Code suggested ivfflat with lists = 100, a blog post says HNSW is always better. Which one and what settings?

What I’ve tried

Created ivfflat, queries got fast but some obvious matches disappeared from results.

Comment

3 answers

hannah_reyes · edited

HNSW, for your size. Reasons:

  • IVFFlat builds its clusters from the data present at index time. Built on an early or empty table, the clusters are poor and recall drops, which is the "missing matches" you see. You'd have to rebuild it as data changes.
  • HNSW has better recall at the same speed and doesn't need rebuilding.
create index on chunks using hnsw (embedding vector_cosine_ops);

Match the operator class to the operator you query with (<=> is cosine). Building it on 50k rows needs some maintenance_work_mem; on a small compute it can take a few minutes, run it outside peak hours.

Comment
HNSW built in 3 minutes, all expected matches back and ~15ms per search. Thanks both. chen_wei · edited
olu_backend · edited

HNSW here too. If you stay on IVFFlat for some reason, raise ivfflat.probes (default 1) at query time, e.g. set local ivfflat.probes = 10. With probes = 1 you search only one cluster, which explains the missing matches.

Comment
Setting probes to 10 already brought the matches back. Will try HNSW this weekend and compare. chen_wei · edited
marco_py · edited

Small one: OpenAI embeddings are already normalized to length 1, so inner product (<#> with vector_ip_ops) gives the same ranking as cosine and is a bit cheaper. Not worth changing if cosine is fast enough.

Comment