From c0d7248276109d03c0a6e69b16e6063f5e0c0cf1 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 11 Jun 2026 09:27:10 +0000 Subject: [PATCH] docs(constructive-search): update skill docs for RRF scoring searchScore now uses Reciprocal Rank Fusion (RRF) instead of sigmoid weighted-average. Updated SKILL.md and search-composite.md reference to reflect the new rank-based fusion algorithm. --- .agents/skills/constructive-search/SKILL.md | 2 +- .../references/search-composite.md | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.agents/skills/constructive-search/SKILL.md b/.agents/skills/constructive-search/SKILL.md index 13e79db..d27cb8e 100644 --- a/.agents/skills/constructive-search/SKILL.md +++ b/.agents/skills/constructive-search/SKILL.md @@ -29,7 +29,7 @@ Use this skill when: | **Trigram** | Fuzzy / typo-tolerant matching | `pg_trgm` extension | Lower = better (distance) | | **pgvector** | Semantic / embedding similarity | `pgvector` HNSW | Lower = better (distance) | | **PostGIS** | Spatial / geographic search | `postgis` extension | Lower = better (distance) | -| **Unified** | Fan-out across all strategies | Composite `searchScore` | Normalized 0–1 | +| **Unified** | Fan-out across all strategies | Composite `searchScore` via RRF | Normalized 0–1 | ## Quick Start: Unified Search diff --git a/.agents/skills/constructive-search/references/search-composite.md b/.agents/skills/constructive-search/references/search-composite.md index d94e008..1fcc7c6 100644 --- a/.agents/skills/constructive-search/references/search-composite.md +++ b/.agents/skills/constructive-search/references/search-composite.md @@ -4,9 +4,20 @@ Combine multiple search algorithms in a single query using composite fields (`se --- -## searchScore — Composite Relevance +## searchScore — Composite Relevance (Reciprocal Rank Fusion) -A normalized 0..1 field that combines all active search signals into a single relevance number. Returns `null` when no search filters are active. +A normalized 0..1 field that fuses all active search signals via **Reciprocal Rank Fusion (RRF)**. Returns `null` when no search filters are active. + +RRF uses rank positions (not raw scores) to combine results from different algorithms fairly — solving the problem of BM25/pgvector producing unbounded scores that can't be meaningfully normalized: + +``` +searchScore = Σ(weight_i / (rrfK + rank_i)) / max_possible_rrf +``` + +- `rrfK` (default 60) — smoothing constant; lower values amplify rank-1 advantage +- `weight_i` — per-adapter weight from `@searchConfig` (default 1.0 each) +- `rank_i` — this document's position in adapter i's result list (1 = best) +- Score = 1.0 means ranked #1 by every active adapter ```typescript const result = await db.article.findMany({ @@ -39,7 +50,7 @@ A `String` filter field that fans the same text query to all **text-compatible** | Trigram | Yes | Text-based query | | pgvector | **No** | Requires vector array, not text | -When you filter with `unifiedSearch: "machine learning"`, all matching rows from ANY text algorithm are included. The `searchScore` then ranks them by a composite of whichever algorithms matched. +When you filter with `unifiedSearch: "machine learning"`, all matching rows from ANY text algorithm are included. The `searchScore` then ranks them via RRF — each adapter independently ranks its results, and RRF fuses those rank positions into a fair composite score regardless of each algorithm's raw score scale. ### Combining unifiedSearch with Per-Algorithm Filters