Vector & full-text fused for agentic retrieval
Keyword and vector retrieval fail in opposite directions: one misses the paraphrase, the other misses the exact id. Infino powers hybrid search that runs both over the same rows and fuses the rankings, providing the highest accuracy retrieval.
Retrieval modes measured by accuracy
Hybrid is consistently one of the most accurate forms of agentic retrieval, and Infino is one of the few engines that runs it natively.
| mode | accuracy |
|---|---|
| keyword | 40.6 |
| vector | 45.0 |
| hybrid | 48.4 |
| hybrid + rerankinginfino | 50.0 |
Sources: Azure AI Search, 2023 ↗ · BEIR ↗ · RRF, SIGIR 2009 ↗
Why hybrid is expensive, and why it isn't here
Running both retrievers on a search engine or a vector database means keeping the corpus and its vectors resident on hot block storage, in nodes that stay on. Infino reads the same rows from your bucket and meters the query work, so the bill tracks traffic.
| engine | per month |
|---|---|
| Infino | $9,715 |
| OpenSearch | $147,172 |
| Qdrant | $191,918 |
| Elasticsearch | $230,682 |
5B documents, 10M queries a month, 1 KB rows, each engine holding the text and a 1024-dimension vector. Model your workload →
Retrieval results are returned as a table
hybrid_search takes the table, the text column and the words to match, then the embedding column and the query vector. What comes back is an ordinary table: your columns plus a score, so WHERE, ORDER BY, and LIMIT work on it like any other query.
-- BM25 + vector, fused inside the engine SELECT _id, subject, score FROM hybrid_search( 'tickets', -- one table, one snapshot 'body', 'disk full on ingest', -- keyword side (OR) 'embedding', :q, 200 -- vector side, 200 deep each ) WHERE priority IN ('p0', 'p1') ORDER BY score DESC LIMIT 20;
- The keyword index and the embeddings sit inside the same Parquet files.
- Both searches read one version of the table, so the two sides can never be out of step with each other.
- The last argument,
200, is how many rows each side returns before they are merged.
Because the result is a table, the rest of the question stays in the same statement. Here the same call feeds a GROUP BY, asking for 5,000 rows a side so the counts cover the whole match set instead of the first page.
-- Which services retried a failed request, by team? SELECT team, count(DISTINCT service) AS services -- which services FROM hybrid_search('events', 'message', 'retry failed request', 'embedding', :q, 5000) -- BM25 + vector, fused GROUP BY team -- by team ORDER BY services DESC;
How two lists become one ranking
The two searches report different things. BM25 gives a relevance score, where a bigger number is a better match. Vector search gives a distance, where a smaller number is a better match. Adding them would be meaningless, so the engine throws both numbers away and uses each row’s position in its list.
- A row scores
1 / (60 + position)for each list it appears in. First place is worth1/61, tenth place1/70. Near the top counts for more, and the gap between positions shrinks as you go down. - A row found by both searches collects both scores, so the rows they agree on rise to the top. A row only one search found still keeps its place in the ranking.
- There is nothing to tune. You do not set a weight between keyword and vector, and the same query returns the same order every time.
Go deeper on hybrid search
- what is hybrid search? The two retrievers, the fusion arithmetic, k and recall, and how to see where the two disagree.
- queries/ The table-valued functions, and real queries: joins, full outer joins, and window functions over search results.
- object-storage/ A three-copy retrieval stack compared with one engine reading the files in place.
- patterns/ More retrieval patterns: scoped filters, CASE-routed verification, pinned snapshots.
Hybrid search questions
Why run both BM25 and vector?
They fail in opposite directions. BM25 finds the token “retry” and misses “backoff.” Vector finds the same idea said differently and misses an exact id. hybrid_search runs both over one snapshot and fuses the rankings.
What is the score column on hybrid_search?
The column contains the reciprocal-rank-fusion score, where higher is better. It is a separate ranking signal from the BM25 score and vector distance. ORDER BY score DESC lists the best blended matches first.
Do I tune a weight between BM25 and vector?
Fusion uses rank positions with a fixed constant of 60. The function exposes a single deterministic blend instead of an alpha or score-normalization step. A quality reranker can provide a second ranking over the returned rows.
Can I see the BM25 score and the vector distance too?
hybrid_search emits the fused score. Run bm25_search and vector_search as separate relations and join them on _id to inspect each raw signal and the disagreement set.
What is a table-valued search function?
hybrid_search (and bm25_search, vector_search) are relations. They take a table name, return that table’s columns plus a score, and belong in FROM. COUNT, WHERE, JOIN, and GROUP BY are ordinary SQL on top. k controls retrieval depth; LIMIT controls the rows displayed.
Where do the embeddings come from?
Infino can embed text on ingest using the model selected for the table. You can also send vectors from your own model. Embed the query with the same model you indexed. Keyword search and SQL run directly on text and columns.
Does hybrid search replace a reranker?
Infino retrieves and fuses candidates. A cross-encoder or other quality model can rerank the returned rows, while query rewrite, chunking, and labeled evaluation remain application concerns.