Navigation
What We AreThe BrainPortfolioThe Lab's LabBuilt For YouThe WhiteboardServices & Prices
Let's Talk →
← The Whiteboard

What is the difference between embeddings and a vector database?

An embedding is a representation. A vector database is storage. Teams buy the second to fix problems that live in the first — and no index can beat exact search over the vectors you already have.

An embedding is a representation: a model turns a piece of text into a fixed-length vector. A vector database is storage plus search over those vectors, usually approximate nearest neighbour. Different layers of the stack. Retrieval quality is set by the embedding model and the chunking; the index decides how much of that quality gets traded away for speed.

Ross Jones — Founder, The Hopium Lab. Last modified 22 July 2026.

Terms first, because the category is sloppy about them. A vector index is a data structure for fast nearest-neighbour lookup. A vector store holds vectors and hands back neighbours. A vector database adds durability, transactions, filtering, backups, access control. pgvector is a Postgres extension, not a database. Conflating any two of the four is how a storage decision gets sold as a quality decision.

What does an embedding actually encode?

An embedding encodes distributional meaning under one model's training objective, compressed into d dimensions. Topical similarity, paraphrase, rough intent: encoded well. Exact strings, rare identifiers, numeric magnitude, negation: encoded badly or not at all. A vector holds what the training objective rewarded, never what a given query needs.

Dimension is a budget, not a detail. Weller, Boratko, Naim and Lee (arXiv:2508.21038, v2 12 March 2026) connect retrieval to learning theory: "the number of top-k subsets of documents capable of being returned as the result of some query is limited by the dimension of the embedding." The limit holds even when embeddings are optimised directly on the test set with free parameters, so better training data does not dissolve it. A capacity property of single-vector dot-product retrieval — not a claim about cross-encoders, late-interaction models or BM25.

The paper's LIMIT dataset makes the abstraction concrete: 1,000 queries over 50,000 documents, plus a small variant holding only the 46 documents relevant to any query. Forty-six documents, a task a human solves instantly, leading embedding models failing it while BM25 nearly solves it. LIMIT is adversarial, built from the theory to break models. Real corpora are not adversarial — concede the point, then keep what survives it. The failure lives in the representation, where storage and indexing cannot reach.

Why does semantic search miss exact identifiers?

Because an identifier fragments into low-frequency subword pieces carrying no learned meaning, leaving the pooled vector to encode the surrounding sentence rather than the string. Anthropic's engineering write-up says it plainly: an embedding model "might find content about error codes in general, but could miss the exact 'TS-999' match", where "BM25 looks for this specific text string".

Rare entities fail identically, and the gap is enormous. In EntityQuestions (EMNLP 2021), on the pattern "Where was [E] born?", BM25 leads DPR by 49.9 points absolute in top-20 retrieval accuracy. Multi-dataset training lifts DPR's average from 49.7% to 56.7%, and augmentation does not repair the generalisation problem. Dense retrievers generalise to common entities and to nothing rarer.

Part numbers, error codes, case references, SKUs, CAS numbers, amendment identifiers. Every regulated corpus is full of strings that mean everything to the reader and nothing to the encoder.

Why do embedding models fail on negation?

Bi-encoders — precisely the models feeding a vector database — rank paired documents differing only by a negation at roughly chance. NevIR (EACL 2024) builds that pair deliberately and reports that "most current information retrieval models do not consider negation, performing similarly or worse than randomly ranking", ordered by architecture: "cross-encoders perform best, followed by late-interaction models, and in last place are bi-encoder and sparse neural architectures".

Scope the claim or one query kills it. Plenty of negated questions retrieve fine, because other words carry the work. The measured failure is discrimination between near-identical passages where a negation is the only difference — exclusion criteria, eligibility rules, "except where" clauses.

Can a better vector database fix bad retrieval?

Rarely, and never through the index itself. An approximate index is evaluated as recall against exact search over the same vectors: ANN-Benchmarks built the field's methodology on recall@k versus queries per second, with exact nearest neighbours as ground truth. pgvector's docs give the operational form of that test: monitor "recall by comparing results from approximate search with exact search". The retrieval ceiling is the best result exact search over your stored vectors can return. The recall gap is the difference between what an approximate index returns and what exact search over those same vectors returns.

An approximate index is scored as recall against exact search over the same vectors. It cannot beat exact search. The retrieval ceiling was fixed the moment the embedding model and the chunking strategy were chosen.

The concession that keeps the argument honest: migrating to a dedicated vector database frequently does improve results, through what comes bundled around the index — built-in BM25 and fusion, a hosted reranker, multi-vector support, quantisation, filter-aware search, defaults tuned for recall rather than for a demo. Something other than the index improved, and that something was almost always available where the data already sat. Most head-to-head comparisons are comparisons of HNSW implementations anyway: Malkov and Yashunin's algorithm is the default graph index in pgvector, Qdrant, Weaviate, Milvus and Lucene-based stacks.

What actually moves retrieval quality?

Changes to the representation and the ranking move the ceiling. Changes to the index recover quality already given away. Only the last row is the purchase you were considering.

ChangeLayerEffect on the retrieval ceilingEvidence
Different embedding modelRepresentationMoves it — up or downBEIR: zero-shot rank order does not transfer across corpora
Re-chunking, per-chunk generated contextRepresentation inputMoves itAnthropic's own eval: top-20 failure 5.7% → 3.7%
BM25 alongside vectors, ranks fusedRankingMoves itAnthropic's own eval: 5.7% → 2.9%
Cross-encoder reranker over top candidatesRankingRe-scores with an architecture a bi-encoder cannot matchAnthropic's own eval: 5.7% → 1.9%
Raising hnsw.ef_search or ivfflat.probesIndexNone — closes a gap already concededpgvector defaults: 40 and 1
Swapping vector databaseStorage and operationsNone from the index aloneANN ground truth is exact search

Label the sources honestly. Anthropic's reductions come from an internal eval on their own blog: 800-token chunks plus roughly 100 tokens of generated context per chunk cut top-20 retrieval failure by 35%, then 49% with contextual BM25, then 67% with reranking. BEIR — 18 datasets, 10 retrieval systems, zero-shot, NeurIPS 2021 — is the peer-reviewed warning that a leaderboard-topping model is not automatically good on a given corpus.

When is Postgres with pgvector enough?

Most of the time, once the debits are on the table. pgvector 0.8.5 shipped 8 July 2026 and supports Postgres 13+. The costs, all checkable in the README:

  • HNSW indexes vector up to 2,000 dimensions and halfvec up to 4,000, while storage runs to 16,000. A 3,072-dimension model needs a halfvec expression index or Matryoshka truncation.
  • "With approximate indexes, filtering is applied after the index is scanned." At the default hnsw.ef_search of 40, against a predicate matching 10% of rows, "only 4 rows will match on average". Iterative index scans landed in 0.8.0 on 30 October 2024; anyone who configured pgvector earlier and never enabled them is silently dropping results.
  • Defaults ship tuned for speed. ivfflat.probes is 1 — a single list scanned — the most common cause of "we tried pgvector and the results were bad".
  • Three of the last four releases repaired HNSW vacuuming and parallel-build bugs (0.8.2, February 2026; 0.8.3 and 0.8.4, June 2026). Maturing software under active repair.
  • Changing embedding model means a full re-embed and re-index, no easier here than anywhere else.

Hybrid search is not a reason to leave. The README points straight at Postgres full-text search, fused with Reciprocal Rank Fusion — Cormack, Clarke and Buettcher, SIGIR 2009, where k = 60. The widely copied Supabase implementation defaults to 50. Take the constant from the paper.

How do you measure the recall you are giving away?

Run the real query set twice — once against exact search, once against the index — and score the overlap. Threshold folklore ("under 10 million vectors, stay on Postgres") is blog arithmetic with no benchmark under it. A recall gap measured on production queries survives a room full of engineers.

Filtered queries are where the number falls apart, and for every product in the category. ACORN (SIGMOD 2024) and the filtered-ANN work following it describe the mechanism: as a predicate gets more selective, predicate-satisfying nodes thin out of a graph's one- and two-hop neighbourhoods, traversal fragments, recall degrades. Post-filter, pre-filter and filter-aware indexes trade differently, and none escapes.

Retrieval sits inside the data-handling category of the production-readiness audit I run across my own products, and it has a single entry criterion: a recall number, on real queries, with the filter attached. A live stack where nobody can state the number is a two-day first look, not a migration. Regulated corpora raise the bar again — retrieval over certification regulations needs point-in-time versioning before recall means anything.

Why doesn't retrieval improve after the migration?

Because the constraint sat upstream and the migration only changed storage. Every failure below surfaces downstream as a confident wrong answer, which is why a retrieval miss reads as a hallucination. Name them, because unnamed failures never get budget.

  • The mixed embedding space. Query embeddings switched to a new model, stored document vectors never regenerated. Nothing errors. Cosine similarity keeps returning numbers, computed across incompatible spaces. Practitioner-reported rather than measured — check your own pipeline.
  • The default-probe index. ivfflat.probes = 1. One list scanned, latency excellent, dashboard green, recall unmeasured.
  • The silent post-filter. A WHERE clause applied after the index scan, four rows surviving where a hundred were expected.
  • The identifier query. An exact string in the query and nothing corresponding in the vector.
  • The leaderboard swap. Top of a public leaderboard, worse on your corpus — documented by BEIR in 2021, re-run locally by almost nobody.
  • The uncapped dimension. 3,072-dimension vectors that will not take an HNSW vector index, found the week before launch.
  • The unmeasured migration. No recall baseline before, no recall number after, improvement asserted from p95 latency and vibes.

A migration with no recall baseline cannot be evaluated as a success or a failure. Faster and wrong is the easiest thing in this category to buy.

What should you run before buying a vector database?

The check below settles the argument with a number instead of a preference. Copy it, fork it, argue with it.

RETRIEVAL CEILING CHECK v1.0 (22 July 2026) — The Hopium Lab
Run before any vector database migration.

  retrieval ceiling = the best result exact search over your stored
                      vectors can return
  recall gap        = the difference between what an approximate index
                      returns and what exact search over those same
                      vectors returns

0. QUERY SET
[ ] >= 200 real user queries, never synthesised from the documents
[ ] Include exact identifiers, rare proper nouns, negated queries,
    and queries carrying a WHERE clause
[ ] Chunk ids labelled by hand. No model-generated ground truth

1. CEILING — exact search, index off
      BEGIN;
      SET LOCAL enable_indexscan = off;
      SET LOCAL enable_bitmapscan = off;
      SELECT id FROM chunks ORDER BY embedding <=> :q LIMIT 10;
      COMMIT;
[ ] Score recall@10 against the hand labels
[ ] Ceiling below target -> the database is not the problem. Stop

2. RECALL GAP — index on, defaults as shipped
      SET LOCAL hnsw.ef_search = 40;   -- pgvector default
      SELECT id FROM chunks ORDER BY embedding <=> :q LIMIT 10;
[ ] gap = ceiling recall@10 - index recall@10, averaged
[ ] Repeat at ef_search 40 / 100 / 200, logging latency at each
[ ] Repeat with the WHERE clause, then with
    hnsw.iterative_scan = relaxed_order. Expect worse

3. UPSTREAM FIXES, ONE AT A TIME, RE-SCORED AGAINST STEP 1
[ ] BM25 over tsvector, fused by RRF with k = 60 (SIGIR 2009)
[ ] Re-chunk: fixed windows vs structure-aware, same model
[ ] Per-chunk generated context prepended before embedding
[ ] Cross-encoder rerank over the top 50 candidates

4. ONLY NOW CONSIDER A MIGRATION
[ ] Gap large AND ef_search/probes already raised AND latency at the
    required recall unacceptable -> a genuine index problem
[ ] Otherwise -> representation or ranking, and it travels with you

Buy a vector database for the operations: replication, filter semantics, quantisation, someone else running it at 3am. Retrieval quality is not on that list. The ceiling belongs to a model and a chunking strategy, and every product in the category competes over how much of it to hand back. Measure the gap first — the number usually says the money belongs upstream, which is the same lesson as knowing which parts should never be a model call.

Ross Jones, Founder, The Hopium Lab. Last modified 22 July 2026. Engineering commentary, not legal advice.