Calibrated Entropy-Weighted Hybrid Retrieval
I built this research-oriented hybrid retrieval system to test whether score calibration makes retrieval uncertainty measurable and useful for search performance. This interactive masterclass explains every architectural decision, mathematical algorithm, and implementation detail I built into the system.
7 Modes
Retrieval Ablation
Computer Science
& Science Data
Strict Guard
Low-Confidence Rejection
0.7071
Peak NDCG@10 Score
๐ฎ Operational Retrieval Engine & Live Queries
Test the actual hybrid retrieval pipeline I built across Computer Science & Biomedical corpora. If top candidates fall below minimum confidence (Score < 0.15), the system explicitly rejects the result to prevent hallucination.
What I Built & Core Technologies
Every library, framework, and model I integrated into the system.
Python 3.11
Core runtime language, typing system, async context management, and fast scientific computation.
FastAPI & Uvicorn
High-performance web API framework with automatic Pydantic request validation and interactive Swagger UI docs.
BM25Okapi (rank_bm25)
Lexical keyword retriever calculating term frequency / inverse document frequency scores across tokenized corpora.
FAISS & Sentence Transformers
Dense vector search using all-MiniLM-L6-v2 embeddings (384 dimensions) and IndexFlatL2 distance indexing.
Cross-Encoder Reranker
High-precision reranking using cross-encoder/ms-marco-MiniLM-L6-v2 (22M parameter pairwise cross-attention model).
NumPy & SciPy
Empirical CDF quantile mapping via np.searchsorted, Pearson correlation r with p-values, and bootstrap resampling.
End-to-End Pipeline & Background Data Flow
Click any pipeline node to expand and inspect its detailed execution logic right beneath that step.
Query Receipt & Tokenization
User query hits POST /query endpoint
Step 1: User Query Input & Tokenization
The user submits a natural language search query (e.g. "Transformer models rely on multi-head self-attention mechanisms.") to the POST /query endpoint. The query is cleaned and tokenized separately for lexical and dense search streams.
Dual Parallel Retrieval (BM25 + FAISS)
Retrieves candidate_k=20 chunks from both engines
Corpus-Level CDF Quantile Calibration
Maps raw scores to corpus percentiles via np.searchsorted
Shannon Entropy Computation (H_sparse & H_dense)
Measures retrieval uncertainty across score distributions
Adaptive Dynamic Alpha Weight Calculation
Computes precision-weighted balance: ฮฑ = H_dense / (H_dense + H_sparse + ฮต)
Weighted Linear Fusion
Score = ฮฑ ยท BM25_cal + (1-ฮฑ) ยท FAISS_cal
Cross-Encoder Pairwise Reranking
Full cross-attention scoring using ms-marco-MiniLM-L6-v2
Document ID Deduplication
Keeps top-scoring chunk per source document
Final Output & Telemetry
Returns top-k snippets, sources, scores, latency & entropy metrics
How Data Was Before, How It's Split, & Persistence
From raw text to FAISS vectors, BM25 inverted indices, and corpus CDF lookup tables.
๐ 1. Input Data Structure
Raw Sources: Uploaded PDF files, plain text (.txt), markdown (.md), Computer Science documents, or the benchmark SciFact corpus (5,183 PubMed scientific abstracts).
Before Chunking: Long documents with full title, abstract, and body text. Raw scores across different length documents would introduce severe length bias without chunking.
โ๏ธ 2. Recursive Chunking Strategy
Using RecursiveCharacterTextSplitter:
chunk_size = 800characterschunk_overlap = 120characters
Metadata Attached: Each chunk is assigned a tuple key (source_doc_id, chunk_index), e.g. "CS-101:1".
๐๏ธ 3. FAISS Vector Store
Each chunk is embedded into a 384-dimensional vector using all-MiniLM-L6-v2 and saved to data/faiss_index/index.faiss.
๐ 4. BM25 Tokenized Corpus
Chunks are lowercased, stripped of punctuation, whitespace-split, and pickled in bm25_index.pkl for BM25Okapi keyword matching.
๐ 5. Corpus CDF Score Arrays
100 sample queries are scored against ALL 17,243 corpus chunks offline (1,724,300 scores per retriever). Sorted arrays saved to corpus_cdf_bm25.npy and corpus_cdf_dense.npy.
Exact Formulas & Algorithm Mechanics
Understanding score calibration, entropy, precision-weighting, and statistical testing.
1. BM25 Okapi Keyword Scoring
BM25 measures term frequency saturation and document length normalization:
Where k1=1.5 controls term frequency saturation, b=0.75 controls document length penalty, and IDF(qi) = ln((N - n(qi) + 0.5) / (n(qi) + 0.5) + 1).
2. FAISS Dense L2 Distance to Similarity
FAISS IndexFlatL2 computes Euclidean distance dL2. I convert distance to similarity score in (0, 1]:
3. Corpus-Level Quantile CDF Calibration
Per-query min-max destroys global scale information. Instead, I map score s to its percentile rank in the 1.7M corpus score distribution:
Maps any raw score distribution to approximately uniform [0, 1] quantile space while preserving per-query confidence variation.
4. Shannon Entropy of Score Distributions
Normalizes scores into a probability mass pi = Si / ฮฃ Sj, then calculates Shannon entropy (base 2):
Note: For negative-valued z-scores, softmax is applied: pi = eSi - max(S) / ฮฃ eSj - max(S) to prevent affine collapse.
5. Bayesian Precision-Weighted Fusion Weight (ฮฑ)
Per-query dynamic weight allocation based on retriever entropy (uncertainty):
If FAISS dense retrieval has high entropy (uncertainty), ฮฑ $\to$ 1 (system relies on BM25). If BM25 has high entropy, ฮฑ $\to$ 0 (system relies on FAISS dense vectors).
Live Entropy & Adaptive ฮฑ Weight Simulator
Adjust dense and sparse entropy sliders to watch how the system dynamically shifts trust!
What Each File & Function Does
Exhaustive guide to all 9 source files and their underlying functions.
FastAPI application defining REST API endpoints and startup handlers.
lifespan(app): Async startup context manager that creates upload directory and triggersstore.load().GET /health: Returns index status, loaded files, and document counts.GET /modes: Lists all 7 available retrieval modes with descriptions.POST /upload: Accepts PDF, TXT, MD files, saves todata/uploads/, and indexes chunks.POST /query: Main search endpoint accepting question, top_k, and retrieval mode.
Central document manager and mode router combining FAISS, BM25, and Cross-Encoder.
DocumentStore.load(): Loads FAISS vectorstore, BM25 pickle index, CDF arrays, and text lookup map from disk.DocumentStore.add_file(path): Extracts text from PDF/TXT/MD, chunks text, and builds indices.DocumentStore._search_dense(query, top_k): Runs FAISS similarity search and converts L2 distance to [0, 1] similarity.DocumentStore._search_sparse(query, top_k): Runs BM25 tokenized keyword search.DocumentStore.search(query, top_k, mode): Routes search to one of 7 modes and records latency telemetry.extract_text(path): Extracts raw text from PDF usingpypdf.PdfReaderor UTF-8 text files.chunk_text(text, source): Splits text withRecursiveCharacterTextSplitter(800, 120).
Research math module handling distribution transforms, Shannon entropy, QPP baselines, and bootstrap significance testing.
calibrate_raw(scores): Identity baseline.calibrate_minmax(scores): Scales scores to [0, 1] per query.calibrate_zscore(scores): Standardizes scores to mean=0, std=1.calibrate_cdf(scores, corpus_cdf): Maps scores to corpus percentile ranks usingnp.searchsorted.compute_entropy(scores): Computes Shannon entropy H = -ฮฃ p log2 p with softmax handling for negative z-scores.compute_alpha(h_dense, h_sparse): Calculates dynamic precision weight ฮฑ = H_dense / (H_dense + H_sparse + ฮต).build_corpus_cdfs(...): Scores sample queries against ALL corpus docs to create offline CDF arrays.clarity_score(top_k_texts, corpus_freqs): Computes KL divergence of top-k language model vs corpus language model.nqc(scores, corpus_mean): Normalized Query Commitment std(top_k) / |mean(corpus)|.bootstrap_ci(a, b, n_resamples=1000): Performs paired bootstrap resampling for 95% confidence intervals and p-value significance.
Implements reciprocal rank fusion, fixed linear fusion, and calibrated entropy-weighted fusion.
rrf_fuse(sparse, dense, k=60): Combines candidate ranks via RRF(d) = ฮฃ 1 / (60 + r(d)).linear_fuse(sparse, dense, alpha=0.5): Merges candidates with fixed ฮฑ=0.5 linear combination.entropy_fuse(sparse, dense, calibration="cdf"): Calibrates scores, computes Shannon entropy per retriever, calculates dynamic ฮฑ, and merges candidates.
Manages BM25Okapi index and full-corpus scoring.
BM25Index.tokenize(text): Lowercases, strips punctuation, and splits text into tokens.BM25Index.add_documents(docs): Tokenizes documents and buildsBM25Okapimodel.BM25Index.score_all(query): Returns BM25 scores across all corpus documents (used for offline CDF building).
Lazy-loads cross-encoder/ms-marco-MiniLM-L6-v2 for pairwise (query, document) scoring.
CrossEncoderReranker.rerank(query, candidates, top_k): Runs pairwise cross-attention prediction and sorts candidates descending by score.
Loads BEIR SciFact benchmark corpus (5,183 PubMed abstracts), test claims (300 queries), and qrels relevancy labels.
load_scifact_corpus(): Parsescorpus.jsonlinto document records.load_scifact_queries(): Parsesqueries.jsonlmapping query IDs to claim text.load_scifact_qrels(): Loads ground-truth relevance pairs fromqrels/test.tsv.
Offline script executing indexing step, generating FAISS vectors, BM25 indices, unigram language models, document lookup tables, and corpus-level CDF numpy files.
Evaluates 7 retrieval modes across 300 test claims, computes Pearson correlations for H1, runs 1,000 paired bootstrap resamples for H2, and deduplicates chunk results by document ID.
BEIR SciFact Benchmark Results & Research Hypotheses
Evaluating 7 retrieval modes across 300 test claims (5,183 PubMed abstracts).
| Mode | NDCG@10 | MRR | P@3 | P@5 | R@5 | p95 Latency |
|---|---|---|---|---|---|---|
dense |
0.6715 | 0.6329 | 0.2466 | 0.1647 | 0.7495 | 33 ms |
sparse |
0.6151 | 0.5804 | 0.2233 | 0.1520 | 0.7089 | 130 ms |
rrf |
0.7028 | 0.6713 | 0.2555 | 0.1680 | 0.7744 | 249 ms |
hybrid_fixed |
0.6829 | 0.6527 | 0.2522 | 0.1647 | 0.7594 | 232 ms |
hybrid_calibrated |
0.6981 | 0.6672 | 0.2489 | 0.1660 | 0.7661 | 241 ms |
hybrid_fixed_rerank |
0.7006 | 0.6653 | 0.2578 | 0.1700 | 0.7714 | 2432 ms |
| hybrid_calibrated_rerank | 0.7071 | 0.6719 | 0.2622 | 0.1720 | 0.7838 | 2116 ms |
๐ฌ H1: Entropy Correlation Analysis
Hypothesis: CDF entropy has the strongest negative correlation with retrieval quality.
โ Verdict: Not Supported.
Z-score entropy turned out to be the strongest negative predictor (r = -0.4065, p < 10-6) for dense retrieval on SciFact, whereas CDF entropy showed a weaker correlation (r = -0.1151).
๐ H2: Paired Bootstrap Significance
Hypothesis: Calibrated entropy fusion significantly outperforms fixed-alpha and RRF baselines.
โ ๏ธ Verdict: Partially Supported.
CDF entropy fusion significantly beats fixed-alpha fusion (+0.0152 NDCG@10 gain, p = 0.012), but ties with RRF. With cross-encoder reranking, the full pipeline achieves the best overall NDCG@10 (0.7071).
How to Run & Deploy
Commands to build indices, run FastAPI, execute pytest, and evaluate performance.
1. Local Setup & Installation
# Create virtual environment
python -m venv venv
# Activate venv (Windows PowerShell)
.\venv\Scripts\Activate.ps1
# Install requirements
pip install -r requirements.txt
2. Build Retrieval Artifacts & Index SciFact
# Builds FAISS, BM25, Corpus CDFs, and Document Lookup tables
python scripts/build_index.py --dataset scifact
3. Start the FastAPI Server & Interactive Swagger Docs
# Launch server at http://127.0.0.1:8000
uvicorn app.main:app --reload
# Open Swagger Docs in your browser: http://127.0.0.1:8000/docs
4. Run Pytest Test Suite
# Executes all 9 test cases covering API endpoints, telemetry, and calibration
pytest tests/ -v
5. Run Benchmark Evaluation & Significance Tests
# Evaluates all 7 modes on SciFact test claims & runs bootstrap tests
python scripts/evaluate.py