What Is Hybrid Search in Elasticsearch?
A complete, plain-English guide to combining keyword search and vector search in one request: why each one alone falls short, how their results are merged into a single ranking, and how to build, tune, secure, and measure a hybrid search that people actually trust.
Picture a library with two very different librarians. The first, Elena, has memorized every title, author, and catalog code. Ask her for “ISBN 978-0-14-312854-0” and she walks straight to the shelf. But describe a book vaguely, “that story about a boy and a whale-sized fish,” and she is lost, because none of your words match the title. The second librarian, Marco, understands topics deeply. He recognizes your vague description at once. But ask him for a precise code, and he may hand you a book that is merely similar.
A wise library asks both librarians and lets a head librarian merge their recommendations into one list. Books that both suggest go to the top. Books that only one suggests still appear, in a sensible place. That is hybrid search. In Elasticsearch, Elena is keyword search, which matches the exact words in a query against an inverted index. Marco is vector search, which matches meaning by comparing embeddings. Hybrid search runs both, merges their results, and returns one ranked list that is better than either alone. This guide starts from zero, opens the machinery step by step, and ends with the numbers, the choices, and the habits that keep a hybrid search accurate, fast, and safe in production.
1What Hybrid Search Actually Is
Three plain ideas, put together: two ways of finding, one list of results, and a rule for merging them.
Elasticsearch can find documents in two quite different ways. The first is lexical search, also called keyword or full-text search. It breaks the query into terms, looks those terms up in an inverted index, and ranks documents by how well their words match, using a scoring formula called BM25. It is fast, precise, and easy to explain: a document matched because it contains the words you typed.
The second is semantic search. Here, the query and the documents are turned into vectors, lists of numbers that capture meaning, by an embedding model. Documents whose vectors lie closest to the query vector are returned. It finds paraphrases and related ideas even when no words are shared. But it is less precise with exact strings, and harder to explain.
Hybrid search uses both at once. A single request contains a lexical part and a semantic part. Elasticsearch runs each part, collects two ranked lists of candidate documents, and merges them into one final ranking. The merging rule is the heart of hybrid search, and much of this guide is about how to choose it well.
Two judges score a talent contest. One judge counts technical skill with a checklist, exact and measurable. The other judge feels the overall impression, artistic and holistic. Neither judge alone is reliable. Combining their views, with a fair rule for how much each counts, gives a result that both accurate and rounded. Hybrid search is that panel of two judges.
What it is not
Hybrid search is not a separate field type or a separate index. It is a way of asking. The documents still contain ordinary text fields, which have inverted indexes, and they also contain vector fields, which have graphs. Hybrid search is the request that uses both. It is also not a single fixed recipe. Elasticsearch offers several ways to combine the two legs, and the best one depends on your data, your users, and your tolerance for tuning. Finally, hybrid search is not the same as a filter plus a search. A filter narrows the set of documents. Hybrid search changes how the remaining documents are ranked.
The word “hybrid” is sometimes used loosely. Here it means combining lexical retrieval and semantic retrieval in one request. It does not mean combining several fields, several indexes, or several clusters, although you can do those too. The semantic leg may use dense vectors, or a related kind called sparse vectors, and both count.
The one-sentence version
If you remember one line from this chapter, make it this: hybrid search runs a keyword search and a vector search for the same query, then merges the two ranked lists into one, so that exact matches and meaning-based matches both have a fair chance of appearing near the top.
2Why It Exists: Two Tools With Opposite Weaknesses
Hybrid search is not a fashion. It is an answer to a specific fact: keyword search and vector search fail in opposite ways.
Keyword search fails when the words do not match. A user types “cheap flights” and the page says “budget airfare.” A user types “how do I fix a leaking tap” and the article is titled “Repairing a dripping faucet.” The engine has no way to know that these are the same ideas. Search engineers built synonym lists, stemming, and spelling correction to patch this, with partial success.
Vector search fails when the words must match. A user types a part number, an error code, a person’s surname, an abbreviation, or a rare technical term. An embedding model may blur these into something similar rather than exact. It may return documents about a similar-looking part number, or about a different person with a related name. For queries where the exact string is the whole point, keyword search is simply better.
Real users send both kinds of queries, sometimes in the same session, sometimes in the same sentence: “error 0x80070057 when installing update.” A search engine that handles only one kind serves half of its users badly. Hybrid search removes the need to choose.
| Query type | Keyword search | Vector search | Hybrid search |
|---|---|---|---|
| Exact identifier, code, or SKU | Excellent | Weak | Excellent |
| Person or product name | Strong | Uneven | Strong |
| Rare technical term or acronym | Strong | Uneven, depends on the model | Strong |
| Paraphrase or long natural question | Weak | Strong | Strong |
| Vague description of what you want | Weak | Strong | Strong |
| Mixed: a code plus a description | Partial | Partial | Strong |
| Different language from the documents | Fails | Works with a multilingual model | Works, with keywords as a backstop |
| Explaining why a result matched | Easy | Hard | Partly easy |
A map app that shows only street names is precise but helpless if you do not know the street. An app that shows only satellite pictures gives a feel for the area but cannot tell you the house number. Most people want both layers on the same screen, and can switch attention between them as needed.
A short history
Keyword search everywhere
For most of its life, Elasticsearch was a lexical engine. Relevance was improved with analyzers, synonyms, boosts, and careful field design.
Vectors arrive
Around version 8, vector search became a first-class feature, with indexed approximate nearest-neighbor search over dense vectors.
Combining in one request
Soon after, a single request could carry both a query and a vector search, with their scores added together using weights.
Rank-based fusion
A method called reciprocal rank fusion was added, which merges lists by position instead of by score, avoiding the problem that the two kinds of score are on different scales.
Retrievers and managed semantic fields
A composable way of describing multi-stage searches, called retrievers, appeared, along with fields that manage embeddings automatically and options for reranking with stronger models.
The exact release for each step is worth double-checking in the release notes of your version. The direction of travel is what matters: from “choose one method” to “run both and merge them well, then refine the top with a stronger model.”
Why the keyword side stays essential
It might seem that vectors, being smarter, should replace keywords entirely. Experience says otherwise. Independent evaluations of retrieval systems have repeatedly found that a well-tuned keyword search is a hard baseline to beat, especially on data unlike what an embedding model was trained on, such as specialist vocabularies, product catalogs, and internal jargon. Vectors often win on natural language questions, and often lose on exact terms. The combination tends to beat both, which is why hybrid search has become the default recommendation for many production systems.
3Core Concepts You Need First
A dozen words explain nearly everything about hybrid search. Learn them here, and later chapters will read like common sense.
Lexical retrieval
Finding documents by the words they contain, using an inverted index and a scoring formula such as BM25.
BM25
The default keyword scoring formula. It rewards rare terms, repeated terms with diminishing returns, and matches in short fields.
Semantic retrieval
Finding documents by meaning, using vectors made by an embedding model and a nearest-neighbor search.
Embedding and vector
A list of numbers that stands for the meaning of a piece of content. Close vectors mean similar meaning.
Dense and sparse vectors
Dense vectors have a meaningful number in every position. Sparse vectors hold a few weighted terms, including related ones.
Candidate list
The ranked documents that one leg returns, before merging. Each leg produces its own.
Rank window
How many top results from each leg are taken into the merge. Documents outside the window cannot be rescued.
Score fusion
Combining the scores of the two legs, usually after scaling, with weights that say how much each counts.
Reciprocal rank fusion
Combining the positions of a document in each list, not the scores, so that scales do not matter.
Reranker
A stronger, slower model that re-orders the top of the merged list by reading the query and each document together.
Recall and precision
Recall asks how many of the good documents were found. Precision asks how many of the returned ones are good.
Ranking metric
A number, such as nDCG, that scores how well a ranked list puts the best documents first.
Scores and ranks are different things
This distinction is the key to understanding fusion. A score is a number that a search leg gives a document: 12.4 for one, 8.1 for another. A rank is the position: first, second, third. Scores carry extra information, such as how much better the first result is than the second. But scores from different legs are on different scales and mean different things. A keyword score of 12.4 and a vector score of 0.84 cannot be added meaningfully. Ranks, on the other hand, are comparable across lists, because “third place” means the same thing in any contest.
Two contests are held: a weightlifting event scored in kilograms, and a diving event scored out of ten. Adding kilograms to points makes no sense. But you can ask, “who came first, second, and third in each?” and combine the placings. The placings are ranks, and they can be compared across different kinds of contests.
Recall first, precision later
Hybrid search is usually built in stages. The first stage, retrieval, should be generous. Its goal is high recall: make sure that the good documents are among the candidates, even if many bad ones come along. Later stages, such as merging and reranking, aim at precision: put the best candidates at the top. Using two legs increases recall, because a document that one leg misses may be found by the other. This staged thinking explains most design choices in this guide.
Why the two legs see different worlds
The lexical leg sees only terms after analysis: lowercased, split, perhaps stemmed. The semantic leg sees only vectors: positions on a map. They share no internal structure, so each can find documents the other cannot see. That is exactly why they complement each other, and exactly why merging their scores is tricky.
A hybrid search is only as good as its weakest leg. If the embedding model is a poor match for your content, or the analyzers are misconfigured, one leg will add noise instead of value. Test each leg on its own before you judge the combination.
Quick glossary
| Word | Plain meaning |
|---|---|
| Inverted index | The structure that maps each term to the documents that contain it. |
| kNN | k-nearest-neighbor search: return the k stored vectors closest to a query vector. |
| Fusion | Merging several ranked lists into one. |
| Normalization | Rescaling scores to a common range so that they can be combined. |
| Boost | A multiplier that makes a query part count more or less. |
| Cross-encoder | A model that reads the query and a document together and scores their match. Used for reranking. |
| Bi-encoder | A model that embeds queries and documents separately. Used for vector retrieval. |
| Chunk | A short piece of a long document, embedded and searched on its own. |
4Architecture and Components
Where do the two legs live, how do their results meet, and what happens after the merge?
A hybrid search touches the same documents in two different structures. The text fields of each document are held in inverted indexes, one per field per segment. The vector fields are held in vector files and graphs, one per field per segment. The request runs a lexical search against the first and a vector search against the second. The results meet at a merge step, and optionally pass through a reranker before going back to the user.
flowchart TB
U["User query"] --> QU["Query understanding: clean, classify, and expand"]
QU --> LX["Lexical leg: BM25 over the inverted index"]
QU --> EM["Embedding step: turn the query into a vector"]
EM --> SM["Semantic leg: nearest-neighbor search over vectors"]
LX --> FU["Fusion: merge the two ranked lists"]
SM --> FU
FU --> RR["Optional reranker: re-order the top results"]
RR --> OUT["Final ranked results"]
Read the picture from top to bottom. The user’s query may first be cleaned or classified. Then two things happen in parallel: the lexical leg searches the inverted indexes using the words of the query, and the query is embedded and used by the semantic leg to search the vectors. Each leg returns a ranked list of candidates. The fusion step merges the two lists into one. An optional reranker then re-orders the best candidates using a stronger model. The final list goes back to the user.
The main components
Query understanding
Optional steps that clean the query, detect its type, correct spelling, or expand it, before the legs run.
Lexical query
A match, multi-field match, phrase, or combined query over text fields, scored with BM25.
Embedding model
Turns the query into a vector, or into weighted terms for sparse models. Runs inside the cluster, or through a service.
Vector query
A nearest-neighbor search over a dense vector field, or a query over a sparse vector field.
Fusion step
Combines the two ranked lists, by adding weighted scores or by combining ranks.
Reranker
A stronger model, often a cross-encoder, that reads query and text together to re-order the top candidates.
Filters
Conditions such as permissions, language, and availability that restrict the candidates of both legs.
Evaluation tools
Ways to score the quality of rankings against judged examples, and to compare configurations.
Two structures, one document
A key point of the architecture is that the same document carries both representations. A product might have a title and a description, indexed as text, and also a vector made from its title and description, stored in a vector field. The document has one identifier, so when both legs return the same document, the fusion step can recognize it and combine its evidence. Documents that only one leg found are still kept, with evidence from one side.
A book in the library has a card in the title catalog and a place on the subject map. A visitor who asks for “the whale story” may find it through the subject map, and a visitor who asks for “Moby Dick” finds it through the title catalog. The book is the same, and the librarian can tell that the two searches point to it.
Walking one hybrid search through the machine
The user types a query
For example, “waterproof jacket for hiking in rain, model XR-450.”
The request carries both parts
A lexical part with the words, a vector part with the query embedding, and shared filters.
Each shard runs both searches
The inverted indexes are searched for the words. The vector graphs are searched for close vectors.
Candidate lists are collected
The coordinating node gathers the top candidates of each leg from all shards.
The lists are fused
Documents found by both legs, such as a jacket with the model number in its title and matching meaning, rise to the top.
The top is optionally reranked
A stronger model reads the query and the best candidates and refines the order.
The documents are fetched and returned
The final winners are loaded and sent back, with any highlights and fields.
Every box in the picture is a place where quality can be won or lost, and where time and money are spent. The rest of this guide takes them one by one: the two legs, the fusion, the reranker, and the surrounding pieces of filtering, data modeling, and evaluation.
5The Lexical Leg: Getting the Keyword Side Right
A hybrid search is only as strong as its two legs. The keyword leg is older and better understood, and worth tuning first.
How the lexical leg finds documents
The query text passes through an analyzer, which splits it into terms, lowercases them, and applies the same kind of processing that was applied to the documents. For each term, Lucene reads the postings list of documents that contain it, combines the lists according to the query, and scores each matching document with BM25. The score depends on how rare the term is in the collection, how often it appears in the document, and how long the field is. A rare term in a short title counts far more than a common term in a long body.
Think of a detective looking for a suspect. A rare distinguishing mark, such as a scar in an unusual place, is worth far more than a common feature, such as brown hair. And a clue found in a short, focused report is worth more than the same clue buried in a thousand pages.
Choosing the lexical query
| Query style | What it does | When to use it |
|---|---|---|
| Match on one field | Analyzes the text and matches any or all terms | Simple cases, single text fields |
| Multi-field match | Searches several fields, with different weights | Titles, descriptions, and tags searched together |
| Phrase match | Requires terms to appear next to each other | Boosting exact wording |
| Combined boolean query | Mixes required, optional, and excluded clauses with filters | Most production lexical legs |
| Exact-value term match on keyword fields | Matches identifiers and codes exactly | SKUs, IDs, status codes |
| Fuzzy match | Tolerates small spelling errors | User typos in names and words |
What makes a strong lexical leg
Sensible analyzers
Lowercasing, appropriate stemming, and the right language handling, applied the same way at indexing and search time.
Field weights
A match in a title should count more than a match in a footer. Give fields boosts that reflect their value.
Keyword fields for codes
Store identifiers in keyword fields so that an exact code matches exactly, and not as a set of stemmed pieces.
Phrase boosts
Reward documents where the query words appear together, in order.
Synonyms and spelling
A small, curated synonym list for known terms and abbreviations, plus tolerance for typos.
Conditions as filters
Put yes-or-no conditions in filter context, so that they do not distort scores and can be cached.
The lexical leg is a strong baseline
Before adding vectors, it pays to know how good the keyword side is on its own. Build a set of real queries with judgments, measure it, and improve it with analyzers, field weights, and synonyms. Many teams find that a carefully tuned keyword leg solves a large share of their problems, and that vectors then add value on the remaining hard cases. The measurement also gives you a baseline that hybrid search must beat, or it is not worth its extra cost.
Where keywords are weak
- Vocabulary mismatch. The query uses different words from the documents.
- Long natural questions. Many function words and little signal, which can dilute matching.
- Intent. The user’s goal is not stated in any word of the query.
- Cross-language search. Words in one language never match words in another.
- Very short documents. Few terms to match, so many relevant items are missed.
Whatever you add on the vector side, make sure that an exact identifier typed by a user still finds its document at the very top. A hybrid system that loses this basic ability, because vector scores pushed a near-match above the exact one, will erode trust quickly. Test exact lookups explicitly.
6The Semantic Leg: Getting the Meaning Side Right
The second leg finds documents by meaning. There is more than one way to build it, and each has its own strengths.
Three ways to build the semantic leg
Dense vectors
An embedding model turns text into a list of hundreds of numbers, stored in a dense vector field and searched by nearest neighbor. Strong on paraphrase and, with the right model, on many languages.
Sparse vectors
A learned model expands text into a small set of weighted terms, including related words that were not in the text. The terms are stored and searched much like ordinary keywords, so results are easier to explain.
A managed semantic field
A field type that calls a model for you, chunks long text, and stores the embeddings, so you index text and search text, and the machinery stays out of sight.
Dense vectors are like describing a painting by its overall feeling. Sparse vectors are like adding extra tags to a photo: you write “beach” and the system also tags “sea,” “sand,” and “holiday.” The tagged photo can still be found by ordinary tag search, while the feeling-based description needs a special kind of comparison.
How the dense leg works
The query is turned into a vector by the same model that produced the stored vectors. Elasticsearch then searches the graphs of each segment for the vectors nearest to it and returns the closest documents, with a score that grows as closeness grows. You control how many neighbors are wanted, and how many candidates each shard examines. More candidates find more of the true neighbors, but cost more time. A minimum similarity can be set, so that results below it are dropped.
How the sparse leg works
At indexing time, a model reads each document and produces a set of terms with weights, for example “hiking 1.9, trail 1.4, boots 1.1, outdoor 0.8, mountain 0.6,” where some terms were never in the text. These are stored in a sparse vector field. At search time, the query is expanded the same way, and documents are ranked by the overlap of weighted terms. Because it is built on term overlap, it works like keyword search with a learned vocabulary. It needs no graph, uses less memory than dense vectors, and lets you see which terms drove a match.
| Aspect | Dense vectors | Sparse vectors |
|---|---|---|
| What is stored | A list of hundreds of numbers per document or chunk | A small set of weighted terms |
| Finds paraphrases | Yes, strongly | Yes, through learned expansion |
| Explainable | Hard | Easier, terms are visible |
| Memory needs | High, needs cache for vectors and graphs | Lower, similar to keyword indexes |
| Works across languages | Yes, with multilingual models | Depends on the model |
| Indexing cost | Graph building | Model inference, then ordinary indexing |
| Typical role | General semantic retrieval | Semantic retrieval that stays close to keywords |
Choosing the model
The choice of model shapes the semantic leg more than any setting. It must fit your language, your content type, and your budget. Test candidate models on your own queries before you commit, and remember the rule that queries and documents must be embedded by the same model. A more detailed treatment of models, dimensions, similarity metrics, and quantization is beyond this guide, but the essential point is that hybrid search inherits the strengths and weaknesses of whichever model you pick.
Chunking for the semantic leg
A vector for a long document blurs many ideas together. The usual answer is to cut long content into chunks of a few hundred words, embed each, and search the chunks. This has consequences for hybrid search: the semantic leg now returns chunks, while the lexical leg may return whole documents. Chapter 12 covers how to line the two up, so that fusion compares like with like.
The semantic leg on its own is not enough
Exact strings blur
A part number may be matched to similar-looking numbers.
Rare terms are uneven
Words that the model rarely saw in training may be placed poorly.
Results are hard to explain
A closeness score does not tell a user or a developer why a document matched.
Every query costs a model call
Embedding the query adds delay and, for outside services, money.
Approximate results
The graph search may occasionally miss a true neighbor.
A vector score of 0.85 for one query does not mean the same as 0.85 for another. Scores depend on the model and the query. Do not use fixed score thresholds across all queries without testing, and do not assume that a high score means a correct answer.
7Combining by Scores: Weighted Fusion
The most direct way to merge two legs is to add their scores. It works, but only when you handle one important problem.
The simple approach
In a single request, you can send a lexical query and a vector search together. For each document, Elasticsearch takes the lexical score, if the document matched the query, and the vector score, if the document was among the nearest neighbors, and adds them. Each part can carry a boost, a multiplier that says how much it should count. Boosting the lexical part by 0.9 and the vector part by 0.1 means that the final score is mostly lexical with a small semantic contribution. A document found by only one leg simply has no contribution from the other.
The problem: different scales
Lexical scores from BM25 are not bounded. They depend on the query, the field lengths, and the collection, and can be anywhere from a fraction to dozens. Vector scores, by contrast, are bounded, typically between zero and one. If you add them raw, the larger numbers dominate, and the vector leg has almost no influence, whatever you intended. The weights you choose then have to fight the scale difference, and a weight that works for one query may fail for another, because the lexical score range changes with the query.
Adding a runner’s time in seconds to a jumper’s height in meters gives a number dominated by the seconds. To combine the two fairly, you first convert each result to a common scale, such as “how far above or below the average,” and then add.
A numbers walkthrough
Let us use invented numbers with four documents, A, B, C, and D. The lexical leg returns A with a score of 12.4, B with 8.1, and C with 3.2. It does not find D. The vector leg returns C with 0.91, D with 0.88, and A with 0.84. It does not find B.
If we add the raw scores, A gets 12.4 plus 0.84, which is 13.24. B gets 8.1. C gets 3.2 plus 0.91, which is 4.11. D gets 0.88. The order is A, B, C, D. Notice that the vector leg made almost no difference: even D, the vector leg’s second choice, comes last, and C, the vector leg’s first choice, is third.
Now scale each leg’s scores to a range from zero to one, using the lowest and highest score in that leg. For the lexical leg, A becomes 1.0, B becomes about 0.53, and C becomes 0. For the vector leg, C becomes 1.0, D becomes about 0.57, and A becomes 0. Adding with equal weights, A gets 1.0, B gets 0.53, C gets 1.0, and D gets 0.57. Now A and C tie for first, D is third, and B is fourth. Both legs count, and the result reflects their agreement. The difference between the two orders is the whole reason for normalization.
| Document | Lexical score | Vector score | Raw sum | Scaled sum, equal weights |
|---|---|---|---|---|
| A | 12.4 | 0.84 | 13.24, first | 1.00, tied first |
| B | 8.1 | not found | 8.10, second | 0.53, fourth |
| C | 3.2 | 0.91 | 4.11, third | 1.00, tied first |
| D | not found | 0.88 | 0.88, fourth | 0.57, third |
Ways to normalize
Min-max scaling
Rescale each leg’s scores so that its lowest becomes zero and its highest becomes one. Simple and popular, but sensitive to a single outlier score.
Score by rank in the window
Replace scores with positions, which leads to the rank-based methods of the next chapter.
Statistical scaling
Center scores by their average and divide by their spread. More robust, but needs enough results to estimate.
Built-in options in newer versions
Newer releases offer a weighted combination that applies a chosen normalization for you, so you set weights and not formulas.
Choosing the weights
Weights express how much you trust each leg. There is no universal answer. A catalog full of part numbers deserves a heavy lexical weight. A support site full of natural language questions may lean semantic. Start with equal weights after normalization, and adjust using a judged set of queries. Change one weight at a time, measure a ranking metric, and beware of tuning to a handful of examples.
How documents found by only one leg are treated
In a union-style merge, a document found by only one leg still appears, with the other leg contributing nothing. This is usually what you want, because it is the source of the recall gain. But it also means that the meaning of “zero” matters: when scaled, a missing score is treated as zero contribution, the same as the worst found score. Some designs prefer to treat missing as slightly worse than the worst found, to penalize documents that only one leg likes. Be aware of the choice your method makes.
The vector leg as a clause in a larger query
Newer versions allow the vector search to appear as a clause inside a boolean query, next to lexical clauses, filters, and boosts. This makes it possible to mix legs in more flexible ways, for example, requiring a lexical match and using vector similarity only as a scoring boost. The flexibility is useful, but adds ways to make mistakes, since the scoring of a boolean query has its own rules.
Weighted fusion gives you the most control, including per-query-type weights and business boosts. The price is the effort of normalization and tuning. If you have judged data and time, it can beat simpler methods. If you do not, the rank-based method of the next chapter is often the safer start.
8Combining by Rank: Reciprocal Rank Fusion and Choosing a Method
If scores cannot be compared, compare positions. That simple idea is the basis of the most popular fusion method.
The idea
Reciprocal rank fusion, often shortened to RRF, ignores the scores of each leg completely. It looks only at where each document stands in each leg’s ranking. For every list in which a document appears, the document earns a small amount of credit, larger when it is near the top and smaller when it is farther down. The credit is one divided by a constant plus the rank. The credits from all lists are added, and documents are sorted by the total. The constant, by default sixty, softens the difference between the very top positions.
flowchart LR
L1["Lexical ranking: A first, B second, C third"] --> R["For each list, a document earns one divided by sixty plus its rank"]
L2["Vector ranking: C first, A second, D third"] --> R
R --> F["Fused order: A, C, B, D"]
A worked example
Take the same four documents. In the lexical ranking, A is first, B second, and C third. In the vector ranking, C is first, A second, and D third. With the constant at sixty, a document in first place earns one over sixty-one, about 0.01639. Second place earns one over sixty-two, about 0.01613. Third place earns one over sixty-three, about 0.01587.
Document A is first in one list and second in the other, so it earns 0.01639 plus 0.01613, about 0.03252. Document C is third in one list and first in the other, so it earns 0.01587 plus 0.01639, about 0.03226. Document B appears only in the lexical list, in second place, and earns 0.01613. Document D appears only in the vector list, in third place, and earns 0.01587. The fused order is A, C, B, D. Documents that both legs like rise to the top, while documents that only one leg likes follow, ordered by how highly that leg placed them.
Two critics each publish a top-ten list of films. A film on both lists is probably good, even if the critics use different scales. A film at the top of one list and absent from the other is interesting but less certain. Combining by position, without caring how each critic scores, gives a fair overall ranking.
The two knobs
Rank window size
How many top results from each leg enter the fusion. A document ranked below the window in a leg gets no credit from it. Larger windows improve recall but cost more.
Rank constant
The number added to each rank. A larger constant flattens the differences between top positions. A smaller one rewards the very top more strongly. The default of sixty suits most cases.
Strengths and weaknesses of rank fusion
Strengths
- No score normalization needed.
- Works with any number of legs.
- Robust: needs very little tuning to give good results.
- Rewards agreement between legs.
- Easy to explain: each document’s credits can be listed.
Weaknesses
- Throws away score information, such as a huge gap between first and second.
- Hard to give one leg a clearly larger say in a simple way.
- Depends on the rank window: documents outside it are invisible.
- Paging is limited to the window.
- May require a specific subscription level, depending on the version.
Retrievers: describing multi-stage searches
Newer versions let you describe a search as a tree of building blocks called retrievers. A standard retriever runs an ordinary query. A vector retriever runs a nearest-neighbor search. A fusion retriever takes several child retrievers and merges their results. A reranking retriever takes another retriever’s results and re-orders them with a model. Because retrievers nest, a hybrid search with reranking is described as one tree, which is easier to read, test, and change than a pile of separate options.
Choosing between the methods
flowchart TD
A["Need to combine two result lists"] --> B{"Do the scores share a comparable scale?"}
B -- No --> C{"Do you have judged queries to tune weights?"}
C -- No --> D["Reciprocal rank fusion: uses positions, little tuning"]
C -- Yes --> E["Weighted combination after normalizing scores"]
B -- Yes --> F["Simple weighted sum may work, verify with tests"]
D --> G["Optionally rerank the top results with a stronger model"]
E --> G
F --> G
| Method | Uses | Tuning effort | Best when |
|---|---|---|---|
| Raw score sum with boosts | Scores as they come | High and fragile | Rarely, when scales happen to be comparable |
| Normalized weighted sum | Scaled scores and weights | Medium to high | You have judgments and want fine control |
| Reciprocal rank fusion | Positions only | Low | You want a strong result quickly and robustly |
| Fusion followed by reranking | Either, then a stronger model | Medium | Top-of-list quality matters and latency allows |
A practical starting recipe
Get each leg working alone
Measure the keyword leg and the semantic leg separately on judged queries.
Start with rank fusion at defaults
It is strong out of the box, and gives a baseline for hybrid.
Try a normalized weighted sum
Compare it with rank fusion on the same queries.
Adjust windows before weights
Make sure that good documents are inside each leg’s window, then tune balance.
Add reranking if the top still disappoints
Only after the merge is sound.
The availability of rank fusion, of retrievers, and of newer weighted options, and the subscription level they require, differ between versions. Check the documentation and license terms for the version you run before designing around a specific method.
9Reranking: A Second, Sharper Look at the Top
Retrieval is fast but coarse. Reranking is slow but sharp. Using them in sequence gives quality that neither could reach alone at a sensible cost.
flowchart LR
A["Millions of documents"] --> B["Stage 1: hybrid retrieval of the top 100 to 1000"]
B --> C["Stage 2: a reranker reads query and text together"]
C --> D["Top 10 shown to the user"]
Why a second stage helps
Both retrieval legs judge a document without ever looking at the query and the document together. The keyword leg counts term matches. The vector leg compares two separately made vectors. Neither reads the query and the passage side by side, the way a human would. A cross-encoder model does exactly that: it takes the query and one candidate document as a pair, reads both at once, and outputs a relevance score. It is much more accurate, and much too slow to run on millions of documents. But it is affordable for a few hundred candidates.
A hiring team first screens thousands of résumés by keywords and a quick skim, which is fast and rough. Then it interviews the top thirty in person, which is slow and careful. Nobody interviews all thousands, and nobody hires from the skim alone. The interview stage is the reranker.
Bi-encoders and cross-encoders
| Aspect | Bi-encoder, used in vector retrieval | Cross-encoder, used in reranking |
|---|---|---|
| What it reads | Query and document separately | Query and document together |
| When documents are processed | Once, at indexing time | At query time, for each candidate |
| Speed per query | Very fast, a vector comparison | Slow, one model run per candidate |
| Accuracy | Good | Higher |
| Scale | Millions of documents | Tens to hundreds of candidates |
How reranking fits into Elasticsearch
In the newer retriever style, a reranking retriever wraps a first-stage retriever, such as a fusion of the two legs. It sends the query and the text of the top candidates to a reranking model, which is called through an inference endpoint, and re-orders them by the returned scores. The number of candidates sent is a window you choose. Older approaches use a rescore step with a second query over the top results, or a learned ranking model that combines many signals, but the idea is the same: spend more effort on fewer documents.
Choosing the window
A larger window gives the reranker more chances to find good documents, and costs more in time and money. A smaller window is cheap, but the reranker can only reorder what the first stage gave it. Typical windows are in the tens to low hundreds. Measure the gain at several sizes on your queries, and choose the point where more candidates stop paying for themselves.
Cost and latency
Adds delay
Reranking hundreds of candidates may take tens to hundreds of milliseconds, depending on the model and hardware.
Adds a per-call cost
Outside services often bill by the number of documents reranked.
Text length matters
Rerankers have input limits. Long documents are cut, so send the most relevant passage, not the whole document.
Plan for failure
If the reranker is slow or down, return the first-stage order rather than nothing.
Business signals after relevance
Relevance is not the only thing that matters. A shop may want to favor products that are in stock, popular, well-rated, or on promotion. A news site may want fresh articles. These signals can be applied after the merge, as gentle boosts on top of the relevance order, for example by multiplying the score by a factor that grows with popularity or recency. Keep such boosts modest, or they will drown out relevance, and test their effect with the same judged queries.
If the right documents are already inside the candidate list but ordered poorly, reranking helps a lot. If the right documents are not in the list at all, reranking cannot help, and you should fix retrieval first: the legs, the windows, the chunks, or the filters.
10How a Hybrid Request Executes
Understanding the path of a request through the cluster explains its cost and its limits.
flowchart TB
Req["Search request with lexical and vector parts"] --> Coord["Coordinating node"]
Coord --> S1["Shard 1: keyword top window and vector top candidates"]
Coord --> S2["Shard 2: keyword top window and vector top candidates"]
S1 --> M["Coordinating node merges each list across shards"]
S2 --> M
M --> Fu["Fusion computes the final scores"]
Fu --> Fe["Fetch phase loads the documents of the winners"]
The phases
Preparation
If the query is to be embedded inside Elasticsearch, the model is called first to produce the query vector. This adds the model’s latency before any searching begins.
Shard-level search
Every shard runs the lexical search over its inverted indexes and the vector search over its graphs, both restricted by the filters.
Collection of candidate lists
Each shard returns its top window for each leg, with scores.
Global merge of each leg
The coordinating node combines the shards’ lists into one lexical ranking and one vector ranking for the whole index.
Fusion
The two global rankings are merged by the chosen method.
Optional reranking
The top of the fused list is sent to the reranker, and its scores reorder it.
Fetch
The documents of the final winners are loaded, with highlights and requested fields.
The cost adds up
A hybrid search is roughly the cost of a keyword search plus a vector search, plus the fusion, plus any reranking, plus the query embedding. The legs run in parallel on each shard where possible, so the elapsed time is closer to the slower leg than to the sum, but the total work is the sum. That work multiplies with the number of shards, because each runs both legs, and with the size of the windows and the candidate counts.
Two teams of researchers search two archives at the same time. The waiting time is set by the slower team, but the salary bill covers both. Adding more archive branches means more researchers, all working at once.
Paging: the window is the limit
With rank-based fusion, only the documents inside the rank window can appear in the final list. So the deepest page you can reach is limited by the window. Asking for results beyond it returns nothing, or an error, depending on the version. For interfaces that need deep paging, either raise the window, accepting the cost, or use a different technique for deep results, such as filtering more narrowly. Most search interfaces need only the first few pages, where the window is ample.
Facets and aggregations
Counts by category, brand, or price range are usually computed over the documents that match the query. In hybrid search, the set of matching documents is less clear, since it is the union of candidates from both legs, limited by windows. Aggregations may therefore reflect only the retrieved candidates and not the whole matching population, and counts may differ from what a pure keyword search would show. Test facet behavior carefully in your version, and consider computing facets from the lexical leg alone if consistent counts matter.
Sorting
Hybrid search produces a ranking by relevance. If you ask to sort by another field, such as price or date, the relevance fusion no longer determines the order, and the value of the merge is lost. A better design is to keep relevance ordering, and offer sorting only on the final small set, or to apply gentle boosts for the signals that matter.
Highlighting and explanations
Highlights show the matching words in a snippet. They work naturally for the lexical leg, because the words matched. They do not exist in the same way for a document that was found only by meaning, since no word matched. Some fields designed for semantic search can highlight the most relevant chunk instead. For debugging, explanation options show, for rank fusion, the rank contributed by each leg, which is very useful for understanding why a result appeared.
Timeouts and partial results
A search can be given a time limit. If a leg is slow, partial results may be returned instead of waiting forever. In a hybrid search, a partial result from one leg may distort the fusion, so decide deliberately how the application should behave: fail fast, fall back to the lexical leg, or accept partial results with a marker.
When a result surprises you, ask for an explanation. It will tell you which leg placed the document where, and with what score or rank. Most hybrid mysteries turn out to be one leg behaving unexpectedly, and the explanation points straight to it.
11Filters, Permissions, and Facets: Keeping Both Legs Honest
Filters are simple in a keyword search. In a hybrid search, they must be applied to both legs, or the results can be wrong, or worse, unsafe.
Filters restrict candidates, not scores
A filter is a yes-or-no condition: only documents in stock, only documents in English, only documents this user may see. It removes documents from consideration before ranking. It does not change scores. In a keyword search, you place the filter in the boolean query, and it is done. In a hybrid search, the two legs are separate searches, and each needs the filter.
flowchart TD
F["Filter: permissions, language, availability"] --> L["Applied to the lexical leg"]
F --> V["Applied inside the vector leg"]
L --> M["Only allowed documents reach the fusion"]
V --> M
A club has a rule that only members may enter the reading room. If the door on the front street has a guard, but the side door does not, the rule means nothing. Every door must be guarded, and both search legs are doors into the same room.
The danger of forgetting one leg
Suppose a permission filter is put on the lexical query, but not inside the vector search. The lexical leg will return only allowed documents. The vector leg will return the nearest neighbors among all documents, including ones the user must not see. The fusion merges both lists, and a forbidden document appears in the results. This is not a hypothetical bug: it is one of the most common ways that hybrid search leaks data. Always test with a user who has restricted access, and confirm that no forbidden document appears from either leg.
Filtering inside the vector search
As explained in the vector search literature, a filter given inside the nearest-neighbor part is applied while walking the graph, so that all the returned neighbors satisfy it. A filter applied only after the nearest neighbors are found can leave fewer results than requested, and in the extreme, none. For hybrid search, use the filter inside the vector part. Newer retriever-style requests allow a single top-level filter to be applied to all child retrievers, which reduces the chance of forgetting one.
| Where the filter is placed | Effect | Risk |
|---|---|---|
| Only in the lexical query | Vector leg ignores it | Forbidden documents can enter through the vector leg |
| Only outside the vector part, applied after | Vector leg finds neighbors, then some are removed | Too few vector results, weaker recall |
| Inside the vector part and in the lexical query | Both legs restricted | None, if the two filters are identical |
| Single shared filter over all retrievers | One definition, applied everywhere | Lowest risk of drift |
| Enforced by security features at the index or document level | Applied by the platform for every search | Test that it is applied to the vector leg too |
Filters that are too restrictive
When a filter leaves only a small number of documents, the vector search may switch to an exact comparison against just those documents, which is cheap and precise. When a filter leaves none, both legs return nothing, and the application should say so, not silently drop the filter. When a filter is very selective for one leg but not the other, for example a rare language, the legs may return very different numbers of candidates, which affects the fusion.
Permissions and chunks
If documents are split into chunks for the vector leg, every chunk must carry the permission information of its parent. A chunk without it either leaks, if unrestricted, or is invisible, if the filter cannot match it. The simplest design copies the permission fields into each chunk at indexing time, and updates all chunks whenever the parent’s permissions change. Treat this update as a security-critical step, and test it.
Facets and counts
Facet counts, such as “Brand: 120 results,” are computed over the documents that match. In hybrid search, the matching set is fuzzier, as Chapter 10 explained. Filters applied by the user, such as clicking a brand, should be applied to both legs, and the counts should be consistent with what is displayed. If your interface relies on exact counts, compute them from a well-defined query, such as the lexical leg, or from the filter alone, and explain what the counts mean.
One definition of every filter
Build the filter once in code, and hand the same object to both legs.
Test as a restricted user
Confirm that forbidden documents never appear, even at low ranks.
Copy permissions to chunks
And keep them in sync with the parent.
Never drop a filter to get results
An empty result is better than a leaked one.
The most common hybrid search leak is a permission filter applied to the keyword query but not to the vector search. Add an automated test that runs both legs as a low-privilege user and fails if any restricted document appears.
12Data Modeling and Lifecycle for Hybrid Indexes
Hybrid search asks each document to be searchable in two ways. That shapes how you design the index, and how you keep it healthy.
One index, two representations
The usual design keeps text fields and vector fields in the same index and, where possible, in the same document. A product has a title and a description, indexed as text, and a vector, derived from the same words, stored in a vector field. Because the document identifier is shared, fusion can recognize a document found by both legs. Keeping both in one index also makes filters simple, since one set of metadata fields serves both legs.
A museum object has a label with its name and description, and also a place on the map of related objects. Both refer to the same object with the same catalog number. Keeping them together means a curator can find it either way and know it is the same thing.
What text to embed
The vector should capture what users will search for. Often, that means combining several fields into one text for embedding, such as the title, a short description, and key attributes. Do not embed noise, such as boilerplate footers or navigation. Do not rely on the embedding to capture things it cannot, such as exact numbers. Keep the embedded text within the model’s input limit, and record how it was built, so that it can be rebuilt the same way later.
Documents and chunks
Long documents are cut into chunks for the vector leg, as explained before. This makes the modeling of hybrid search interesting, because the lexical leg naturally works on whole documents, or on the same chunks, while the vector leg works on chunks. There are three common designs.
| Design | How it works | Strength | Weakness |
|---|---|---|---|
| Chunks as documents, both legs on chunks | Every chunk is a document with text and a vector. Both legs search chunks. | Simple, legs align perfectly | Results are chunks, so several may come from one parent |
| Chunks grouped under a parent key | Chunks are documents with a parent identifier, and results are grouped by parent | One result per parent, with the best chunks as evidence | Needs grouping logic and care with paging |
| Nested chunks inside a parent | The parent holds nested objects, each with text and a vector | Natural parent results, best chunk available | Nested queries are more complex and have their own costs |
The first design is the easiest to start with. When users complain that the same article appears three times, add grouping by the parent identifier, keeping the best chunk of each. Many systems use the grouping feature of search for this, and show the matching chunk as the snippet.
The memory and disk bill doubles
A hybrid index holds both the inverted indexes and the vectors with their graphs. The text side needs disk and file cache for postings. The vector side needs disk and, above all, file cache for vectors and graphs. Plan for both. In particular, do not assume that a cluster sized for keyword search can carry vectors too. The vector side often dominates the memory need, and compression is the usual way to keep it in check.
Keeping the legs in step
Both representations are derived from the same source text, and both must be updated when it changes. A frequent bug is to update the text and forget the vector, so that the lexical leg finds the document for its new content, while the vector leg still sees the old meaning. Build your update path so that changing the embedded text always triggers a new embedding, and consider storing a hash of the embedded text to detect stale vectors.
Source content changes
A description is edited, or a document is replaced.
The embedded text is rebuilt
The same recipe, the same fields, the same cleaning.
A new vector is computed
By the same model version as the rest of the index.
Text and vector are indexed together
In one document update, so the legs cannot disagree.
Old versions are cleaned up
Merges remove the dead entries of the old document from both structures.
Documents without vectors
During a backfill, or when the embedding service fails, some documents may have text but no vector yet. In a hybrid search, such documents are simply missing from the vector leg, and still available to the lexical leg. This is a good property: the system degrades gracefully. But it also means that quality varies across documents. Track the share of documents with vectors, and finish the backfill before judging the vector leg.
Changing the model
Replacing the embedding model means recomputing every vector, as the old ones are meaningless to the new model. Build a new index, load it, evaluate it against the current one on judged queries, and move an alias when the new index wins. Because the lexical leg does not depend on the model, the keyword side is unchanged and continues to work during the rebuild.
Store, with the index or with each document, the model name and version, the rule for building the embedded text, and the chunking parameters. When quality changes, this record tells you what to rebuild and how.
13Query Understanding and Routing
Not every query deserves the same recipe. A little understanding of the query, before the legs run, can lift quality more than any weight tweak.
flowchart TD
Q["Incoming query"] --> C{"What kind of query is it?"}
C -- "Looks like an identifier or exact phrase" --> L["Weight the keyword leg higher"]
C -- "Natural language question" --> V["Weight the semantic leg higher"]
C -- "Mixed or unclear" --> H["Balanced hybrid"]
L --> F["Fuse and return"]
V --> F
H --> F
Why one recipe does not fit all
A query such as “XR-450” is best served almost entirely by exact matching. A query such as “what should I wear for a rainy hike” is best served largely by meaning. A query such as “waterproof jacket XR-450 women’s” is a mixture. A single fixed balance is a compromise that serves each kind a little worse than a tailored one. Query routing tries to give each query the mix that suits it.
A hospital receptionist listens to a visitor and decides which department to send them to. Someone with a precise appointment number goes to the desk that looks up numbers. Someone who describes vague symptoms goes to a doctor who can interpret them. The receptionist is the query router.
Signals that help
Contains digits, dashes, or codes
Often an identifier or model number. Lean lexical.
Quoted phrases
The user wants those exact words together. Boost phrase matching.
Very short or very long
Short queries are ambiguous and often benefit from meaning. Long ones are usually questions.
Question words
“How,” “why,” and “what” suggest natural language and semantic strength.
Past behavior
Which legs produced the results that people clicked for similar queries.
Detected language
Choose analyzers, models, and filters suited to the language.
Turning parts of a query into filters
Many queries contain conditions hidden in words: “under fifty dollars,” “in stock,” “from last year,” “in French.” An understanding step can pull these out and turn them into filters, leaving the rest of the text for the legs. This improves precision, because the conditions are enforced exactly rather than left to fuzzy matching. It needs care: a wrongly extracted filter can silently hide good results, so log the extracted filters and test them.
Cleaning and correcting
- Spelling correction. Fix obvious typos before the legs run, or let the lexical leg tolerate them with fuzzy matching. Vector models often tolerate small typos by themselves.
- Normalization. Remove stray punctuation, unify units, and expand known abbreviations.
- Synonyms for known vocabulary. A small curated list helps the lexical leg with company-specific terms.
- Stop-phrase removal. Strip filler such as “please show me,” which adds noise to keyword matching.
Rewriting and expansion with a language model
A language model can rewrite a vague or conversational query into a clearer one, generate several variants to search in parallel, or produce a short hypothetical answer whose embedding is used to search. These techniques can improve recall for hard queries, and they add cost, latency, and new ways to go wrong, since the rewritten query may drift from what the user meant. Use them selectively, for the query types that need them, and measure the benefit on judged examples before adopting them widely.
Routing without machine learning
Simple rules go a long way. If the query matches the pattern of an identifier, search the identifier fields with an exact query first, and fall back to hybrid search if nothing is found. If the query has more than eight words, raise the semantic weight. Start with rules, log which route each query took, and evaluate. Introduce learned routing only when rules clearly fall short.
Keeping routing safe and explainable
Log the route
Record which class a query was assigned and which weights it received.
Keep a default
If classification fails or is uncertain, use the balanced recipe.
Test each route separately
Measure quality per query class, not only overall.
Allow overrides
Let editors pin the recipe for important queries.
Review regularly
Queries change with seasons and products. Routes should follow.
A rule for identifiers and a rule for long questions cover a surprising share of real traffic. Add complexity only where measurements show a gap.
14Performance, Sizing, and Tuning
A hybrid search costs more than either leg alone. Knowing where the time and memory go tells you where to save them.
A latency walkthrough
Let us use invented numbers for one query. Embedding the query takes 30 milliseconds. The keyword leg takes 20 milliseconds on each shard, and the vector leg takes 25 milliseconds, running at the same time, so the shard phase takes about 25 milliseconds once the vector exists. The coordinating node spends 5 milliseconds merging and fusing. A reranker takes 80 milliseconds for 50 candidates. Fetching the winners takes 15 milliseconds. The total is about 30 plus 25 plus 5 plus 80 plus 15, or 155 milliseconds. Without the reranker, it is about 75. The point is that the embedding call and the reranker are often the largest parts, larger than the searches inside Elasticsearch.
| Stage | Typical time in this example | Can it overlap with another stage? |
|---|---|---|
| Query embedding | 30 ms | Can overlap with the lexical leg if the client sends both parts separately |
| Keyword leg | 20 ms | Runs in parallel with the vector leg |
| Vector leg | 25 ms | Runs in parallel with the keyword leg |
| Merge and fusion | 5 ms | No |
| Reranking | 80 ms | No, needs the fused list |
| Fetch | 15 ms | No |
Preparing a dinner, the oven and the stove run at the same time, so the time is set by the slower dish. But the shopping before, and the careful plating after, cannot overlap with cooking. The total evening is the sum of the sequential stages.
Where the resources go
Vectors and graphs in the file cache
Usually the largest need. Compression is the main way to reduce it.
Both legs on every shard
Postings walks and distance calculations, multiplied by the number of shards.
Embedding and reranking calls
Processor time on machine-learning nodes, or money on outside services.
Candidate lists between nodes
Larger windows move more data to the coordinating node.
Original vectors and rescoring
Random reads when compressed vectors are rescored.
Embedding and graph building
Loading is slower than for keyword-only data.
Tuning levers
| Lever | Effect on quality | Effect on cost | Comment |
|---|---|---|---|
| Larger rank windows | Higher recall | More work and network | Increase until gains flatten |
| More vector candidates | Higher vector recall | Slower vector leg | Measure against exact search |
| Compression of vectors | Small loss, recoverable | Much less memory | Often the best single saving |
| Smaller embedding model | Possibly lower quality | Faster embedding, less memory | Test on your data |
| Cache query embeddings | None | Saves model calls for repeated queries | Most search traffic repeats |
| Rerank fewer candidates | Slightly lower gain | Faster and cheaper | Find the smallest window that works |
| Skip reranking for easy queries | Usually none | Saves time and money | Identifier queries rarely need it |
| Fewer, larger segments | None | Fewer graph walks and postings lookups | Force merge finished data |
| Filters in filter context | None | Cheaper, cacheable | Keeps scoring out of conditions |
| Dedicated machine-learning nodes | None | Steadier search latency | Model work does not compete with search |
Throughput and concurrency
Because each hybrid query does two searches and possibly two model calls, the cluster handles fewer hybrid queries per second than keyword queries on the same hardware. Plan capacity with realistic tests: measure queries per second at your target latency, with your real mix of query types. Replicas add read capacity, and each replica needs its own memory for vectors. Model services have their own limits and rate caps, which can become the true ceiling.
Caching
Cache query embeddings
The same query text always gives the same vector. Store it for a while.
Use the filter cache
Repeated filters are remembered per segment by Elasticsearch.
Cache whole result pages, carefully
A cache of full results must include the user’s permissions in its key, or one user’s results may be served to another.
Let the operating system cache files
Leave memory for the file cache, where vectors and postings live.
A faster configuration that quietly loses relevance is not an improvement. Always report a ranking metric next to latency for each setting you test.
15Advantages, Disadvantages, and Trade-offs
Every design carries a price. Here is the honest balance sheet of hybrid search.
Advantages
- Handles exact terms and meaning in the same search.
- Higher recall: what one leg misses, the other may find.
- More robust across different kinds of queries and data.
- Degrades gracefully: if one leg fails, the other still works.
- Can be improved step by step with routing, reranking, and boosts.
- Keeps keyword features such as filters, phrases, and highlights.
- One system, one platform, one place to secure and monitor.
Disadvantages
- More moving parts: two indexes’ worth of structures, a model, a merge.
- Higher cost in memory, processor time, and model calls.
- Fusion choices and weights need evaluation to get right.
- Results are harder to explain than pure keyword results.
- Facets, paging, and sorting behave differently and need care.
- Filters and permissions must be applied consistently to both legs.
- Changing the embedding model means rebuilding the vector side.
| Trade-off | Leaning toward quality | Leaning toward cost and simplicity |
|---|---|---|
| Fusion method | Tuned weighted fusion with normalization: finest control | Rank fusion at defaults: robust, little effort |
| Rank windows | Large: more recall, more work | Small: cheaper, may miss good documents |
| Reranking | On for all queries: best top results, slower and costlier | Off, or only for hard queries |
| Embedding model | Large and multilingual: nuanced, heavy | Small and specialized: light, narrower |
| Vector precision | Full precision: best accuracy, most memory | Compressed with rescoring: much smaller |
| Query understanding | Routing and rewriting: tailored, complex | One recipe: simple, one-size-fits-all |
| Chunking | Small chunks: precise, many vectors | Large chunks: fewer vectors, blurrier |
A newsroom that uses both a fast fact-checker and a careful editor produces better articles than one using only a single reviewer, but it costs more salaries and takes longer to publish. The right level of checking depends on how much the errors would cost.
When is hybrid worth it?
| Situation | Recommended stance |
|---|---|
| Small, structured data with codes and short fields | Keyword search with good analyzers may be enough |
| Natural language questions over documents | Hybrid, with the semantic leg emphasized |
| Mixed catalogs: descriptions plus identifiers | Hybrid with routing or rank fusion |
| Retrieval feeding a language model | Hybrid, with reranking and careful chunking |
| Sensitive data, tight budget | Start with keyword, add a small model inside your own cluster, measure the gain |
16High Availability and Graceful Degradation
A hybrid search has more parts that can fail. Its great advantage is that it can keep working when one of them does.
Failures and fallbacks
| Failure | Effect | Graceful response |
|---|---|---|
| The embedding service is slow or down | Query vectors cannot be made, so the vector leg fails | Serve the keyword leg alone, and flag the reduced mode |
| The reranker is slow or down | The final refinement fails | Return the fused order without reranking |
| Vector caches are cold after a restart | The vector leg is slow | Allow warm-up, keep keyword search responsive, restart one node at a time |
| A data node fails | Replicas take over, with cold caches | Expect a latency bump, keep headroom |
| Some documents have no vectors | Only the keyword leg can find them | Track vector coverage, finish backfills |
| Model version changed by mistake | Query vectors mismatch stored vectors, results degrade quietly | Pin versions, monitor quality, keep the previous index |
| One leg times out | Partial results skew the fusion | Decide in advance: fail fast, or fall back to the other leg |
| Snapshots missing for vectors | Loss means paying to re-embed everything | Snapshot vector indexes regularly |
A ship with both radar and a paper chart can still navigate if the radar fails. It is slower and less precise, but it gets to port. A ship with only radar has no fallback.
The keyword leg is the lifeboat
Because the keyword leg depends only on the inverted indexes inside Elasticsearch, it is more stable than the semantic leg, which depends on models and possibly outside services. Design your application so that it can fall back to keyword-only search on any sign of trouble with embedding, and can tell the user or the logs that it has done so. A search that returns slightly less clever results is far better than one that returns an error.
Timeouts, retries, and circuit breakers
Set strict time limits on model calls
A query embedding that takes seconds is worse than none.
Retry sparingly
One quick retry may help. Many retries add load to a struggling service.
Open a circuit after repeated failures
Stop calling the failing service for a short time, and use the fallback.
Close the circuit gradually
Test the service with a few calls before restoring full traffic.
Alert on fallback rate
A rising share of degraded searches is an early sign of trouble.
Replicas and consistency between legs
Each replica builds its own inverted index and its own graph, so the two legs on different copies of a shard can differ slightly at the edges, especially for approximate vector results. Identical queries may occasionally return slightly different lists. If your application needs stable results for one user within a session, use a stable routing preference so that the same user is served by the same copies.
Upgrades and rebuilds
The keyword side and the vector side may be affected differently by upgrades. Vector features have evolved quickly across versions, and defaults for compression and options have changed. Test upgrades on a copy, compare a fixed set of queries before and after, and read the release notes for changes in vector and retriever features. Keep the ability to roll back, including the old index if a model change is involved.
Once in a while, switch off the embedding service in a test environment and watch what the application does. It is much better to discover in a drill that the search page shows an error than to discover it during a real outage.
17Security and Privacy Considerations
A hybrid search touches your data in two ways and often calls outside services. Each adds a place where things can go wrong.
Permissions on both legs
As Chapter 11 stressed, every access rule must be enforced on both legs. This is the most important security point of hybrid search. Use one definition of the filter, apply it in both places, and test with restricted users. Where platform features such as document-level or field-level security are available in your subscription, verify that they are applied to the vector leg, and not only to keyword queries.
Vectors are sensitive
Embeddings carry the meaning of the content and can leak information, and parts of the original text may be reconstructed from them. Treat vectors with the same care as the text: restrict access to the vector fields, encrypt data at rest, secure snapshots, and do not return vectors to users who do not need them.
A detailed summary of a confidential report is still confidential. Locking away the report but leaving the summaries on an open desk defeats the purpose.
The embedding and reranking paths
What leaves your environment
Outside services receive your text, and your users’ queries. Check their retention, training, and location rules.
Credentials
Keep service keys in secure storage, rotate them, and give each application its own.
User queries are personal data
Queries can contain names, health topics, and secrets. Handle logs and model calls with that in mind.
Run models inside when required
For regulated data, prefer models that run in your own cluster or network.
Caches and shared results
Caching is a performance tool and a security risk. A cache of search results must be keyed by everything that affects the results, especially the user’s permissions. Otherwise, one user’s results may be served to another. Caches of query embeddings are safer, since a vector depends only on the text, but the cached text itself may be sensitive, so protect and expire it.
Risks when feeding a language model
When a hybrid search supplies text to a large language model, retrieved documents become part of the model’s input. If a retrieved document contains hidden instructions, the model may follow them. This is called prompt injection through retrieved content. Limit what can enter the index, mark retrieved text clearly as data, restrict what the model may do with it, and review outputs where the stakes are high. Also make sure that the model never sees documents the user is not allowed to see, which again depends on the filters being applied to both legs.
Abuse and cost attacks
- Expensive queries. Very long queries, huge windows, and large candidate counts multiply the work. Set limits on all of them.
- Model call flooding. Each search may cost a model call. Rate-limit by user, and cap the query length that is embedded or reranked.
- Content poisoning. Someone who can add documents may write content designed to rank highly for popular queries. Moderate public content and separate it from trusted content.
- Enumeration. Repeated queries can be used to discover the contents of an index. Rate limits and permissions reduce this.
Logging and retention
Search logs are valuable for improving quality and dangerous for privacy. Decide what to log, for how long, and who may read it. Remove or mask sensitive fragments, and keep the model version and route with each entry so that logs remain useful for analysis.
Turn on authentication and encryption, even for clusters that seem internal. Secure the snapshots, the model endpoints, and the logs, since a strong index with a weak surrounding system is only as safe as its weakest part.
18Evaluation, Monitoring, Logging, and Metrics
A hybrid search can look clever and be wrong. Only measurement tells the difference. This chapter is about knowing whether it works.
flowchart LR
A["Collect real queries and judgments"] --> B["Run each configuration"]
B --> C["Compute ranking metrics"]
C --> D{"Better than the current setup?"}
D -- Yes --> E["Adopt it and keep monitoring"]
D -- No --> F["Adjust weights, windows, or analyzers"]
F --> B
Judged queries: the foundation
To measure quality, you need examples where you know what a good answer is. A judged query set is a collection of real queries, each with documents marked as relevant, or graded from “perfect” to “irrelevant.” Sources include human reviewers, click and purchase data, and support staff who know the right answers. Some teams also use a language model to help judge, which is cheap and fast but can be biased, so check its judgments against humans on a sample. A few hundred good queries are far more valuable than thousands of careless ones. Include every kind of query your users send: identifiers, natural questions, vague descriptions, typos, and rare terms.
A teacher cannot know whether a new teaching method works by feeling. She gives the class a test with known answers before and after, and compares the scores. A judged query set is the test for a search engine.
Ranking metrics
| Metric | What it asks | Good for |
|---|---|---|
| Precision at k | Of the top k results, how many are relevant? | Result pages where every slot matters |
| Recall at k | Of all relevant documents, how many are in the top k? | Retrieval stages that feed rerankers or language models |
| Mean reciprocal rank | How high is the first relevant result? | Lookups where one good answer suffices |
| Normalized discounted cumulative gain | Are the best documents placed highest, with graded relevance? | General ranking quality, the most common overall metric |
Elasticsearch includes a rank evaluation feature that runs a set of judged queries against a search definition and reports such metrics. It lets you compare two configurations, such as keyword only, vector only, and hybrid with different fusion methods, on the same queries. Use it in a script that runs on every change.
Measure each leg, then the combination
Keyword leg alone
Your baseline. Every improvement must be measured against it.
Semantic leg alone
Shows where meaning helps and where it fails, for example on identifiers.
Hybrid with default fusion
Measures the gain from simply combining them.
Hybrid with tuned options
Weights, windows, and routing, each changed one at a time.
With reranking
Measures the extra gain against its extra cost.
Per query class
Report results separately for identifier, natural language, and mixed queries.
Offline and online evaluation
Offline evaluation, on judged queries, is cheap and repeatable, and is the tool for development. Online evaluation, on real users, tells you what people actually do. It includes experiments that split traffic between configurations and compare behavior such as clicks, purchases, or time to a useful result, and techniques that mix the results of two configurations in one list and see which results users prefer. Use offline testing to narrow the choices, and online testing to confirm the winner.
What to monitor in production
| Metric | What it tells you | Warning sign |
|---|---|---|
| Latency by stage | Where time is spent: embedding, legs, fusion, reranking, fetch | One stage growing steadily |
| Overall latency percentiles | User experience, including the slow tail | Rising tail |
| Fallback rate | How often the system ran without a leg or the reranker | Any sustained increase |
| Embedding and reranker errors and timeouts | Health of the model path | Rising errors, rate limits |
| Zero-result rate | Queries that found nothing | Increase after a change |
| Click-through and reformulation rates | Whether users find results useful | Falling clicks, more rewritten queries |
| Vector coverage | Share of documents with vectors | Below expectations after a load |
| Scheduled ranking test scores | Quality drift over time | A drop after a deployment |
| Memory headroom for the file cache | Whether vectors stay in memory | Shrinking headroom, rising disk reads |
| Cost per thousand searches | Model and infrastructure spend | Unexpected growth |
Tools for looking inside a query
Explanation of a result
Shows how a document’s score or rank came about, including each leg’s contribution.
Query profiling
Reports the time spent in each part of each query on each shard.
Analysis endpoint
Shows the terms that a text produces, for debugging the keyword leg.
Slow query logs
Records queries slower than a threshold.
Index disk usage analysis
Shows how much space text and vector structures use.
Rank evaluation
Scores a configuration on judged queries.
A troubleshooting playbook for a bad result
Reproduce it with the exact request
Same query, same filters, same user, same version.
Run each leg alone
Does the expected document appear in either leg’s window?
If in neither leg
Check filters, analyzers, chunking, the model, and whether the document has a vector.
If in one leg but lost in fusion
Check the windows and weights. Ask for the explanation of the fused ranking.
If found but ranked low after reranking
Check the text sent to the reranker and its length limit.
Add the case to the judged set
So that the fix is tested from now on.
Alert on rising latency in any stage, on a rising fallback rate, on embedding and reranker errors, on a drop in the scheduled ranking test, on a rising zero-result rate, and on shrinking memory headroom for the vector cache.
19Design Patterns and Anti-patterns
Good habits make hybrid search accurate and affordable. Bad habits are behind most disappointing results and most security surprises.
Patterns that work
Strong keyword baseline first
Tune analyzers, fields, and synonyms before adding vectors, and keep the baseline as a benchmark.
Rank fusion to start
Begin with a robust, low-tuning method, then compare with weighted fusion on judged queries.
One shared filter for all legs
Define it once, apply it everywhere, and test as a restricted user.
Retrieve broadly, rerank narrowly
A generous first stage for recall, a sharp second stage for the top.
Route by query type
Exact path for identifiers, semantic emphasis for questions, balanced for the rest.
Degrade gracefully
Fall back to the keyword leg when the embedding or reranking path fails.
Evaluate continuously
A judged set, a script, and a scheduled run that alerts on drops.
A good restaurant kitchen has a reliable basic menu that always works, and adds daring specials only after they have been tested. If the special ingredient is missing, the kitchen serves the basic dish, and no customer goes hungry.
Anti-patterns to avoid
What people do
They add raw keyword scores and raw vector scores together with hand-picked boosts.
Why it hurts
The scores are on different scales, so one leg dominates, and the boosts behave differently for every query.
Better approach
Use rank fusion, or normalize the scores before combining, and tune weights on judged queries.
What people do
They apply a permission or language filter to the keyword query and forget the vector search.
Why it hurts
The vector leg returns documents from the whole index, and forbidden or wrong-language documents appear in the results.
Better approach
Use one shared filter for all legs, and add an automated test with a restricted user.
What people do
They use tiny rank windows to save time, such as ten results per leg, and then wonder why good documents are missing.
Why it hurts
A document outside a leg’s window cannot be rescued by fusion or reranking. Recall collapses.
Better approach
Use windows of tens to hundreds, measure recall at each size, and choose the smallest size where gains flatten.
What people do
They send identifier lookups, such as part numbers, only through the vector leg.
Why it hurts
Embeddings blur exact strings. The exact part may be outranked by similar-looking ones.
Better approach
Keep identifiers in keyword fields, route identifier-like queries to an exact match first, and let hybrid search handle the rest.
What people do
They rerank every query with the largest model available, whatever the query and whatever the cost.
Why it hurts
Latency and bills grow, and easy queries gain nothing. When the right document is not in the candidates, reranking cannot help.
Better approach
Rerank a modest window, skip easy queries, fix retrieval first, and measure the gain against the cost.
What people do
They tune weights by trying a handful of queries and judging by eye.
Why it hurts
A change that helps five queries may hurt hundreds. Quality drifts without anyone noticing.
Better approach
Keep a judged query set, measure a ranking metric before and after every change, and report per query class.
What people do
They update the text of documents but forget to recompute their vectors.
Why it hurts
The two legs disagree about what the document says, and the vector leg returns documents for meanings they no longer have.
Better approach
Re-embed whenever the embedded text changes, and store a hash of that text to detect stale vectors.
What people do
They let users sort a hybrid result list by price or date without thinking about relevance.
Why it hurts
Sorting discards the fused relevance order, so the benefit of hybrid search disappears and irrelevant items float to the top.
Better approach
Keep relevance as the default, offer sorting on a narrowed set, or use gentle boosts for the signals that matter.
20Best Practices and Common Mistakes
A short list you could hand to a new teammate on their first day.
Best practices
Start with a good keyword search
Measure it, and require hybrid to beat it.
Begin with rank fusion
Robust and low effort, then compare with weighted fusion.
Give each leg enough candidates
Recall is capped by the windows.
Apply every filter to both legs
One definition, tested as a restricted user.
Keep text and vectors in step
Re-embed on change, and track vector coverage.
Plan the fallback
Keyword-only mode when models fail.
Cache and compress
Cache query embeddings, and compress vectors with rescoring.
Evaluate on judged queries
Per query class, after every change.
Common mistakes
- Assuming hybrid is always better. On some data, a tuned keyword search is already excellent, and vectors add cost and little else. Measure.
- Comparing raw scores across legs. They live on different scales and mean different things.
- Forgetting the rank window. It limits both recall and paging.
- Judging by demos. A few impressive examples hide the failures on identifiers and rare terms.
- Mixing embedding models. Query and document vectors must come from the same model and version.
- Ignoring analyzers. A poorly analyzed keyword leg makes the whole hybrid weaker.
- Neglecting cold caches after restarts. Vector latency is high until the cache warms.
- Not testing the fallback. The first outage should not be the first time you see it.
- Assuming facets and paging behave as in keyword search. They depend on windows and candidate sets.
Myths versus facts
| Myth | Fact |
|---|---|
| Vector search makes keyword search obsolete. | Keywords remain best for exact terms and are a strong baseline. Hybrid combines them. |
| Hybrid search is a special index type. | It is a way of querying ordinary text and vector fields together. |
| Adding the two scores is fine. | Scores are on different scales, so raw addition is dominated by one leg. |
| Rank fusion needs tuning to work. | It works well at defaults, which is why it is a good first choice. |
| A reranker fixes any retrieval problem. | It can only reorder the candidates it is given. |
| Filters on the keyword query are enough. | Both legs need the filter, or forbidden documents leak through the vector leg. |
| Hybrid costs about the same as keyword search. | It costs more in memory, processing, and model calls. |
| Once tuned, hybrid search stays good. | Content, queries, and models change, so quality must be monitored. |
Trust measurements, not impressions. A hybrid search earns its place by beating a well-tuned keyword baseline on judged queries, and keeps its place by being measured again every time something changes.
21Real-World and Industry Examples
Where does hybrid search quietly change what users can do?
Many well-known organizations have said publicly that Elasticsearch is part of their systems, including Wikipedia’s search, Netflix, Uber, and Stack Overflow. They rarely publish how they combine keyword and semantic search, so the scenarios below are typical patterns for such workloads, not descriptions of anyone’s private configuration.
Online marketplace: descriptions plus model numbers
A marketplace of the size of Amazon or eBay serves shoppers who type either “XR-450” or “warm jacket for camping.” Model numbers live in keyword fields for exact matching, while titles and descriptions have both text and vectors. Rank fusion merges the legs, filters for stock and region apply to both, and a light popularity boost is applied after relevance.
Support center: questions in natural language
A software company indexes help articles, manuals, and resolved tickets in chunks. Users ask long, conversational questions, so the semantic leg carries much of the weight, while error codes and product names are caught by the keyword leg. A reranker refines the top candidates, and permission filters keep internal notes away from customers.
Retrieval for a language model assistant
An enterprise assistant answers employee questions by retrieving passages from internal documents and giving them to a language model. Hybrid retrieval raises recall, the reranker orders the passages, and the same permission filter is applied to both legs, so that the model never sees documents the employee may not read. Answers cite their sources.
Legal and compliance search
Analysts need exact citations, statute numbers, and defined terms, together with conceptual matches for similar cases. Phrase matching and keyword fields serve the exact needs, and the semantic leg finds related passages in different words. Explanations of why a result matched are important, so the interface shows highlights for keyword matches and the best chunk for semantic ones.
Job and real-estate listings
Users describe what they want loosely: “quiet flat near a park for a small family.” Structured conditions, such as price and bedrooms, become filters applied to both legs, while the description is matched by meaning and by words. Query understanding extracts the conditions from the text automatically.
Multilingual travel site
Visitors search in many languages across pages written in others. A multilingual embedding model lets the semantic leg bridge languages, while the keyword leg handles place names and hotel names. When the embedding service is slow, the site falls back to keyword search in the visitor’s language and records the fallback.
In every example, the winning ideas are the same: exact terms kept exact, meaning added on top, one shared filter for both legs, a robust fusion method, a reranker only where it pays, a keyword fallback, and steady measurement on judged queries.
22Frequently Asked Questions
Short answers to the questions that come up most often.
23Summary and Key Takeaways
If you skim only one part of this guide, make it this one.
Hybrid search gives Elasticsearch two ways of finding documents and a rule for merging what each finds. The keyword leg is precise with exact terms. The semantic leg understands meaning. Fusion turns two rankings into one, a reranker can sharpen the top, and query understanding can choose the recipe for each query. Its real value shows up only when it is measured, and its safety depends on filters, fallbacks, and care with the data that flows through it.
Key Takeaways
- What it is: a keyword search and a vector search run for the same query, with their ranked lists merged into one, so that exact terms and meaning both count.
- Why it exists: keyword search fails when words differ, vector search fails when exact strings matter, and hybrid search covers both failures.
- How results are merged: weighted scores work only after normalization, while reciprocal rank fusion compares positions, needs little tuning, and is a strong first choice.
- How quality is sharpened: retrieve broadly for recall, rerank a modest window with a cross-encoder for precision, and route different query types to different mixes.
- How to keep it correct and safe: apply one shared filter to both legs, copy permissions to chunks, key caches by permissions, and test with restricted users.
- How to keep it running: keep text and vectors in step, plan memory for the vector cache, cache query embeddings, and fall back to keyword search when models fail.
- How to know it works: keep a judged query set, measure ranking metrics per query type after every change, and monitor latency by stage, fallback rate, and quality over time.