Retrievers
View SourceRetrievers provide different strategies for finding relevant documents based on queries.
Overview
The library provides four retriever implementations:
| Retriever | Method | Query Type | Best For |
|---|---|---|---|
| Semantic | Vector similarity | Embedding | Conceptual matching |
| FullText | Keyword matching | Text | Exact keywords |
| Hybrid | RRF fusion | Both | Balanced results |
| Graph | Knowledge graph | Both | Entity relationships |
Retriever Behaviour
All retrievers implement the Rag.Retriever behaviour:
@callback retrieve(retriever, query, opts) :: {:ok, [result()]} | {:error, term()}
@type result :: %{
id: any(),
content: String.t(),
score: float(),
metadata: map()
}Semantic Retriever
Uses pgvector L2 distance for vector similarity search.
alias Rag.Retriever
alias Rag.Retriever.Semantic
# Create retriever
retriever = %Semantic{repo: MyApp.Repo}
# Search with embedding
{:ok, results} = Retriever.retrieve(retriever, query_embedding, limit: 10)Scoring:
- Score = 1.0 - L2_distance
- Range: 0.0 (dissimilar) to 1.0 (identical)
Capabilities:
supports_embedding?()- truesupports_text_query?()- false
Best for:
- Finding conceptually similar content
- When query meaning matters more than exact words
FullText Retriever
Uses PostgreSQL tsvector for keyword matching.
alias Rag.Retriever
alias Rag.Retriever.FullText
# Create retriever
retriever = %FullText{repo: MyApp.Repo}
# Search with text
{:ok, results} = Retriever.retrieve(retriever, "GenServer state", limit: 10)Scoring:
- Score from PostgreSQL ts_rank function
- Multiple terms combined with AND
Capabilities:
supports_embedding?()- falsesupports_text_query?()- true
Best for:
- Finding documents with specific keywords
- Technical term searches
- When exact matches matter
Hybrid Retriever
Combines semantic and full-text using Reciprocal Rank Fusion (RRF).
alias Rag.Retriever
alias Rag.Retriever.Hybrid
# Create retriever
retriever = %Hybrid{repo: MyApp.Repo}
# Search with both embedding and text
{:ok, results} = Retriever.retrieve(retriever, {embedding, "search text"}, limit: 10)Query Format:
- Tuple of
{embedding_vector, text_query}
Scoring (RRF):
RRF(d) = Σ 1 / (k + rank(d)) where k = 60- Documents in both result sets get combined scores
- Balances semantic understanding with keyword precision
Capabilities:
supports_embedding?()- truesupports_text_query?()- true
Best for:
- Balanced semantic + keyword search
- When you want best of both methods
- Production RAG systems
Graph Retriever
Uses knowledge graph structure for context-aware retrieval.
alias Rag.Retriever.Graph
# Create retriever
retriever = Graph.new(
graph_store: graph_store,
vector_store: vector_store,
mode: :hybrid,
depth: 2,
local_weight: 0.7,
global_weight: 0.3
)
# Search
{:ok, results} = Retriever.retrieve(retriever, query_embedding,
limit: 10,
embedding_fn: &embed/1
)Search Modes
Local Search (:local)
- Vector search on entity embeddings
- Graph traversal to related entities
- Collect source chunks from entities
- Score by graph distance
{:ok, results} = Graph.local_search(retriever, query, limit: 10)Global Search (:global)
- Vector search on community summaries
- Returns high-level context
- Good for overview questions
{:ok, results} = Graph.global_search(retriever, query, limit: 10)Hybrid Search (:hybrid)
- Runs local and global in parallel
- Combines with weighted RRF
- Best of both approaches
{:ok, results} = Graph.hybrid_search(retriever, query, limit: 10)Configuration
| Option | Default | Description |
|---|---|---|
graph_store | required | Graph store module |
vector_store | required | Vector store module |
mode | :local | Search mode |
depth | 2 | Graph traversal depth |
local_weight | 1.0 | Weight for local in hybrid |
global_weight | 1.0 | Weight for global in hybrid |
Scoring Comparison
| Retriever | Score Source | Range | Formula |
|---|---|---|---|
| Semantic | L2 distance | 0-1 | 1.0 - distance |
| FullText | ts_rank | 0-1+ | PostgreSQL rank |
| Hybrid | RRF | varies | Σ 1/(60+rank) |
| Graph Local | Depth | 0-1 | 1/(1+depth) |
| Graph Global | Rank | 0-1 | 1/(1+rank) |
Complete Example
alias Rag.Router
alias Rag.Retriever
alias Rag.Retriever.{Semantic, FullText, Hybrid}
alias Rag.Reranker
alias Rag.Reranker.LLM
# Setup
{:ok, router} = Router.new(providers: [:gemini])
query = "How does GenServer handle state?"
# Get query embedding
{:ok, [query_embedding], router} = Router.execute(router, :embeddings, [query], [])
# Semantic search
semantic_retriever = %Semantic{repo: Repo}
{:ok, semantic_results} = Retriever.retrieve(semantic_retriever, query_embedding, limit: 10)
# Full-text search
fulltext_retriever = %FullText{repo: Repo}
{:ok, fulltext_results} = Retriever.retrieve(fulltext_retriever, query, limit: 10)
# Hybrid search
hybrid_retriever = %Hybrid{repo: Repo}
{:ok, hybrid_results} = Retriever.retrieve(hybrid_retriever, {query_embedding, query}, limit: 10)
# Compare results
IO.puts("Semantic: #{length(semantic_results)} results")
IO.puts("FullText: #{length(fulltext_results)} results")
IO.puts("Hybrid: #{length(hybrid_results)} results")
# Rerank hybrid results
reranker = LLM.new(router: router)
{:ok, reranked} = Reranker.rerank(reranker, query, hybrid_results, top_k: 5)
# Use top results for RAG
context = Enum.map(reranked, & &1.content) |> Enum.join("\n\n")Choosing a Retriever
Use Semantic when:
- Query meaning matters more than keywords
- Finding conceptually similar content
- Working with paraphrased queries
Use FullText when:
- Searching for specific terms
- Technical/domain-specific queries
- Exact keyword matching needed
Use Hybrid when:
- Want balanced results
- Building production RAG systems
- Unsure which method works best
Use Graph when:
- Entity relationships matter
- Need multi-hop reasoning
- Building knowledge-intensive applications
Pipeline Integration
# In a pipeline step
def retrieve_step(input, context, _opts) do
retriever = %Hybrid{repo: context.repo}
embedding = Context.get_step_result(context, :embed_query)
query = context.query
case Retriever.retrieve(retriever, {embedding, query}, limit: 10) do
{:ok, results} -> {:ok, results}
{:error, reason} -> {:error, reason}
end
end