Search Modes Overview
| Mode | Purpose | Memory Backend | PgVector Backend |
|---|---|---|---|
:semantic | Find similar meaning | HNSWLib cosine similarity | pgvector HNSW index |
:fulltext | Find keyword matches | TF-IDF-like scoring | PostgreSQL tsvector |
:hybrid | Combine both | Two queries + RRF | Single-query with weights |
Semantic Search
Both backends use cosine similarity to find semantically similar content.Memory Backend (HNSWLib)
Uses Hierarchical Navigable Small World graphs for approximate nearest neighbor search.cosine_distance = 1 - cosine_similarity. A score of 1.0 means identical vectors.
Complexity: O(log n) average case for k-NN queries.
PgVector Backend
Uses PostgreSQL’s pgvector extension with HNSW indexing.<=> operator computes cosine distance. The HNSW index makes this efficient even for millions of vectors.
Fulltext Search
Memory Backend: TF-IDF-like Scoring
A simplified term-matching algorithm inspired by TF-IDF:"elixir pattern matching" (3 terms)
| Document | Matches | Term Ratio | Length | Length Factor | Score |
|---|---|---|---|---|---|
| ”Pattern matching in Elixir is powerful” | 3 | 1.0 | 6 | 0.51 | 0.51 |
| ”Elixir is great” | 1 | 0.33 | 3 | 0.72 | 0.24 |
| ”A very long document about many topics including elixir…“ | 1 | 0.33 | 50 | 0.26 | 0.09 |
Why “TF-IDF-like” not actual TF-IDF:
The simplification avoids maintaining a persistent term index, which would add complexity to an in-memory store.
| Feature | Real TF-IDF | Memory Backend |
|---|---|---|
| Term frequency | Counts occurrences | Binary (present/absent) |
| Inverse document frequency | Corpus-wide statistics | No corpus index |
| Document length normalization | Yes | Yes (via log factor) |
PgVector Backend: PostgreSQL Full-Text Search
Uses PostgreSQL’s battle-tested full-text search withtsvector and tsquery:
to_tsvector
Converts text to a searchable vector of lexemes (normalized word forms):
- “running” → “run”
- “patterns” → “pattern”
- Removes stop words (“the”, “is”, “a”)
to_tsquery
Converts query to search terms joined with
& (AND):"elixir pattern matching"→'elixir' & 'pattern' & 'match'
- Stemming (matches “running” when searching “run”)
- Stop word removal
- Proximity scoring
- Language-aware processing
Hybrid Search
Hybrid mode combines semantic and fulltext search. The implementation differs by backend:| Backend | Approach | Advantages |
|---|---|---|
| PgVector | Single-query weighted combination | Better coverage, configurable weights |
| Memory | Two queries + RRF | Simple, rank-based fusion |
PgVector Backend: Single-Query Hybrid
The pgvector backend uses a single SQL query that combines both scores:- Semantic scores (cosine similarity) naturally range 0-1
- Fulltext scores (ts_rank) vary widely based on document content
- The query normalizes fulltext scores using min-max scaling within the result set
Memory Backend: Reciprocal Rank Fusion (RRF)
For the memory backend, hybrid search uses Reciprocal Rank Fusion to combine results from separate queries. The Problem: Semantic and fulltext searches return scores on different scales:- Semantic: 0.0 to 1.0 (cosine similarity)
- Fulltext: Unbounded (ts_rank or term matching)
k is a constant (default 60) that prevents top-ranked items from dominating.
Algorithm:
"BEAM virtual machine"
| Document | Semantic Rank | Fulltext Rank | Semantic RRF | Fulltext RRF | Combined |
|---|---|---|---|---|---|
| ”Erlang runs on the BEAM VM” | 1 | 2 | 0.016 | 0.016 | 0.032 |
| ”The BEAM virtual machine” | - | 1 | 0.001 | 0.016 | 0.017 |
| ”The BEAM is Erlang’s runtime” | 2 | - | 0.016 | 0.001 | 0.017 |
Choosing the Right Mode
| Use Case | Recommended Mode |
|---|---|
| Conceptual questions (“How does X work?”) | :semantic |
| Exact terms, names, codes | :fulltext |
| General search, unknown query type | :hybrid |
| API/function lookup | :fulltext |
| Finding related concepts | :semantic |
Backend Comparison
| Aspect | Memory | PgVector |
|---|---|---|
| Setup | No database needed | Requires PostgreSQL + pgvector |
| Persistence | Lost on restart | Persisted |
| Semantic search | HNSWLib (excellent) | pgvector HNSW (excellent) |
| Fulltext search | Basic term matching | Full linguistic processing |
| Stemming | No | Yes |
| Stop words | No | Yes |
| Scale | < 100K vectors | Millions of vectors |
| Best for | Testing, small apps | Production |
Next Steps
Basic Usage
Learn essential ingest, search, and ask patterns
Evaluation
Compare search modes with retrieval metrics
Re-ranking
Improve results with second-stage scoring
GraphRAG
Combine graph and vector search with fusion