﻿# Milvus BM25 functions: combine server-generated sparse and dense retrieval

Milvus can generate BM25 sparse vectors from raw text through a declared function while searching a separate dense representation.

Author: Retrivium team
Updated: 2026-11-03
Canonical URL: https://retrivium.ai/journal/milvus-bm25-function-dense-sparse-fusion/
Language: en

Milvus can generate BM25 sparse vectors from raw text through a declared function while searching a separate dense representation. Treat those paths as different retrieval signals whose inputs, fields and fusion must remain visible in the collection design.

## Trace text into the sparse field

The [full-text search documentation](https://milvus.io/docs/full-text-search.md) describes the text field, analyzer, BM25 function, sparse output and index as distinct parts of the schema. The function output is not an arbitrary external embedding pasted into a field with a convenient name. Preserve how that field is populated. Otherwise a query can appear to use BM25 while the stored representation was produced through another route.

## Keep functions tied to their fields

The checked documentation specifies one input field and one output field for a BM25 function. Several text properties therefore need an explicit design rather than a hidden assumption that one function interprets every field automatically. Decide whether titles and body text are separate evidence paths or deliberately serialized into one input. Keep that decision consistent when inserting documents and forming queries so missing title evidence can be diagnosed.

## Add dense retrieval deliberately

The [multi-vector hybrid-search guide](https://milvus.io/docs/multi-vector-search.md) uses separate search requests before ranking their results together. A semantic encoder can recover paraphrases that lexical matching misses, while exact codes may need a lexical path. Those are motivations for an experiment, not guarantees for every corpus. Export each branch result and its document IDs before evaluating fusion. A document absent from both branches cannot be recovered by changing only the final ranker.

## Use mixed query types as a fixture

Create an illustrative product-document set containing exact error codes, ordinary descriptions and paraphrased questions. Keep source text identical across representations. Judge whether each required passage enters the candidate lists and then whether the combined order is useful.

| Query type | Evidence to inspect |
|---|---|
| Exact code | Tokenization and lexical candidates |
| Paraphrase | Dense representation and candidates |
| Mixed question | Contribution from both paths |

This fixture identifies retrieval roles without inventing a universal accuracy advantage or benchmark result.

## Separate analyzer and fusion changes

The [official architecture overview](https://milvus.io/solutions/hybrid-search) places lexical and vector work inside a hybrid search flow. That does not remove their independent contracts. An analyzer change can alter sparse candidates before fusion happens. An embedding update can alter dense candidates independently. Test those changes separately and preserve original lists. Otherwise a later score improvement may be credited to the wrong component, making the result difficult to reproduce or transfer to another collection.

## Accept ingestion and search together

Insert a small known document set, confirm the expected generated fields, and execute the saved query fixture. Include a source update so the test exercises more than initial indexing. Record function definitions, analyzer settings, dense checkpoint and ranker configuration. The final artifact should explain how raw evidence becomes both representations and which observed failures each stage addresses, rather than merely saying that hybrid search was enabled.

Related reading: [A local RAG server: placing components around the GPU](/journal/rag-server-local-architecture/); [Embeddings and rerankers: other tasks for an idle GPU](/journal/embeddings-rerankers-gpu/).
