Which dense, sparse, and compact embedding families should you compare?

Compare at least one model from each representation family, not just several large dense encoders. Dense models capture meaning and paraphrase; learned sparse models such as SPLADE keep exact terms and identifiers while adding related words; multi-output models such as BGE-M3 produce both from one pass; and compact static models trade some quality for very cheap encoding. Milvus stores each as a different field type, so you can test them side by side and combine the winners with hybrid search.

Shortlist models by the workload. Keep model revisions separate; equal dimensions do not mean equal spaces. Shortlist models by the workload. Keep model revisions separate; equal dimensions do not mean equal spaces.

How do the representation families differ?

FamilyWhat the vector looks likeStrong atWeak atMilvus field
Dense contextual encoderA few hundred to a few thousand floats, all non-zeroParaphrases, synonyms, cross-language meaningRare identifiers, codes, exact namesFLOAT_VECTOR (or FLOAT16/BFLOAT16/INT8)
BM25 (classical sparse)Vocabulary-sized vector of term weights from a fixed formulaExact keywords, no training neededSynonyms and paraphraseSPARSE_FLOAT_VECTOR generated by a BM25 Function
Learned sparse (SPLADE-style)Vocabulary-sized vector; a model chooses which terms matter and adds related termsExact terms plus expansion; interpretable weightsLarger index than BM25; out-of-vocabulary IDs still hardSPARSE_FLOAT_VECTOR
Multi-output (BGE-M3, mGTE)Dense vector plus sparse weights, and for BGE-M3 also token vectorsOne model feeds hybrid searchEach output still needs its own field and indexDense + sparse fields, optional embedding list
Instruction-conditioned denseDense, but the query carries a task instruction or prefixAdapting one model to several tasksWrong or missing prompts quietly hurt qualityFLOAT_VECTOR
Static (Model2Vec-style)Dense vector built from precomputed token embeddings, no transformer at inferenceExtremely fast CPU encoding, tiny footprintContext-dependent meaning, negation, long queriesFLOAT_VECTOR

Two terms are easy to confuse. A mixture-of-experts encoder activates only part of its network per token, but its output is still a normal dense vector, not a sparse one. And Matryoshka models are dense models trained so the first N dimensions of the output still work on their own, which lets you store shorter vectors; truncate only to the sizes the model card documents.

When should you choose dense, sparse, or both?

Dense retrieval is the right default for natural-language questions over prose: support articles, documentation, chat history. It finds “how do I cancel my plan” when the document says "ending your subscription".

Sparse retrieval matters when users type the exact thing they want: SKUs, error codes, function names, legal citations, drug names. Dense models often blur these because similar-looking codes land near each other. BM25 is the cheapest sparse option and needs no model at all; learned sparse models usually beat BM25 on benchmarks by learning which terms to weight and which related terms to add, at the cost of model inference and a larger inverted index.

In practice the strongest setup for mixed workloads is hybrid: a dense field and a sparse field over the same text, searched together and fused. If your evaluation shows dense-only misses identifiers or sparse-only misses paraphrases, that is the signal to go hybrid. See what hybrid search is and when to use it and how a sparse inverted index differs from dense ANN.

Compact and static models earn a place on the shortlist when encoding cost dominates: billions of short records, edge devices, or a quick baseline that tells you how much a large model actually adds.

Families worth putting on the shortlist

These are well-documented representatives of each family, not a ranking. Check the live MTEB leaderboard for current scores and each model card for prompts, pooling, and license.

ModelFamilyNotes for evaluationPyMilvus Model route
BAAI/bge-m3Dense + sparse + token vectorsOver 100 languages and long inputs; pick which outputs you needBGEM3EmbeddingFunction
Alibaba-NLP/gte-multilingual-baseDense + sparseMultilingual; store each output in its own fieldMGTEEmbeddingFunction
naver/splade-cocondenser-ensembledistilLearned sparseTokenizer vocabulary and model revision define the index; change either and re-encodeSpladeEmbeddingFunction
intfloat/multilingual-e5-large-instructInstruction-conditioned denseFollow its query instruction format; test cross-language questionsGeneric Sentence Transformers route
hkunlp/instructor-xlInstruction + textTakes instruction/text pairs, not concatenated stringsInstructorEmbeddingFunction
nomic-ai/nomic-embed-text-v1.5Task-prefixed dense, MatryoshkaRequires task prefixes; supports documented shorter dimensionsNomicEmbeddingFunction
nomic-ai/nomic-embed-text-v2-moeMultilingual MoE denseSparse activation inside, dense vector outGeneric or native Nomic route
Snowflake/snowflake-arctic-embed-l-v2.0Retrieval-tuned denseCheck its prompt, normalization, and language coverageGeneric Sentence Transformers route
KaLM-Embedding/KaLM-embedding-multilingual-mini-instruct-v2.5Compact instructed denseKeep its mean pooling and query instructionsGeneric or official implementation
maidalun1020/bce-embedding-base_v1Chinese/English denseAn established bilingual baselineGeneric or official implementation
minishlab/potion-base-8MStatic denseVery cheap encoding; test hard, context-dependent queriesModel2VecEmbeddingFunction
sentence-transformers/all-MiniLM-L6-v2Compact dense baselineGood for plumbing tests; short input limit and English-centricSentenceTransformerEmbeddingFunction

A dedicated wrapper means PyMilvus Model knows how to call that family; it still has to match the exact checkpoint’s prompts, arguments, and output. A generic wrapper or a package dependency does not certify every model a provider publishes. The Milvus Model support matrix lists what each wrapper actually handles.

How do you store each family in Milvus?

Dense output goes in a FLOAT_VECTOR field whose dim matches the model, indexed with a metric the model card recommends (usually COSINE or IP for normalized vectors). Learned sparse output goes in a SPARSE_FLOAT_VECTOR field, which needs no dimension, accepts dictionaries like {2: 0.33, 98: 0.72}, and is indexed with SPARSE_INVERTED_INDEX using the IP metric. For BM25 you do not need a model: add a BM25 Function that turns a text field into a sparse field automatically.

A multi-output model such as BGE-M3 fills both fields from one encoding pass:

from pymilvus.model.hybrid import BGEM3EmbeddingFunction

ef = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
docs_emb = ef(docs)            # {"dense": [...], "sparse": ...}
# insert docs_emb["dense"] into a FLOAT_VECTOR field
# and docs_emb["sparse"] into a SPARSE_FLOAT_VECTOR field

At query time, build one AnnSearchRequest per field and call hybrid_search with an RRF or weighted ranker to fuse the two result lists. BGE-M3’s token-level vectors are a third, multi-vector representation; they belong in an embedding list, described in multi-vector retrieval.

Run a fair comparison

Keep the documents, chunking, and relevance judgments fixed, and encode them once per candidate into separate fields or collections. Your query set should deliberately include rare identifiers, synonyms and paraphrases, cross-language questions, and queries with no correct answer, because that is where the families separate. Measure first-stage recall on its own before adding a reranker, and report encoding throughput and memory, vector storage, and filtered query latency next to quality.

Two rules prevent most mistakes: never mix vectors from different models in one field even if the dimensions match, and record the model revision, prompts, and normalization alongside every collection so the comparison can be reproduced.

Related reading

Next step: build a dense-plus-sparse collection with the multi-vector hybrid search guide, or get a local instance running with the Milvus Quickstart.

Sources and further reading

Like the article? Spread the word