
A search box looks like a single feature, although the ranking behind it follows one of three patterns. Some engines match the exact words that you typed, while others match what you meant even when you reached for different words, and a third group blends the two together. Which of the three you run will usually decide whether your users ever reach the right answer.
The problem every search engine solves
Imagine a company handbook with a page titled 'Paid leave policy'. An employee opens the search box and types 'how many days off do I get', so not one word of that query appears in the title of the page that answers it. Each of the patterns in this article is a different strategy for closing the gap between the words that people type and the words that documents use.
Researchers who study retrieval have a name for that gap, which they call the lexical gap. It is the difference between the words a user puts into a query and the words that carry the same meaning in a document that would answer it. A 2025 survey of retrieval architectures identifies the lexical gap as the central weakness of systems that match on terms alone, and every pattern below handles it in a different way.
Keyword search
Keyword search, which you may also see called lexical or full-text search, matches the literal terms of your query against the literal terms in your documents. It is what runs behind the search box in your email client, the search in your code editor, and many of the site search boxes you use during a normal week.
An index that works like the back of a book
The data structure underneath it is called the inverted index. Rather than storing each document together with its words, the engine stores each word together with a list of the documents that contain it, in the way that the index at the back of a book lists every page on which a term appears. When the engine looks up 'refund', it makes a single dictionary lookup and gets back a ready-made list of the documents that match, which is why keyword search stays fast even when the collection runs to millions of documents. The keyword half of the hybrid pattern later in this article still rests on that same structure.
How the best match gets to the top
Finding the documents that match is the easy half of the job, and putting the best of them first is the hard half. The ranking function that most engines reach for is called BM25, and the 2025 survey above still treats it as the standard lexical baseline that the whole field measures itself against. It rests on three ideas.
- Rare words count for more. If you search a company handbook for 'annual refund policy', nearly every page will match 'annual', so the match tells you almost nothing, while only a few pages will mention 'refund', which makes that match a strong clue. BM25 therefore weights each word by how uncommon it is across the whole collection, in a weight that is called inverse document frequency.
- Repetition helps, although the benefit fades as it goes. A page that mentions 'refund' five times is a better bet than a page that mentions it once; a page that mentions it fifty times, however, is barely better than the page with five, because the score climbs quickly at first and then flattens out.
- Long documents score lower. A page of 10,000 words will mention almost everything at least once, in the way that a whole newspaper matches more searches than a single headline does. BM25 compares the length of each page against the average for the collection and trims the scores of the long ones, so a short and focused page comes out ahead when the rest of the score is close.
Those last two ideas each carry a tuning constant, and the two constants are called k1 and b.
Why b is set between 0.5 and 0.8
The b constant runs from 0 to 1, and it sets how hard the engine penalises a long document. At 0 the engine
ignores length entirely, so a rambling page of 10,000 words competes on equal terms with a focused one-paragraph
answer. At 1 the engine applies the full penalty, which drags down the pages that are long because their topic
demands it. A value between 0.5 and 0.8 applies most of the penalty while it still leaves a thorough page a fair
chance, and Narsil defaults to 0.75.
How a typo still finds the right page
Plain keyword matching breaks down on a typo, because 'refnud' matches nothing at all. The repair for that is fuzzy matching, which accepts any term falling within a small Levenshtein edit distance of the one you typed. That distance counts the single-character insertions, deletions, and substitutions it would take to turn one word into another, and some engines count the swapping of two adjacent letters as a single edit as well. Since 'refnud' is one such swap away from 'refund', a search for the typo still returns every document that contains the real word.
Where keyword search wins and where it fails
Keyword search is precise, fast, cheap, and easy to reason about, and it is usually the strongest option you have when your users query with exact tokens such as a product code, an error number, or a person's name. Its weakness is the lexical gap from the opening example, where the employee who asks about 'days off' scores nothing against a page that says 'paid leave', although the answer has been in the handbook the whole time.
The demo below shows that strength and that weakness together, since it runs the ranking described above over six pages of a handbook. Try each of the searches, and watch which words the engine marks and which page reaches the top.
Pick a search
- 1
Public holidays
0.74The office closes on national public holidays, and the days are listed each January.
- 2
Expense refunds
0.74Submit receipts within 30 days and the refund arrives with the next payroll run.
- 3
Paid leave policy
0.56Every employee receives 25 days of paid annual leave each year, in addition to the public holiday calendar, and part-time staff receive a pro-rata amount.
- 4
Parental leave
no matchNew parents can take up to 18 weeks of parental leave at full pay.
- 5
Remote work
no matchYou can work from anywhere for up to six weeks a year with approval from your manager.
- 6
Building access
no matchYour badge opens the office between 07:00 and 22:00 on weekdays.
Vector search
Vector search tackles the lexical gap directly, since it matches meaning in place of spelling.
Turning meaning into numbers
The idea underneath it is called the embedding. A machine-learning model takes a piece of text and converts its meaning into a list of numbers, usually several hundred or several thousand of them, and that list of numbers is called a vector. Two texts that mean similar things end up with similar vectors, which is why 'days off', 'paid leave', and 'annual holiday' all fall close together in this numeric space although they share no words at all. When you search, the engine embeds your query in the same way and returns the documents whose vectors lie nearest to it.
The word 'nearest' needs a definition of its own. The usual choice is cosine similarity, which is the cosine of the angle between two vectors, while the dot product and Euclidean distance are the common alternatives. Whichever metric the embedding model was trained with is the one you should measure with.
Finding neighbours fast
Comparing a query against millions of vectors one at a time would be far too slow, so production systems build an approximate nearest neighbour index instead. An index of that kind gives up a small amount of accuracy in return for the ability to search a high-dimensional space at scale. The structure that most engines use is HNSW, a multi-layer graph published in 2016, whose search cost grows logarithmically, which means that doubling the size of the collection adds roughly one extra step to the search. Finding a vector in that graph works in the way that you would find an address on a map, where the motorways take you to the right city, the main roads to the right district, and the small streets to the door itself. The upper layers of the graph make the big jumps towards the right region of the space, and the lower layers take the small steps that end at the closest vectors.
Where vector search wins and where it fails
Vector search handles paraphrase, synonyms, and the vague or conversational queries that keyword search scores nothing on. It carries two weaknesses that you should know about before you rely on it.
The first is that it handles exact tokens poorly. In a retrieval study Microsoft published in 2023, pure vector search scored 11.7 on a standard relevance measure () for keyword-style queries, while keyword search scored 79.2 on the same queries. An embedding model represents the meaning of a text, and an exact string such as 'SKU-1187-B' carries little meaning for it to represent.
The second is that an embedding model degrades on data that differs from the data it was trained on. The BEIR benchmark paper, which tests retrieval systems across 18 diverse datasets, found that often score worse once they are moved to a domain they were never trained on, and it concluded that plain BM25 remains a strong baseline. Since a vector model is strong on data close to its training set and weaker on anything further away, you should test one on your own before you trust it.
The demo below places the same six handbook pages as points on a map of meaning. Pick one of the searches and watch where the map puts it, because the query about 'days off' ends up beside the paid leave page although it shares no words with that page, which is the case the keyword demo got wrong.
Pick a search
Hybrid search
Since the two patterns fail in opposite ways, the obvious move is to run both of them and merge what they return. That is what hybrid search does, so a single query brings back the semantic matching of the vector side and the precise word matching of the keyword side in one ranked list.
How the scores are merged
Keyword scores and vector scores run on different scales, so you cannot add one to the other directly. A keyword score of 12 and a vector similarity of 0.83 measure different quantities, in the way that a sprinter's finishing time and a gymnast's score do, so adding them together produces nothing you could use. The merging method that most engines reach for gets around this by throwing the raw scores away and keeping only the finishing positions, and it is called Reciprocal Rank Fusion. A 2023 analysis of fusion functions for hybrid retrieval examines it as the standard rank-based approach.
The method scores the two lists in the way that a judge would score a two-event competition. Each of the searches produces its own ranked list, and every document takes points from each list according to the position it reached, under the formula 1 / (k + r), where r is the rank of the document in that list and k is a constant that defaults to 60. The top position is worth the most points, the second is worth slightly fewer, and the points shrink steadily as you go down the list. A document that both searches rank highly therefore takes points from both lists and comes out at the top of the merged list, while a document that only one of them ranks highly still appears, further down. The main alternative to this method is a weighted blend of , in which a single parameter slides the mix from pure keyword to pure vector.
Why k defaults to 60
The constant k sets how much more the top position is worth than the positions below it. At k = 0 the top position scores 1 while the second scores 0.5, so the top pick of one list takes double the points of its runner-up and can outweigh everything the other list found. At k = 60 the top position scores 1/61 while the tenth scores 1/70, which is a gap of about 13 per cent, so a document reaches the top of the merged list by ranking well on both lists. The value of 60 came out of trial and error in the original evaluation of the method, and it has held as the convention ever since.
What the numbers show
The Microsoft study cited earlier measured all three of the patterns across a range of query types, and it scored relevance as nDCG@3, on which a higher number is better.
| Query type | Keyword | Vector | Hybrid |
|---|---|---|---|
| Concept-seeking queries | 39.0 | 45.8 | 46.3 |
| Exact-phrase queries | 51.1 | 41.5 | 51.0 |
| Keyword-style queries | 79.2 | 11.7 | 61.0 |
| Queries with misspellings | 28.8 | 39.1 | 40.6 |
| Long queries | 42.7 | 41.6 | 48.1 |
Two results in that table are worth your attention. Hybrid search is the best or nearly the best pattern on almost every row, which is what makes it the sensible default for anything a user touches. It also has one clear weak spot, since it scores 61.0 on pure keyword-style queries, well below the 79.2 that keyword search reaches, because merging in a poor vector result pulls down a keyword result that was already right. The next pattern is what closes that gap.
Before you move on, you can try the fusion for yourself. The demo below runs the keyword ranking and the semantic ranking from the two earlier demos side by side and merges them by position. Moving the slider changes how much each of the two sides counts, and the page that both sides rank highly is the one that comes out first.
Pick a search
Keyword ranking
- 1Public holidays
- 2Expense refunds
- 3Paid leave policy
- 4Parental leave
- 5Remote work
- 6Building access
Fused ranking
- 1
Public holidays
high in bothkeyword rank 1 + semantic rank 2
- 2
Paid leave policy
high in bothkeyword rank 3 + semantic rank 1
- 3
Expense refunds
keyword rank 2 + semantic rank 5
- 4
Parental leave
keyword rank 4 + semantic rank 3
- 5
Remote work
keyword rank 5 + semantic rank 4
- 6
Building access
keyword rank 6 + semantic rank 6
Semantic ranking
- 1Paid leave policy
- 2Public holidays
- 3Parental leave
- 4Remote work
- 5Expense refunds
- 6Building access
Re-ranking
Every pattern so far optimises the first pass over millions of documents, where the need for speed forces an approximation. Re-ranking adds a second pass on top of that. You retrieve a generous set of candidates with one of the fast methods, and then you re-score only those candidates with a slower and more accurate model, before the engine shows the top few of them to a user or passes them to an AI system.
The accurate model is usually a cross-encoder, which takes the query and one candidate document together and scores how well the two of them match. The sentence-transformers documentation is direct about the trade-off, since a cross-encoder scores better than an embedding model while it runs far too slowly to cover a whole collection, which is why the recommended pattern is to retrieve roughly the top 100 candidates cheaply and re-rank only those. The Microsoft study above measured that exact arrangement, where adding a cross-encoder re-ranker on top of hybrid retrieval lifted the keyword-style row from 61.0 to 66.9 and the misspellings row from 40.6 to 54.6, which recovers most of what the fusion step had given up.
Filters and facets
One more pattern deserves a mention here, because you meet it in the checkboxes and dropdowns beside the results on most e-commerce sites. Those controls cut down the result set either before or after the ranking runs, and they contribute no score of their own. Nielsen Norman Group draws the distinction between filters and facets in these terms: a filter is any control that excludes some of the items in a set, while faceted navigation combines several filters, one for each attribute of the content, such as brand, size, colour, and price. Facets pair with any of the patterns above, since a hybrid search for 'lightweight rain jacket' would still need a size filter before a shopper could use what it returns.
One engine that runs every pattern
Having read this far, you might expect to assemble these patterns out of separate systems, with a keyword engine on one side, a vector database on the other, and your own code in the middle to merge what each of them returns. That split is what pushed me to build Narsil, an open-source distributed search engine in which every pattern in this article is one setting on a single query API.
Narsil covers the patterns in the following way.
- Full-text search scores with BM25 and supports field boosting, fuzzy matching through bounded Levenshtein distance (the same edit-distance idea described earlier), and match thresholds. Its ranking matches the Anserini reference implementation to within 0.006 nDCG@10 on the BEIR datasets, which means that the lexical side is calibrated against the academic standard.
- Vector search serves cosine, dot-product, and Euclidean queries against
vector[N]fields. While a field holds few vectors, the engine runs an exact brute-force scan over them, and once the field passes a promotion threshold, the engine builds an HNSW graph in the background and switches to approximate search, where it stores the vectors in compressed form (scalar quantisation) to keep memory use down. - Hybrid search runs both retrievals inside one query and fuses the two rankings through reciprocal rank fusion or a weighted blend, which you can tune per query. Embedding adapters turn text into vectors automatically on insert and on query, through OpenAI-compatible APIs, local Transformers.js models, or an adapter you write yourself.
- Filters and facets compose with any query mode, alongside sorting, grouping, highlighting, and cursor pagination.
The same engine runs in either of two settings. You can embed it in your own application process, where a query runs without a network hop, or you can run it as a standalone server with a REST API, a write-ahead log, and bulk import. On the public BEIR SciFact dataset it takes the top nDCG@10 at 0.6814, narrowly ahead of Elasticsearch and OpenSearch on 0.6789, while it answers 9 to 14 per cent more keyword queries per second, and the benchmarks page publishes the method along with the steps to reproduce it. You can try it in your browser or start with the documentation.
Choosing a pattern
The patterns compose with one another, and the evidence above points to a clear order in which you would adopt them.
- Start with keyword search when your users query with exact identifiers, when your budget is small, or when you need a result you can explain, since BM25 remains a strong baseline even against trained models.
- Add vector search once your users describe what they want in their own words and the vocabulary gap is costing you answers you can point to.
- Blend the two with hybrid fusion as your default for anything a user touches, because it holds up across the widest range of query types.
- Add a re-ranker when the top three results matter more to you than the top thirty, which is usually the case once those results feed the context window of an AI system.
None of these choices has to be permanent. You can measure rank quality with a labelled set of real queries, which means that you can introduce each pattern in turn, measure whether it improved your numbers, and keep it only where it did.