BM25 vs BM42 vs miniCOIL vs SPLADE: Which Sparse Retriever for Hybrid RAG?
BM25 is lexical, SPLADE learns term expansion, and Qdrant's BM42/miniCOIL add neural weights to the BM25 formula—compared for hybrid RAG.
Contents
Short answer: BM25 is classic lexical scoring (term frequency + inverse document frequency, no model). SPLADE is a learned-sparse retriever that expands each token into related vocabulary terms with learned weights. BM42 and miniCOIL are Qdrant-built sparse neural retrievers that keep the BM25 scoring formula but replace its statistical term weights with transformer-derived ones—miniCOIL is the one Qdrant recommends for new projects. None of them should be used alone in production; pair whichever you pick with dense embeddings.
Quick comparison
| BM25 | SPLADE (prithivida/Splade_PP_en_v1) | BM42 | miniCOIL | |
|---|---|---|---|---|
| Type | Statistical | Learned sparse (MLM expansion) | Neural weights on BM25 | Neural weights on BM25 |
| Term importance | IDF + saturation | Learned per-term logits | Attention-based | Contextual, per-token |
| Vocabulary | Corpus tokens only | Expands to related terms | Query/doc tokens | Query/doc tokens |
| Out-of-domain | Robust (no training) | Can degrade on unseen domains | Robust-ish | Robust-ish |
| Vector size | Small | Large (many expansion terms) | Small | Small |
| Inference cost | None (index-time only) | Transformer forward pass | Transformer forward pass | Lightweight transformer |
| Cold start | Instant | Needs model + heavy indexing | Model download | Model download |
How each handles term importance, vocabulary, and OOD terms
BM25 scores a document purely on how often query terms appear, discounted by how common those terms are across the corpus. It never leaves the observed vocabulary, which is exactly why it's bulletproof on out-of-domain and rare terms—a product SKU, an error code, or a surname is matched literally. Its weakness is that it can't tell that "cardiac" and "heart" are related.
SPLADE fixes vocabulary mismatch by running a masked-language-model head over the text and expanding each token into a weighted bag of related terms. That gives strong recall, but the expansion inflates the vector and the learned weights can drift on domains far from the training data.
BM42 and miniCOIL take a middle path: keep BM25's proven ranking formula, but derive term importance from a transformer instead of raw frequency. BM42 uses attention weights; miniCOIL learns compact contextual weights per token. They don't expand vocabulary aggressively like SPLADE, so vectors stay small and behavior stays close to lexical—more predictable out of domain.
Index size, inference cost, cold start
- BM25: cheapest everywhere. No model, no GPU, near-instant to stand up. Cost is only the inverted index.
- SPLADE: largest vectors (expansion terms) and a transformer forward pass at both index and query time. Indexing a big corpus is slow and storage-heavy.
- BM42 / miniCOIL: small vectors like BM25, plus a model forward pass at ingest and query. miniCOIL's model is deliberately lightweight, so its query-time latency is closest to BM25 among the neural options.
Which to pick by corpus and latency budget
- Keyword-heavy, exact-match corpora (code, logs, IDs, legal citations) with a tight latency budget: BM25. It's hard to beat on literal matching and adds zero inference cost.
- New hybrid project, general prose, want better-than-lexical without SPLADE's overhead: miniCOIL. This is Qdrant's default recommendation for new work.
- Short or technical text where BM25's frequency stats are noisy: BM42.
- Max learned-sparse recall, willing to pay for larger vectors and slower indexing: SPLADE.
How each plugs into hybrid + rerank
The pattern is identical regardless of which sparse retriever you choose. Run sparse and dense in parallel, fuse, then rerank the merged shortlist.
# Qdrant hybrid query: dense + sparse (miniCOIL/BM42/SPLADE), fused, then rerank
results = client.query_points(
collection_name="docs",
prefetch=[
Prefetch(query=dense_vec, using="dense", limit=40),
Prefetch(query=sparse_vec, using="sparse", limit=40), # sparse retriever output
],
query=FusionQuery(fusion=Fusion.RRF), # reciprocal rank fusion
limit=40,
)
# then: cross-encoder rerank the 40 → keep top 8 for the LLMSparse-only retrieval consistently underperforms in production because it can't capture semantic similarity that shares no tokens. Dense-only misses exact terms. The sparse retriever's job in the stack is precise lexical recall; the dense vector covers semantics; the reranker fixes ordering. Swapping BM25 for miniCOIL or SPLADE changes the sparse leg only—the fusion and rerank stages stay the same.
Pick miniCOIL for a new hybrid RAG build, keep BM25 for pure keyword workloads, reach for SPLADE only when you need its recall and can pay for it—and never ship any of them without dense vectors and a reranker.
Related: more writing.
Frequently asked
- What's the difference between BM25, BM42, miniCOIL, and SPLADE?
- BM25 is statistical lexical scoring. SPLADE learns to expand tokens into related vocabulary. BM42 and miniCOIL keep BM25's formula but replace frequency-based term weights with transformer-derived ones.
- Is BM42 better than BM25?
- BM42 adds transformer attention-based term weighting on top of BM25's formula, helping short and technical text, but you should still pair it with dense vectors.
- What is miniCOIL?
- A lightweight sparse neural retriever from Qdrant that learns contextual term weights on the BM25 formula. It's Qdrant's recommended sparse retriever for new projects.
- Is SPLADE still worth using?
- Yes for strong learned-sparse recall, but it has larger vectors and higher indexing and query cost than miniCOIL or BM42. The common model is prithivida/Splade_PP_en_v1.
Keep reading
Building Agentic Search on Qdrant: A Production Architecture Walkthrough
How to build a production agentic search system on Qdrant: single-shot vector+filter tool calls, Postgres hydration, and progressive relaxation.
ReadWhy RAG fails in production — and where
When RAG breaks, the model usually isn't the problem — retrieval is, about 73% of the time. Here's the real failure map and what to fix first.
ReadWhy I don't use LangChain in production RAG
Frameworks are great for a demo. In production, the abstraction you can't see into costs more than it saves.
ReadGet new essays by email
Occasional field notes on production RAG and LLM systems. No spam, unsubscribe anytime.