fix BM25 score normalization using max-normalization approach
problem: min-max normalization crushed BM25 scores to near-zero when:
- single result returned: (score - min) / (max - min) = 0 / 0.001 = 0
- similar scores: small range compressed relative differences
solution: BM25-max-scaled normalization (divide by max score)
- ensures top result always gets 1.0
- preserves relative spacing between results
- handles edge cases (single result, clustered scores)
references:
- https://opensourceconnections.com/blog/2023/02/27/hybrid-vigor-winning-at-hybrid-search/
- used in TREC 2021 winning hybrid search submission
tested:
- query=redis, alpha=0.0 → score=1.0 ✓ (was 0.0)
- query=bufo, alpha=0.0 → [1.0, 0.928, 0.812] ✓ (proportional)
- query=happy, alpha=0.5 → exact matches rise in rankings ✓
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>