Skip to main content
OpenGround uses hybrid search combining two complementary techniques: vector similarity (semantic search) and BM25 (keyword search). This approach finds relevant documentation even when queries use different terminology than the source material.

Hybrid Search Architecture

Why Hybrid?

Strengths:
  • Finds conceptually similar content
  • Works with synonyms and paraphrasing
  • Understands context and intent
Example:
Weaknesses:
  • May miss exact technical terms
  • Can retrieve overly broad matches

Query Flow

Let’s trace a search query through OpenGround’s system.

1. Query Input

From the CLI or MCP server:
Or from an AI agent via MCP:

2. Query Embedding

From query.py:94, the query is converted to a vector:
Query embedding uses the same model as document embedding, ensuring they’re in the same vector space.

3. Hybrid Search Execution

From query.py:96-104, LanceDB performs the hybrid search:
1

Query Type: Hybrid

Tells LanceDB to combine vector and BM25 search.
2

BM25 Component

Performs keyword search using the full-text index on the content field.
3

Vector Component

Performs cosine similarity search in the vector space.
4

Metadata Filtering

Filters results to specific library/version before ranking.
5

Limit Results

Returns only the top K highest-scoring chunks.

4. Result Ranking

LanceDB internally combines scores from both search types:
LanceDB’s hybrid search uses sophisticated score fusion techniques. The exact algorithm is internal to LanceDB.

5. Result Formatting

From query.py:110-134, results are formatted for the user:
Example output:
BM25 (Best Matching 25) is a probabilistic ranking function for keyword search.

BM25 Index Creation

From ingest.py:223-226, the full-text index is created after ingestion:
The content field is indexed for full-text search. This enables BM25 scoring on chunk text.

How BM25 Works

BM25 ranks documents based on:
How often a query term appears in the document.
Saturation: BM25 uses diminishing returns - 5 mentions isn’t 5x better than 1.

BM25 Example

Vector search finds chunks with embeddings close to the query embedding.

Cosine Similarity

From mathematical perspective:
Cosine similarity measures the angle between vectors, not their magnitude. Values range from -1 (opposite) to 1 (identical).

Normalized Embeddings

From embeddings.py:154, embeddings are normalized:
Normalization benefits:
  • Embeddings have unit length (magnitude = 1)
  • Cosine similarity simplifies to dot product
  • Faster computation: similarity = dot(a, b) instead of dot(a, b) / (norm(a) * norm(b))

Approximate Nearest Neighbor

LanceDB uses ANN (Approximate Nearest Neighbor) indexes for fast vector search:
LanceDB automatically builds ANN indexes for the vector field.

Metadata Filtering

From query.py:98-103, filters are applied before ranking:

Why Filter First?

SQL Injection Prevention

From query.py:46-65, user input is escaped:
Always escape user input in SQL WHERE clauses to prevent injection attacks.

Retrieving Full Content

Search results contain chunk content (800 chars). To get the full page, use get_full_content (from query.py:211-251):
1

Query All Chunks

Find all chunks belonging to the same URL and version.
2

Sort by Chunk Index

Ensure chunks are in original order (chunk_index: 0, 1, 2, …).
3

Concatenate Content

Join chunk content with double newlines to preserve formatting.
4

Format as Markdown

Return complete page with title, source, and full content.

Query Caching

From query.py:12-15, database connections are cached:
Caching avoids reconnecting to the database for every query. Especially important for MCP server which handles many sequential requests.

Search Configuration

From config.py:69, default top K:
Configure with:
Choosing top K:
  • Small (3-5): Precise, focused results for AI agents
  • Medium (10-15): Good for exploratory queries
  • Large (20+): Comprehensive coverage, but may include noise

Performance Characteristics

Factors:
  • Embedding model speed (GPU vs CPU)
  • Number of chunks in database
  • Complexity of filters

Search Quality Tips

Good queries:
  • “how to configure embeddings”
  • “FastAPI dependency injection”
  • “error handling best practices”
Poor queries:
  • “stuff” (too vague)
  • “asdfasdf” (gibberish)
  • Single words without context
BM25 rewards exact matches:
Always specify version for accurate results:
Search results are chunks (800 chars). For complete context:

Next Steps

Architecture

See how search fits into OpenGround’s architecture

Embeddings

Deep dive into the vector embeddings powering semantic search

Sources

Learn what documentation can be searched

CLI Reference

Complete reference for the query command