Supabase Easy RAG
A modular, lightweight Hybrid RAG engine built natively on PostgreSQL & Supabase.
Why Supabase Easy RAG?
- 🎯 High-Accuracy Hybrid Search: Combines semantic vector search with keyword matching — catches both conceptual questions and exact IDs/terms.
- 📖 Parent-Context Expansion: Searches precise 400-token chunks for high retrieval precision (89%+ Document Top-1, 92%+ Fact Recall), while feeding the full parent section to your LLM.
- 🔒 Native Multi-Tenant Security: Out-of-the-box Row-Level Security (RLS) via Supabase Auth (
auth.uid()) — users only see documents they own or are shared with them. - ⚡ High-Speed Parallel Ingestion: Automatic change detection (SHA-256) verifies 700+ docs/sec incrementally, with multi-threaded embedding generation.
- 🌍 Battle-Tested Multilingual: Evaluated across 11 languages with automatic text search dictionary fallbacks.
- 🔌 Zero Framework Overhead: Clean Python SDK and pure PostgreSQL RPCs. No heavy dependencies.
📊 Comprehensive Multilingual Benchmark (TyDi QA)
Evaluated against the complete Google Research TyDi QA gold-standard validation corpus (4,488 authentic Wikipedia articles, 5,077 real human questions across 11 typologically diverse languages) with 400-character chunking and Reciprocal Rank Fusion (RRF).
1. Global Information Retrieval (IR) Quality Metrics
| Benchmark Metric | Score | Description |
|---|---|---|
| Document Hit Rate @ 1 (Top-1) | 88.46% | Ground-truth relevant document is ranked #1 (Strict Document Match) |
| Document Hit Rate @ 3 (Top-3) | 91.61% | Ground-truth relevant document in Top-3 retrieved chunks |
| Document Hit Rate @ 5 (Top-5) | 92.34% | Ground-truth relevant document in Top-5 retrieved chunks |
| Document Hit Rate @ 10 (Top-10) | 92.75% | Ground-truth relevant document in Top-10 retrieved chunks |
| Document MRR (Mean Reciprocal Rank) | 0.9012 | Average reciprocal rank on ground-truth document retrieval |
| Answer Span Recall @ 5 | 91.90% | Exact fact-answer span is contained in the top-5 retrieved chunks |
| Incremental Verification Speed | 651.5 docs/sec | 4,488 documents verified via SHA-256 in 6.9 seconds (16 parallel workers) |
[!NOTE] Metric Rigor:
- Document Hit Rate @ K strictly requires the retrieved chunk to belong to the target ground-truth document.
- Answer Span Recall @ K verifies that the exact answer span is present in the retrieved chunk content for QA generation.
- Full benchmark is 100% reproducible via
python eval/corpora/fetch_tydiqa.pyandpython eval/benchmark.py.
2. Multilingual Breakdown Across 11 Languages
| Language | Language Family | Evaluated Queries | Doc Hit @ 1 | Doc Hit @ 5 | Doc MRR | Answer Recall @ 5 |
|---|---|---|---|---|---|---|
| Arabic | Afroasiatic (Semitic) | 964 | 89.2% | 92.8% | 0.908 | 92.0% |
| Finnish | Uralic (Agglutinative) | 920 | 90.0% | 93.0% | 0.913 | 92.9% |
| Russian | Indo-European (Slavic) | 828 | 91.5% | 93.8% | 0.926 | 93.2% |
| Telugu | Dravidian | 668 | 89.1% | 92.8% | 0.906 | 93.1% |
| Indonesian | Austronesian | 499 | 89.4% | 91.8% | 0.903 | 91.6% |
| Swahili | Niger-Congo (Bantu) | 475 | 87.4% | 92.6% | 0.895 | 91.6% |
| English | Germanic | 278 | 87.1% | 89.9% | 0.883 | 91.0% |
| Korean | Koreanic | 194 | 75.8% | 85.0% | 0.795 | 83.0% |
| Japanese | Japonic | 139 | 82.0% | 89.2% | 0.854 | 88.5% |
| Bengali | Indo-Aryan | 111 | 76.6% | 91.9% | 0.834 | 90.1% |
| Thai | Kra-Dai | 1 | 100.0% | 100.0% | 1.000 | 100.0% |
Quick Start
1. Installation
pip install supabase-easy-rag
2. Apply Database Migrations to Supabase
Export and run the SQL migrations:
easy-rag init-sql --output ./migrations --dimensions 1536
Apply 01_schema.sql and 02_functions.sql to your Supabase project (via Supabase CLI supabase db query --file ... or SQL Editor).
3. Configure Environment Variables
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_SERVICE_ROLE_KEY="your-service-role-key"
# Embedding Provider (OpenAI or Azure OpenAI)
OPENAI_API_KEY="sk-..."
# or Azure:
AZURE_OPENAI_API_KEY="your-azure-key"
AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
AZURE_OPENAI_EMBEDDING_DEPLOYMENT="text-embedding-3-large"
💻 Python SDK Usage
1. Hybrid Search with Parent-Context Expansion
from supabase_easy_rag import EasyRagClient
from supabase_easy_rag.providers.azure import AzureEmbeddingProvider
# Initialize provider & client
provider = AzureEmbeddingProvider(
api_key="...",
endpoint="https://your-resource.openai.azure.com",
model="text-embedding-3-large",
)
client = EasyRagClient(embedding_provider=provider)
# Search by dense chunk, expand to full parent section for LLM context
results = client.search_hybrid(
query="When was the Ottoman Empire established?",
match_count=5,
candidate_count=50,
rrf_k=60,
expand_context="section", # "section" or "document"
)
for item in results:
print(f"[{item.final_score:.4f}] {item.document_title} > {item.section_title}")
# Effective text contains the full parent section text
print(item.effective_text[:200] + "...")
2. High-Throughput Parallel Directory Ingestion
# Sync a directory of Markdown documents with 8 parallel workers
sync_stats = client.sync_directory(
directory_path="./knowledgebase_docs",
batch_size=30,
max_workers=8,
enable_chunking=True,
chunk_size=800,
chunk_overlap=100,
)
print(f"Synced {sync_stats['total_files']} files in parallel.")
3. Asynchronous Client (FastAPI / High-Concurrency)
from supabase_easy_rag import AsyncEasyRagClient
async_client = AsyncEasyRagClient(embedding_provider=provider)
results = await async_client.search_hybrid(
query="PostgreSQL connection pooling guidelines",
match_count=3,
expand_context="section",
)
🛠️ CLI Commands
# Export migration files
easy-rag init-sql --dimensions 1536 --output ./migrations
# Sync directory of documents
easy-rag sync ./docs --workers 8
# Execute test query with diagnostics
easy-rag query "What is distributed erasure coding?" --mode hybrid --count 5
# Manage backend API access tokens
easy-rag create-token "Production Ingestion Worker"
easy-rag list-tokens
⚙️ Architecture & Implementation Details
- Two-Stage Hybrid Fusion: Independent candidate pools are retrieved via indexed scans (
HNSWfor vector distance,GINfor full-text match) and fused using Reciprocal Rank Fusion: $$RRF_Score = \frac{w_v}{k + rank_v} + \frac{w_t}{k + rank_t}$$ This avoids arbitrary score normalization issues between cosine similarities and BM25/FTS weights. - Weighted Lexical Search: Uses PostgreSQL native
setweight()indexing where document titles receive WeightA($1.0$), section headings receive WeightB($0.4$), and chunk text receives WeightD($0.1$). - Candidate Pre-filtering: Full-text candidate scans limit initial matches to Top-200 before applying
ts_rankto minimize CPU cycles on frequent keywords. - Multi-Tenant Security: Enforces database-level isolation via Supabase Auth (
auth.uid()) using Row-Level Security (RLS) policies on documents and chunks.
📄 License
Distributed under the MIT License. See LICENSE for details.
Metadata
Release files for supabase-easy-rag 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| supabase_easy_rag-0.1.2.tar.gz | 101.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| supabase_easy_rag-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.9 kB
Release files / supabase_easy_rag-0.1.2.tar.gz
| Download URL | supabase_easy_rag-0.1.2.tar.gz |
|---|---|
| Size | 101.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a3964f0eedc8805ec5bed8447f563aa86f5cf27491626220af4512a8e5d39e3
|
|
BLAKE2b-256 checksum How to use checksums |
3dd7cd9c4b37b791a5e9dd426aca425e761359eaf0369851d6799645a6908630
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / supabase_easy_rag-0.1.2-py3-none-any.whl
| Download URL | supabase_easy_rag-0.1.2-py3-none-any.whl |
|---|---|
| Size | 41.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4b00c31800c76a4d5368f383c2e48fe61e06e14beaee218a7897f8f46fadb61c
|
|
BLAKE2b-256 checksum How to use checksums |
b09326e71a68ca32a41f3acfb70bfeb186a2dc7eb923bc2c455a29bead283c38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|