curiosity

Article · Hybrid search

What is hybrid search?

Hybrid search runs two searches on the same query and merges their results into one ranked list. Keyword search finds records that contain the exact terms, such as a part number. Meaning-based search finds records that describe the same thing in other words.

Topic Hybrid search Reading time 7 min References 7 Updated October 2026

In short

Hybrid search combines keyword search and meaning-based search into one ranked list. Keyword search, also called lexical search, matches the words in a query. Meaning-based search, also called vector or semantic search, matches what the query is about. Each misses what the other finds, so a hybrid system runs both and merges the results.

What separates it from its neighbors is the merge. Keyword search with a synonym list is still one search. Vector search on its own has no exact match. A reranker reorders a single list after the fact. Hybrid search starts from two lists and has to decide how to make them one. Elastic’s explainer notes that the term can cover other pairs, such as text and image search, but keyword with meaning is the common one.

Keyword search: the exact words

Keyword retrieval breaks each record into terms and builds an index from every term to the records that contain it. Keyword engines commonly rank the matches with BM25, a scoring function that Stephen Robertson and Hugo Zaragoza reviewed in 2009.

BM25 follows three rules. A rare term counts for more than a common one. A term counts for less each time it repeats. In the review’s words, any one term’s “contribution to the document score cannot exceed a saturation point”. And a long record is damped, so it cannot win by size alone.

Two properties make keyword search hard to replace. It finds an exact string such as A320-2741-08, and it can say why a record matched: these are the terms it shares with the query. Its weakness is vocabulary. A field report about an aft door seal weeping fluid shares no word with a ticket about a hydraulic leak on door 4.

Meaning-based search: the closest vectors

Meaning-based search turns each record, or each passage of a long one, into a vector: a list of numbers produced by a language model. Texts about the same thing land close together, whatever words their authors chose. The query becomes a vector the same way, and the search returns the records nearest to it. An index such as HNSW finds those neighbors without comparing the query with every record.

That is right for descriptions and wrong for identifiers. Part 2741-08 and part 2741-09 sit close in meaning, and they are different parts. Without a minimum similarity, a vector search also returns its nearest records when none of them is relevant, and the cutoff has to be tuned. A match is a distance, so it cannot say which words made two records close. Our post on identifiers and similarity shows each of these with invented part numbers.

How the lists merge

Two rankings become one

One query, two ranked lists, merged by rank. The records and their ranks are invented for the drawing. Pick a step to stop it and read it.

Reciprocal rank fusion merging two ranked lists The query A320-2741-08 fluid loss runs as a keyword search and a meaning-based search. Keyword ranks a supplier notice, a ticket and a maintenance log for the wrong part. Meaning ranks a field report, the ticket, the log and the notice. Each record scores 1 divided by 60 plus its rank in every list it appears in. In the merged list the ticket, second in both, comes first, and the field report, found by meaning only, drops to fourth. QUERYA320-2741-08 fluid lossKEYWORD · BM25MEANING · VECTORS01Notice · 2741-081/6102Ticket · 2741-08 leak1/6203Log · 2741-091/6301Report · seal weeping1/6102Ticket · 2741-08 leak1/6203Log · 2741-091/6304Notice · 2741-081/64RANK FUSION · 1 / (60 + RANK)01Ticket · leak on part 2741-080.032302Notice · part 2741-080.032003Log · fluid loss, part 2741-090.031704Report · aft door seal weeping0.0164
Reciprocal rank fusion merging two ranked lists A query runs as a keyword search and a meaning-based search, giving two ranked lists. Each record scores 1 divided by 60 plus its rank in every list it is in. The ticket, second in both lists, comes first in the merged list; the field report, found by meaning only, drops to fourth. QUERYA320-2741-08 fluid lossKEYWORDMEANING01Notice 2741-0802Ticket 2741-0803Log 2741-0901Report · seal02Ticket 2741-0803Log 2741-0904Notice 2741-08RANK FUSION · 1/(60 + RANK)01Ticket · leak, 2741-080.032302Notice · part 2741-080.032003Log · part 2741-090.031704Report · seal weeping0.0164
  1. 01

    One query, two searches

    A technician types A320-2741-08 fluid loss. It runs as a keyword search and as a meaning-based search.

  2. 02

    Keyword ranks by terms

    Three records share terms with the query. The supplier notice names the exact part, so it ranks first.

  3. 03

    Meaning ranks by closeness

    Four records are close in meaning. The field report never names the part, and it ranks first here.

  4. 04

    Each rank becomes a score

    Reciprocal rank fusion gives a record 1 / (60 + rank) from every list it is in, and adds them up.

  5. 05

    One list

    The ticket is second in both lists and comes out first. The report, found by one search only, drops to fourth.

How the two lists are merged

The two searches score on different scales. A BM25 score has no fixed top, and a vector similarity usually falls between 0 and 1. Elastic’s explainer puts the problem plainly: “The main challenge lies in merging multiple ranked lists into a single, coherent ranking.”

There are two common answers. The first normalizes both scores to the same range and adds them with a weight, so a setting decides how much keyword counts against meaning. It can be tuned well, but the right weight depends on the data and has to be measured.

The second ignores the scores and uses only the ranks. Reciprocal rank fusion, published by Cormack, Clarke and Büttcher in 2009, gives each record 1 / (k + rank) from every list it appears in and adds them up. They fixed k at 60 in a pilot study. In their words, “The constant k mitigates the impact of high rankings by outlier systems.”

In the drawing above, the ticket is second in both lists and scores 1/62 + 1/62, about 0.0323. The field report tops the meaning list but is missing from the keyword list. It scores 1/61, about 0.0164, and drops to fourth. A record that both searches rank well comes out on top.

When the exact match has to win

Fusion rewards agreement, which is not always what the reader needs. In the drawing, the maintenance log for part 2741-09 ranks third for a query about 2741-08. It shares the words fluid loss and sits close in meaning. For a technician it is the wrong part.

So treat identifiers as their own part of the query. Spot them with a pattern for the company’s part numbers, or with a list of known ones. Match them exactly against the field that holds them. Then rank the descriptive part of the query, with both searches, among the records that carry that identifier.

When the identifier matches nothing, return nothing and say so. Offer the close matches as a separate list, marked as close, so the engineer chooses knowingly.

Identifiers first

Split the query

The identifier is matched exactly. The description is ranked by both searches among the records that carry it. Pick a step to stop the drawing and read it.

A query split into an identifier and a description The query A320-2741-08 fluid loss aft is split by a pattern. The identifier is matched exactly against part numbers: part A320-2741-08 matches and the near miss A320-2741-09 is left out. Only records that mention the matched part stay, and both searches rank them by the description: a ticket, a field report and a supplier notice, all about the right part. QUERYA320-2741-08 fluid loss aftA320-2741-08fluid loss aftSPLIT BY A PATTERNIDENTIFIER · EXACT MATCHDESCRIPTION · BOTH SEARCHESPart A320-2741-08Part A320-2741-09LEFT OUTMENTIONS PART 2741-0801Ticket · leak, door 402Report · seal weeping03Notice · supplier change
A query split into an identifier and a description The query is split into the identifier A320-2741-08 and the description fluid loss aft. The identifier matches part 2741-08 exactly; the near miss 2741-09 is left out. Only records that mention the part stay, ranked by the description. QUERYA320-2741-08 fluid loss aftA320-2741-08fluid loss aftIDENTIFIERDESCRIPTION · BOTH SEARCHESEXACT MATCHPart 2741-08NEAR MISS · OUTPart 2741-09MENTIONS PART 2741-0801Ticket · leak, door 402Report · seal weeping03Notice · supplier change
  1. 01

    The query

    One line that names a part and describes a fault: A320-2741-08 fluid loss aft.

  2. 02

    Split it

    A pattern for the company’s part numbers spots the identifier. The rest is the description.

  3. 03

    Match the identifier exactly

    Part 2741-08 matches. Part 2741-09 is a near miss, and it is left out.

  4. 04

    Narrow to that part

    Only the records that mention part 2741-08 stay in the running.

  5. 05

    Rank the description

    Both searches rank those records by fluid loss aft. Every result is about the right part.

How to evaluate a hybrid ranking

  • Judge real queries. Take queries from your search logs, and have people who know the records mark the right answers. 80 to 120 is a workable start.
  • Split them by kind. Score identifier queries and descriptive queries separately. An average can hide a ranking that got better at descriptions and worse at part numbers.
  • Measure the merge. Compare keyword alone, meaning alone and the merged list on the same queries. NDCG at 10 is a common measure: it rewards putting the best records in the first ten. If the merged list does not beat both, the second search is not earning its cost.
  • Judge what is new. A new search surfaces records nobody judged, and unjudged records count as wrong. Judge the new ones near the top before you trust the comparison.
  • Check permissions on both sides. Both searches have to run as the person who asked. A record one search may not return must not arrive through the other.

Our post on measuring search relevance works through these measures, and the unjudged records problem, with examples.

How Curiosity does it

In Curiosity Studio, keyword and vector search run in one query over the same graph: see search for developers. Vector matches are added to the keyword results or rerank them, each above a similarity cutoff you set, so exact part numbers still match. The cutoffs are yours to measure against a judged set.

Studio’s similarity engine can merge its sources by weighted score or by reciprocal rank fusion, which its documentation shows with k set to 60. A graph link can be one of those sources, so records that mention the same part number score together, as the post on identifiers shows.

The vectors are stored beside the records they describe. There is no second store to keep in sync, and no second set of permissions: see vector search for developers. Access is checked per record at query time. Studio ships local models that turn text into vectors in process, with no network, and hosted providers work too. The Modern enterprise search whitepaper puts hybrid search among the six layers of search, and What is enterprise search? covers the rest.

FAQ

Questions people ask

Is hybrid search better than vector search?

It is when people both name things and describe them, which is common in industrial records. Vector search alone misses exact identifiers such as part numbers, and keyword search alone misses paraphrases. Measure both and the merged list on your own judged queries before you decide.

What is reciprocal rank fusion?

A way to merge ranked lists using only the ranks. Each record gets 1 / (k + rank) from every list it appears in, and the sums decide the order. Cormack, Clarke and Büttcher introduced it in 2009 with k fixed at 60.

Why does vector search miss part numbers?

Two part numbers that differ by one character read almost the same to a language model, so their vectors sit close together. For an identifier, close is the failure: 2741-08 and 2741-09 are different parts. Match identifiers exactly with keyword search.

Do I need a separate vector database for hybrid search?

Not in Curiosity Studio. The vectors are stored beside the records in the graph. There is no second store to keep in sync, and no second set of permissions to maintain.

Your data. Your infrastructure.

Grounded, not guessed.