Run a complete hybrid search example
Run a complete hybrid search example
These examples use three sample records and hand-written vectors, so no
embedding service is needed. Each program creates a temporary local table
and removes it when finished.The puppy record ranks first because both searches place it first. The query
returns
- Python: Install with
pip install lancedb, save ashybrid_search.py, then runpython hybrid_search.py. - TypeScript: Install with
npm install @lancedb/lancedb, save ashybrid_search.mts, then runnode hybrid_search.mtswith Node.js 22.18 or later. - Rust: Download and extract the complete Rust examples, then run
cargo run --locked --bin hybrid_searchfrom the extracted directory.
_relevance_score, with higher values first. This small example shows
the mechanics; evaluate retrieval quality with embeddings and queries from
your own application.Generate query embeddings automatically
1. Setup
The following walkthrough uses Sentence Transformers in Python and OpenAI in TypeScript. Install the corresponding provider packages before starting. Python downloads a local model; TypeScript calls OpenAI. Installlancedb sentence-transformers pandas for Python, or
@lancedb/lancedb apache-arrow openai for TypeScript. Set your OpenAI API key
as described in the OpenAI embedding setup.
Run the steps for your chosen language in order, choosing one connection option.
2. Connect to LanceDB
Choose a LanceDB Embedded connection or use your Enterprise connection details. Embedded3. Configure Embedding Model
Configure the model used for both document and query embeddings.4. Create Table and Schema
Define the data structure for your documents, including both the text content and its vector representation.5. Add Data
Insert sample documents into your table, which will be used for both semantic and keyword search.6. Build Full Text Index
Create a full-text search index on the text column to enable keyword-based search capabilities.7. Set Reranker [Optional]
RRF is the default. The examples below configure it explicitly. Other rerankers and their language support are described in Reranking.8. Hybrid Search
Perform a hybrid search query that combines semantic similarity with keyword matching, using the specified reranker to merge and rank the results.9. Supply a vector and text separately
You can supply the vector and text separately. The vector must use the same model and dimensions as the stored embeddings. This example reuses the model configured above; the complete example at the top also demonstrates this pattern in TypeScript and Rust.Control the candidate results
Use a result limit, metadata filters and vector distance bounds to control which candidates are available to the reranker. The examples below show each option on the query builder.Set
limit() to the number of results your application needs. The default is 10.
A larger candidate set can help a reranker find relevant records, but adds work.Returning row IDs
Passwith_row_id(True) (Python) or withRowId() (TypeScript) to include the internal _rowid column in the results. This is useful for joining hybrid results back to a primary table, or for deduping across multiple queries:
Bounding vector distance
distance_range(lower, upper) (Python) and distanceRange(lower, upper) (TypeScript) constrain the vector half of the hybrid query to the half-open interval [lower, upper). This is helpful when you want to cap how far semantic candidates can drift from the query vector before reranking:
Prefilter vs. postfilter
A hybrid query applies its metadata filter to both the vector and full-text searches. Prefiltering, the default, restricts eligible rows before retrieval. Postfiltering removes candidates after retrieval and can leave fewer results than requested. See Filtering.explain_plan on a hybrid query to see whether the filter pushed into the scan or ran as a separate FilterExec step.
Choose and evaluate a reranker
Start with RRF, then compare alternatives on representative queries. Review which relevant rows reach the candidate set before evaluating how a reranker orders them. Record latency as well as relevance: increasing candidate counts or applying a model-based reranker adds work. Reranking runs in the application for both Embedded and Enterprise connections. See Reranking for model-free fusion, model-based rerankers, custom implementations and score interpretation. In synchronous Python,.rerank(...) accepts a reranker and a normalize
option ("score" or "rank"). Normalization matters for methods that blend
raw scores; RRF uses rank positions. These are Python query options, not a
shared signature across every SDK.