Home / How it works / Sparse Vectors Explained: What They Are and Where They Win
ExplainerSparse Vectors Explained: What They Are and Where They Win
A sparse vector is a very long vector, usually with one position per vocabulary term, in which almost every value is zero. Only the few terms a text contains carry a weight. Because so few positions are used, systems store only the non-zero entries as index and value pairs. In a small example, the phrase “password rules and password expiry” uses just 6 of 30,522 positions, or 48 bytes instead of 122,088. Sparse vectors power keyword search: BM25 scores can be read as sparse vectors, and Weaviate calls its BM25F keyword search “sparse vector” search. Learned models such as SPLADE produce sparse vectors that also add related terms. Sparse vectors win on exact terms, codes, and unfamiliar domains, and pair with dense vectors in hybrid search.
Sparse vectors in four facts
- Each position stands for a term; a text sets only the positions of the terms it contains.
- Only non-zero entries are stored, as index and value pairs, so sparse vectors are cheap to keep.
- Search uses an inverted index that lists, for each term, the documents containing it.
- Weights can be counts, TF-IDF, BM25, or learned by a model such as SPLADE.
What is a sparse vector?
A sparse vector is a vector in which most values are zero, so it is described by listing only its few non-zero positions and their values. In search, each position usually represents one term from a vocabulary.
The idea is easiest to see by contrast. A dense vector from an embedding model has a few hundred values, almost all non-zero, with no readable meaning per position. A sparse vector for the same text might have tens of thousands of positions, one per vocabulary term, with only a handful set. Weaviate’s hybrid search guide puts it simply: sparse vectors have mostly zero values, with only a few non-zero values.
Each non-zero value says how much a term matters to the text. In the simplest case it is a count of how often the term appears. In BM25 it is a weight that accounts for how rare the term is and how long the document is. In a learned model it is whatever weight the model assigns.
Sparse vectors are often called sparse embeddings when a model produces them. The name covers both classic keyword representations and modern learned ones. A real example makes the structure concrete.
What does a sparse vector look like?
A sparse vector looks like two short lists, one of term positions and one of weights, standing in for a much longer list that is almost entirely zeros. We built a few to show real values.
We used the WordPiece vocabulary of the all-MiniLM-L6-v2 model, which has 30,522 tokens. Each text becomes a sparse vector of token counts. The phrase “reset your password” sets three positions:
indices: [2115, 20786, 25141] # your, password, reset
values: [1, 1, 1]
(all other 30,519 positions are 0)
“Password rules and password expiry” sets six positions. “Password” appears twice, so its value is 2. “Expiry” is not in the vocabulary as one token, so the tokenizer splits it into three pieces: “ex,” “##pi,” and “##ry.” Even so, the vector uses only 6 of 30,522 positions, or about 0.02%.
That emptiness is the point. Stored as pairs of a 4-byte index and a 4-byte value, those six entries take 48 bytes. Stored as a full array of 4-byte floats, the same vector would take 122,088 bytes. The structure also shapes how these vectors are searched.
How are sparse vectors stored and searched?
Sparse vectors are stored as index and value pairs, and searched with an inverted index that maps each term to the documents containing it. A query touches only the lists for its own terms.
An inverted index flips the sparse vectors around. Instead of storing, for each document, the terms it contains, it stores, for each term, the documents that contain it. Weaviate’s documentation describes this for its own engine: the inverted index maps tokens to the objects that contain them, with a separate index per property.
Scoring is a dot product: multiply the query’s weight for each term by the document’s weight for that term, and add the results. Only shared terms contribute, because every other product is zero. For the query “password reset” in our example, D1 scores 2, D2 scores 0, and D3 also scores 2. D3 earns its points by repeating “password,” not by mentioning a reset.
That tie shows why raw counts are not enough. D1 is clearly the better answer, but plain counting cannot tell. Engines add tricks for speed too: Weaviate uses the BlockMax WAND algorithm, from version 1.30, to skip blocks of the index that cannot reach the top results. Breaking ties like D1 and D3 is the job of the weights.
How are the weights in a sparse vector chosen?
The weights in a sparse vector are chosen by a scoring scheme, from raw term counts to TF-IDF and BM25, or learned by a neural model. Better weights make the dot product reflect relevance.
| Scheme | Weight for a term | Fixes |
|---|---|---|
| Binary or count | 1 if present, or the number of occurrences | Nothing; every term counts the same |
| TF-IDF | Count multiplied by how rare the term is | Common words stop dominating |
| BM25 | Saturated count, rarity, and length normalization | Repetition and long documents stop dominating |
| Learned (SPLADE and similar) | A model’s predicted importance, including added terms | Vocabulary mismatch, partly |
Under BM25, the tie in our example breaks in D1’s favor. “Reset” appears in only one document, so it carries a high weight, while “password” appears in two and carries less. Repeating “password” in D3 also adds less with each mention, because BM25 saturates repeated terms. TF-IDF covers the older scheme.
These classic schemes share one limit: a term can only get weight if it appears in the text. A document about “resetting credentials” scores zero for “password.” Learned sparse models were built to relax that limit.
How do learned sparse embedding models work?
Learned sparse embedding models work by running a transformer over the text and predicting a weight for every vocabulary term, then keeping only the strongest weights so the result stays sparse. The model can give weight to related terms the text never used.
SPLADE, introduced by Formal, Piwowarski, and Clinchant at SIGIR 2021, is the best-known example. It predicts term weights from a BERT-style model and adds a sparsity penalty during training, which pushes most weights to zero. The output still fits an inverted index and still matches exact terms, but now carries some of a dense model’s sense of meaning.
Qdrant’s walkthrough of SPLADE shows the expansion in numbers. A text that tokenizes to 38 tokens produced a sparse vector with 102 non-zero terms. The extra terms are the model’s guesses at related vocabulary, each with its own weight. Its example query, “solar energy advantages,” gains weight on related terms that the query did not contain.
The cost is a model at both indexing and query time, like a dense embedding model. The vectors also stay tied to the model’s tokenizer, so a term outside its vocabulary is split into pieces, as “expiry” was. SPLADE and learned sparse retrieval goes further. Search engines differ in which kinds of sparse vectors they accept.
How do Weaviate, Elasticsearch, and Qdrant handle sparse vectors?
Weaviate handles sparse vectors through its built-in BM25F keyword index, while Elasticsearch and Qdrant also accept sparse vectors produced by learned models. All three use inverted indexes underneath.
- Weaviate: its keyword search computes BM25F scores from an inverted index built per property, which Weaviate’s docs describe as sparse vector search. Its documentation states that the current hybrid search implementation uses BM25 or BM25F alongside vector search. You configure tokenization, stopwords, and BM25 parameters rather than supplying sparse vectors yourself.
- Elasticsearch: a
sparse_vectorfield and query store and search learned sparse vectors, such as those from its ELSER model or models from Hugging Face, on Lucene’s inverted index. - Qdrant: collections can hold named sparse vectors, given as lists of indices and values, searched through an inverted index.
All three engines share the same mechanics underneath. Each keeps an inverted index, reads only the posting lists for the query’s terms, and scores by summing per-term contributions. They differ in where the weights come from: a fixed formula such as BM25F in Weaviate, or a model whose output you store, as in Elasticsearch and Qdrant.
The practical difference is who makes the vectors. In Weaviate the engine builds the sparse side from your text, so there is nothing to compute. In engines that take learned sparse vectors, you run the model and send the pairs. Both approaches meet in hybrid search, where the sparse results are fused with dense ones. Which side should lead depends on the queries.
When do sparse vectors beat dense vectors?
Sparse vectors beat dense vectors when queries hinge on exact terms, such as product codes, names, error messages, and rare jargon, and when a dense model meets a domain it was not trained on. Dense vectors win on paraphrase and synonyms.
Exact terms favor sparse because the match is literal. An error code like “ERR_CONN_RESET” either appears or it does not, and a rare term gets a high weight under BM25. A dense model may blur such strings into something merely similar.
Unfamiliar domains favor sparse because nothing has to be learned. The BEIR benchmark, from Thakur and colleagues, found BM25 a robust baseline when retrieval models were tested outside their training domains. Sparse vectors are also explainable: each match traces to a term you can show the user.
Dense vectors win when people describe ideas in their own words. “Laptop sleeve” against “notebook case” shares no terms, so a classic sparse vector scores zero. That split is why most systems use both, as dense versus sparse vectors compares in detail. The word “sparse” has a wider life in mathematics too.
What is a sparse matrix used for?
A sparse matrix is used to store and compute with large tables that are mostly zeros, such as document-term matrices in search, graph adjacency matrices, and the equations of engineering simulations. A collection of sparse vectors is one such matrix.
Storing every zero would waste memory, so sparse matrices use compact formats. Common ones include a dictionary of keys, a coordinate list of row, column, and value triples, and compressed sparse row, or CSR. CSR uses three arrays: the non-zero values, their column positions, and where each row starts. The term “sparse matrix” is often credited to the economist Harry Markowitz, who did early work on the subject.
Search engines apply the same idea. Stack every document’s sparse vector into rows, and you get a document-term matrix that is almost entirely empty. An inverted index is, in effect, that matrix stored by column, one list per term. Related pages include the inverted index, keyword search, sparse retrieval, and dense versus sparse retrieval.
A sparse vector marks only the terms a text contains, out of a vocabulary of tens of thousands, and stores just those index and value pairs. In our example a six-term phrase used 0.02% of its positions and 48 bytes. Weights decide quality: raw counts tied two documents that BM25 separates easily, and learned models like SPLADE add related terms. Weaviate provides the sparse side through BM25F keyword search, while Elasticsearch and Qdrant also accept learned sparse vectors. The practical step is to keep sparse retrieval for exact terms and unfamiliar domains, and combine it with dense vectors through hybrid search.