ANSWERS · SEARCH QUALITY

What is hybrid search?

AUTHOR · XERJ documentation team · REVIEWED BY · XERJ engineering team · PUBLISHED · 2026-10-30 · UPDATED · 2026-10-30
SHORT ANSWER · UPDATED 2026-10-30

What is hybrid search? It runs a keyword search such as BM25 and a vector search on the same query, then merges the two ranked lists into one. Keywords catch exact words like error codes and names. Vectors catch the same idea in different words. Fusion, often Reciprocal Rank Fusion, combines the ranks.

TL;DR Hybrid search runs two searches on the same query: a full-text search such as BM25 and a vector search. Each returns a ranked list. A fusion step, usually Reciprocal Rank Fusion, merges them into one list. You get exact matches and close meanings in the same results.

Diagram

One query, two rankings, one list

The query goes to BM25 and to vector search. Each returns a ranked list. Fusion merges them into one list. Query "server down" BM25 scores shared words rank 1, 2, 3 Vector search scores closeness of meaning rank 1, 2, 3 Fusion RRF, k=60 1 list
Both searches run on the same query. Fusion reads only the rank of each result, so a BM25 score and a cosine score never have to be put on one scale. In XERJ both run inside one index and one request.
PASTE THIS TO YOUR AI AGENT — IT DOES THE REST Act as a coding agent. Read https://xerj.org/llms.txt, install XERJ, start a local node with --embed-mode neural, index a folder of my docs with xerj autoindex, then run the same question three ways (match, knn, hybrid with fusion rrf) and show me the top 5 of each side by side so I can see what hybrid search adds.
RUN THIS XERJ COMMAND curl -fsSL https://xerj.org/get | sh Install the single XERJ binary.
RUN THIS XERJ COMMAND xerj --embed-mode neural Start a local node that embeds text with all-MiniLM-L6-v2. The model downloads once, about 90 MB.
RUN THIS XERJ COMMAND curl -s -XPOST 'http://127.0.0.1:9200/docs/_search' -H 'content-type: application/json' -d '{"query":{"hybrid":{"queries":[{"query":{"match":{"body":"server unreachable"}},"weight":1.0},{"query":{"knn":{"field":"body_vector","k":10,"num_candidates":50,"query_vector":[]}},"weight":1.0}],"fusion":"rrf"}},"size":5}' One hybrid request. Fill query_vector with your embedding; the empty array marks where the floats go.

Why two searches

Full-text search and vector search fail in different places.

BM25 scores the words a result shares with the query. It is very good at exact things: an error string, a function name, a ticket number like INC-4821. It finds nothing when the result uses other words for the same idea.

Vector search turns text into a list of numbers and returns the closest results by meaning. It finds "cannot reach the server" for the query "server unreachable". It is weaker on exact tokens, because a model can place port 9200 and port 9300 very close together.

Real queries mix both kinds. Hybrid search does not ask you to choose.

Try it

Pick a query or type your own. Watch the two columns disagree, then move the sliders to see how fusion settles it.

Try it: fuse two rankings

Reciprocal Rank Fusion, live

Six lines to search:

  1. Error: connection refused on port 9200
  2. The agent cannot reach the search server
  3. Restart the server if the index looks stuck
  4. Give a coding agent memory across sessions
  5. Port 9200 is the default search API port
  6. My assistant forgets what we discussed yesterday
BM25 top 3
    Vector top 3 (toy)
      Fused (RRF)

        With JavaScript off, here is the BM25 side for "search server down", as a local XERJ node scored it: line 2 at 2.079, lines 3 and 5 at 0.9829. The word "down" is in no line, so it adds nothing.

        Runs in your browser and sends nothing. The BM25 column uses the formula and defaults in XERJ's bm25.rs (k1 1.2, b 0.75); on these six lines it matched a local XERJ v1.0.0-rc.97 node to 4 decimals for 6 test queries on 2026-10-30. The vector column is a toy: each word gets 5 hand-set numbers (network, server, memory, error, time), not a trained model. Fused score per line is the sum of weight / (k + rank).

        Three things to notice:

        How Reciprocal Rank Fusion works

        RRF ignores raw scores. It only reads where a result landed in each list. Each list adds weight / (k + rank) to a result. Results that rank well in both lists rise to the top.

        A worked example with k = 60 and both weights at 1:

        ResultBM25 rankVector rankRRF score
        A131/61 + 1/63 = 0.0323
        B211/62 + 1/61 = 0.0325
        Cnot found21/62 = 0.0161

        B wins because it ranks high in both lists. C still makes the list even though BM25 never saw it. That is the point of hybrid search.

        The RRF guide covers when to change k and when to use a weighted score sum instead.

        Does it help? A recorded run

        Benchmarks are the honest check. This run used the public BEIR SciFact set on one XERJ node.

        Recorded run: BEIR SciFact, 300 queries

        nDCG@10, higher is better

        • BM25 only0.6572
        • Vectors only (MiniLM)0.6764
        • Hybrid, RRF0.6993
        From benchmarks/beir-hybrid/results/scifact.txt in the XERJ repository: xerj v1.0.0-rc.74 with --embed-mode neural (all-MiniLM-L6-v2), one node, run on 2026-09-18. Bars start at 0 and the full width is 1.0. The measured nDCG page has the NFCorpus run and the method.

        Hybrid beat both single methods here, by about 2 to 4 points. On NFCorpus the same setup gave 0.3016 for BM25, 0.3291 for vectors and 0.3448 for hybrid. Your data may differ, so measure it. The nDCG page shows how.

        Hybrid search without a vector database

        Many hybrid setups run two systems: a search engine for keywords and a vector database for embeddings, plus code to merge them. That means two stores to keep in sync.

        XERJ keeps the inverted index and the vectors in the same index. One request carries both sub-queries and the node fuses them. The how XERJ combines search page shows the full request and response.

        SetupStores to runWho merges the lists
        Search engine plus vector database2Your code
        One engine with both index types1The engine

        When to skip it

        How to try it with XERJ

        Use the Copy the prompt button and paste it into your coding agent, or run the commands above yourself. XERJ is one binary on your machine. The neural embedder runs locally, so the text you index stays on your disk.

        If you want a ready-made corpus to test against, hub.xerj.org lists search packs you can pull.

        Sources checked

        All checked on 2026-10-30.

        FAQ

        What is hybrid search in one sentence?

        It runs a keyword search and a vector search on the same query and merges the two ranked lists into one list.

        Is hybrid search better than vector search alone?

        Often, but not always. On the recorded BEIR SciFact run, hybrid RRF scored 0.6993 nDCG@10 against 0.6764 for vectors alone. Test it on your own queries before you decide.

        Do I need a vector database for hybrid search?

        No. You need one place that holds both an inverted index and vectors. XERJ keeps both in the same index and fuses them inside one request.

        What does the k in Reciprocal Rank Fusion do?

        Each result adds weight / (k + rank) to its score. A larger k flattens the gap between rank 1 and rank 10. XERJ uses k = 60 by default and accepts another value.

        Should I use RRF or a weighted score sum?

        Start with RRF because it ignores raw scores, which sit on different scales. XERJ also offers linear fusion, which normalizes each list and adds the weighted scores.

        When is hybrid search not worth it?

        When every query is an exact identifier, plain BM25 is enough. When every query is a loose paraphrase over short texts, vectors may be enough. Hybrid helps when you get both kinds.

        Related