Development

Choosing an Embedding Model by Dimensions, Cost and Fit

Antonio Evans10 min read

A workbench with three small labeled boxes representing candidate embedding models, each feeding a funnel that outputs vectors of different lengths (short, medium, long).
Key points

Key points

  1. 1Dimension size drives vector storage and search latency more than any other single factor, so pick the smallest model that clears your quality bar.
  2. 2Public leaderboards are a shortlist mechanism, not a verdict: benchmark rank rarely predicts recall on your own corpus.
  3. 3Build a golden set of 100 to 300 real queries with labeled relevant passages, then measure recall@10 and nDCG@10 for two or three candidates.
  4. 4Test the whole retrieval pipeline, including chunking and hybrid fusion, because model choice is one decision among several that shape quality.

The three axes that actually decide the model

Most embedding model choices start with a leaderboard and end with a surprise in production. The gap has two documented causes. First, benchmark contamination: many embedding models are partly trained on data overlapping the evaluation corpora, so a leaderboard score can reflect partial memorization rather than generalization the MTEB contamination analysis. Second, measurement mismatch: MTEB's retrieval split scores binary relevance, which collapses the difference between a great result and a barely acceptable one the MTEB contamination analysis.

So treat the leaderboard as a shortlist generator. The decision itself rests on three axes.

Dimensions. Every vector is a fixed-length array of floats. A 384-dimension embedding stored as float32 occupies 1,536 bytes per chunk; a 1536-dimension embedding occupies 6,144 bytes. At one million chunks that is roughly 1.5 GB versus 6.1 GB, before index overhead. Dimension count also raises distance-computation cost, which shows up directly in search latency.

Cost per token and per query. Hosted embedding APIs bill per input token, and you pay twice: once when you index the corpus and again on every query. Query cost is tiny in absolute terms but scales with traffic. Indexing cost is a one-time charge that repeats whenever you change models, because vectors from different models are not comparable and require a full re-embed how to benchmark embedding models.

Fit to your domain. Domain vocabulary changes similarity geometry. In legal or biomedical text, words like "discharge" or "motion" carry meanings that general models conflate with their common-language senses, collapsing documents that should sit far apart how to benchmark embedding models. A model trained for sentence similarity rather than retrieval can score well on similarity benchmarks and still underperform on retrieval, because training objective matters more than model size the embedding model decision framework.

One more axis is worth knowing about because it changes the arithmetic: Matryoshka embedding models are trained so their vectors stay useful when truncated. In a sentence-transformers experiment, a Matryoshka model preserved 98.37% of its performance at 8.3% of the embedding size, versus 96.46% for a standard model the Matryoshka embeddings guide. If your candidate list includes a Matryoshka model, you can test full dimension and a truncated dimension in the same bake-off and pick on measured quality rather than assumption.

Dimensions: the storage and latency arithmetic

Run the numbers for your own corpus before you look at quality. Suppose you have 800,000 chunks and store float32 vectors.

DimensionBytes per vectorCorpus sizeRelative search cost
2561,024819 MB1x baseline
3841,5361.23 GB1.5x
7683,0722.46 GB3x
10244,0963.28 GB4x
15366,1444.92 GB6x

The bytes-per-vector column is arithmetic (dimensions times 4 bytes for float32). The relative search cost column is a rough scaling of distance computation work per candidate, useful for sizing rather than capacity planning. Two conclusions follow.

First, moving from 1536 to 384 dimensions cuts vector storage by 75% and reduces distance work correspondingly. That is the kind of change that turns a memory-bound index into one that fits comfortably in RAM with room for growth.

Second, dimension alone does not cap you at small corpora. A theoretical analysis in the LIMIT paper estimates that even 1024-dimension embeddings face a breaking point at roughly four million documents, and real models hit the wall sooner the reranker selection guide citing that paper. If your corpus is far below that scale, dimension is a cost lever, not a quality ceiling. Test the smaller option.

Two practical notes. Quantizing float32 to int8 quarters storage again and is usually acceptable for retrieval, but measure recall after quantization rather than assuming it. And if your vector database supports it, ask whether your candidate model produces vectors you can truncate, so you can index at full size and query at a smaller one, or the reverse.

Cost: indexing versus serving

Embedding cost has two shapes and they behave differently.

Indexing cost is proportional to corpus size times average chunk tokens, divided by a million, times the per-million-token price. It is paid once per model, and again whenever you re-chunk or change models. A bake-off with three candidates means three full embeddings of the corpus, so keep the golden set and the evaluation corpus separate from the production corpus during exploration.

Serving cost is query length times per-million-token price times query volume. For short queries this is usually small, but it is not zero at scale, and it interacts with reranking decisions. Adding a cross-encoder reranker on top of retrieval adds 20 ms to 150 ms of latency per query for a 50 to 100 document candidate pool the reranking implementation guide. Reranking is often the better place to spend compute than a larger embedding model, because it is a second-stage operation applied to a shortlist, not a full corpus scan the hybrid search and reranking reference.

A simple decision rule: choose the embedding model that maximizes recall@10 at stage one, then decide separately whether to spend latency budget on reranking. If recall@10 is already above your threshold with the cheap model, a reranker buys precision, not recall, and its value depends on whether your queries are complex. Reported gains from reranking are larger for multi-hop (+47%), complex (+52%) and ambiguous (+41%) queries than for simple fact lookup (+18%) the cross-encoder reranking study.

Build the golden set before you compare models

A golden set is a fixed list of queries, each with the passages that should be retrieved. Without one, every model comparison is an opinion.

Target 100 to 300 queries. Fewer than 100 makes the confidence interval on recall@10 too wide to distinguish close candidates. More than 300 is usually hard to label by hand and slow to review.

Sources for queries, in order of preference: real search logs or support tickets, questions written by the people who answer them, then synthetic questions generated from your documents and reviewed by a human. RAG projects are usually domain specific and built on private data, so public benchmarks rarely substitute for a custom set the path to a golden dataset. Synthetic question generation is a legitimate way to bootstrap the set, but label relevance yourself the RAG evaluation guide.

For each query, record the chunk IDs that genuinely answer it. Graded labels (for example 2 for a direct answer, 1 for useful context, 0 for irrelevant) let you compute nDCG, which rewards putting the best result first. Binary labels are simpler and enough for recall.

A minimal record looks like this:

{
  "query_id": "q014",
  "query": "how do I reset the admin password for the on-prem appliance",
  "relevant": [
    {"chunk_id": "runbook-onprem-12", "grade": 2},
    {"chunk_id": "faq-auth-03", "grade": 1}
  ]
}

Keep the golden set under version control and never tune against it repeatedly without adding fresh queries. It is a test set, not a training set.

Metrics: recall@k and nDCG@k, with a worked example

Recall@k measures the fraction of queries where at least one labeled relevant chunk appears in the top k. It answers a blunt question: would the right document reach the model at all? In a worked example with 100 queries, 83 of them had their target document in the top 5, giving recall@5 of 0.83 the retrieval metrics tutorial.

nDCG@k adds ordering. Each result contributes its relevance grade discounted by position, then the total is normalized against the ideal ordering. A query where the grade-2 chunk sits at position 1 scores higher than one where it sits at position 4, even though both count for recall.

Run the numbers on a small example:

QueryRelevant chunks (grade)Model A top 10 positionsModel B top 10 positions
q1A (2), B (1)A at 1, B at 3A at 4, B not present
q2C (2)C at 2C at 1
q3D (2), E (1)D at 6, E not presentD at 1, E at 2

Recall@10 is 1.0 for both models on all three queries: every labeled chunk appears inside the top ten. nDCG tells a different story. Model B places the grade-2 answer first or second on every query, while Model A buries q1's best answer at position 1 but drops q3's at position 6. Model B wins on nDCG despite tying on recall.

This is the central reason to report both. Recall tells you whether the pipeline can find the answer; nDCG tells you whether the answer arrives early enough to matter after truncation to top 5 for the generation step. Benchmark well, and use the Openlayer summary of metric categories as a checklist: retrieval quality (recall, MRR, NDCG), semantic similarity, clustering quality, and performance metrics like throughput, p95 latency and memory footprint how to benchmark embedding models.

Evaluating retrieval separately from generation is standard practice and makes failures diagnosable: when an answer is wrong, you can tell whether retrieval missed or generation hallucinated the RAG evaluation guide the Redis RAG evaluation guide.

Run the bake-off

Pick two or three candidates, not eight. A useful slate: one small model (in the 256 to 384 dimension range), one strong general model, and one model that claims domain fit or that you have seen perform on similar data. Add a truncated Matryoshka variant if one of the candidates is Matryoshka.

Hold everything else constant. Same chunking, same chunk IDs, same golden set, same k. If you change chunking between candidates, you are no longer comparing embedding models.

The evaluation loop, in outline:

  1. Chunk the corpus once with your chosen strategy and record chunk text and IDs.
  2. For each candidate, embed every chunk and build an index in a scratch collection.
  3. For each golden query, embed the query with the same model, retrieve top 50, and compute recall@10 and nDCG@10 against labels.
  4. Record p95 query latency and an estimate of storage per candidate.
  5. Repeat at 2 to 3 dimension settings for any Matryoshka candidate.

A compact scoring harness:

def evaluate(index, embed, golden, k=10):
    recalls, ndcgs = [], []
    for row in golden:
        qv = embed(row["query"])
        hits = index.search(qv, k=50)[:k]
        relevant = {r["chunk_id"]: r["grade"] for r in row["relevant"]}
        recalls.append(int(any(h in relevant for h in hits)))
        dcg = sum(relevant.get(h, 0) / math.log2(i + 2) for i, h in enumerate(hits))
        ideal = sorted(relevant.values(), reverse=True)[:k]
        idcg = sum(g / math.log2(i + 2) for i, g in enumerate(ideal))
        ndcgs.append(dcg / idcg if idcg else 0.0)
    return {"recall@10": sum(recalls) / len(recalls),
            "ndcg@10": sum(ndcgs) / len(ndcgs)}

Read the results with a decision rule, not a ranking. If the small model is within a couple of points of nDCG@10 of the large one on your set, take the small model: it saves storage, lowers latency and simplifies the index. If the small model loses badly, look at the failing queries before concluding the model is at fault. Often the failure is chunking: chunks that mix multiple ideas produce noisy averaged embeddings that retrieval cannot match, and quality collapses below roughly 16 tokens per chunk for every model tested the embedding model decision framework the chunking strategies guide.

One caveat on the decision rule: differences of a couple of nDCG points sit inside labeling noise on a 100-query set. When two candidates are close, add 50 more queries from the same distribution and re-run rather than splitting hairs on the first pass.

Where hybrid search changes the answer

If you run hybrid retrieval, the embedding model competes with a lexical ranker, and fusion can rescue a weak dense model. Reciprocal rank fusion combines ranked lists by position rather than raw score, so an unbounded BM25 score and a bounded cosine similarity never need to be normalized onto a shared scale the OpenSearch RRF introduction. A document that ranks near the top of either list gets credit, which means exact-match queries that defeat a dense model can still succeed through the keyword side the RRF explainer the MongoDB RRF guide.

The practical implication for model selection: evaluate candidates inside your actual fusion setup, not in isolation. On the WANDS e-commerce dataset, baseline BM25 and pure KNN were statistically indistinguishable at NDCG 0.6983 versus 0.6953, while a tuned hybrid reached 0.7497, a 7.4% lift over either alone the hybrid search reference. A dense model that ranks second on its own may contribute more inside a fused pipeline than one that ranks first alone.

Run the bake-off twice if you plan to ship hybrid: once dense-only, once with fusion. The winner can differ, and the fusion run is the one that predicts production.

Re-test when the corpus or the workload changes

An embedding decision has a shelf life bounded by two events: the corpus changing shape and the query distribution changing.

Corpus drift matters because chunk boundaries and domain vocabulary shift as content grows. A model chosen on 50,000 support articles may behave differently on 200,000 that include tickets, transcripts and forum threads. Sentence-length distributions matter: models tuned for short, clean passages can underperform on long contracts or multi-paragraph tickets how to benchmark embedding models.

Workload drift matters because query mix drives which metric matters. If your traffic shifts toward complex, multi-hop questions, the value of a reranker rises, and the optimal first-stage model may change with it the cross-encoder reranking study.

A simple cadence: re-run the golden set whenever you re-chunk more than 10% of the corpus, when you add a document type you have not indexed before, or when recall@10 on a fresh sample of 50 queries drops. Add each new failing query to the golden set so the set grows toward your real workload.

When the re-test happens, the mechanics are the same as the first bake-off, which is the argument for building the harness early and keeping it in the repository. If you are running candidates across many model types (text embeddings alongside image or audio encoders for multimodal retrieval), putting them behind one API key removes the per-provider glue from the evaluation loop, which is what Quanta Inference is for.

FAQ

FAQ

How many queries do I need in a golden set?

Aim for 100 to 300. Below 100, the confidence interval on recall@10 is wide enough that two good candidates can appear different by chance. Above 300, hand labeling becomes the bottleneck, and it is usually better to spend that effort on adding fresh queries as production failures surface the path to a golden dataset.

Can I just pick the top model on the MTEB leaderboard?

No. Leaderboard rank measures average competence across a fixed public battery and does not measure recall on your corpus. Contamination inflates scores when training data overlaps evaluation data, and binary relevance scoring hides ranking quality. Use the leaderboard to build a shortlist, then decide on your own queries the MTEB contamination analysis.

Is a 384-dimension model good enough, or do I need 1536?

It depends on your domain and only your measurements can tell you. Smaller dimensions cut storage and distance-computation cost proportionally, and a model trained for retrieval can match a larger general model on a narrow domain. If recall@10 and nDCG@10 are within a couple of points on your golden set, take the smaller model and spend the savings elsewhere the embedding model decision framework.

Should I spend budget on a bigger embedding model or a reranker?

Usually the reranker, if your stage-one recall@10 already clears your bar. Reranking is a second-stage operation over a shortlist of 50 to 100 candidates, adding 20 ms to 150 ms per query and lifting precision, with larger gains on complex and multi-hop queries than on simple fact lookup the reranking implementation guide the cross-encoder reranking study.

Do I need to re-embed the whole corpus when I change models?

Yes. Vectors from different models are not comparable, so a model change requires re-embedding every chunk and rebuilding the index. This is why the bake-off should run on a separate scratch collection, and why a model decision is best made before the corpus grows very large how to benchmark embedding models.

Sources

Sources

  1. MTEB Leaderboard Lies: Embedding Recall in Production
  2. How to Benchmark Embedding Models for Your Use Case ...
  3. Choosing a Text Embedding Model
  4. Matryoshka Embeddings
  5. How to Select the Right Reranking Model
  6. Reranking in RAG: Cross-Encoders, Latency & Costs
  7. Hybrid Search: BM25, Vector & Reranking 2026 - Digital Applied
  8. Cross-Encoder Reranking Improves RAG Accuracy by 40%
  9. The path to a golden dataset, or how to evaluate your RAG?
  10. A complete guide to RAG evaluation: metrics, testing and ...
  11. Retrieval Metrics Tutorial: Recall@k and MRR Explained
  12. RAG evaluation guide: metrics, frameworks & infrastructure
  13. Chunking Strategies to Improve LLM RAG Pipeline Performance | Weaviate
  14. Introducing reciprocal rank fusion for hybrid search - OpenSearch
  15. What is reciprocal rank fusion in hybrid search? - YouTube
  16. Better RAG Results With Reciprocal Rank Fusion
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles