Problem
On switch_to_typesense, the string /search ranks differently from old ES — canonical high-pagerank parts get buried. Example: query rbs returns obscure parts literally named "RBS" on top, while BBa_B0034 (highest pagerank, the canonical RBS, ES's #1) lands at rank ~49.
Root cause
[flask/search.py:17]: TEXT_SORT_BY = '_text_match(buckets: 10):desc,pagerank:desc'. With 10 buckets, exact-name matches occupy the top text bucket and pagerank only breaks ties within a bucket, so it barely influences order. Old ES used a multiplicative model (BM25 × log(pagerank+1)) where pagerank had global influence.
Verified: buckets:1 brings BBa_B0034 to #1 (matches ES) but discards text relevance entirely — too blunt for all queries.
Proposed fix (decide via Issue 2 harness)
Option B (preferred): apply the multiplicative re-rank the SPARQL path already uses ([search.py:361-392], pagerank × percent_match) to the /search string endpoint too, instead of relying on Typesense sort_by bucketing.
Option A (quick): lower buckets — but tune the value against the Phase 0 metrics, not by eyeballing one query.
Acceptance
rbs → BBa_B0034 and GFP → BBa_E0040 at rank 1, without regressing NDCG across the Phase 0 query set.
Depends on
Issue 2 (need the harness to pick the config safely).
Problem
On switch_to_typesense, the string /search ranks differently from old ES — canonical high-pagerank parts get buried. Example: query rbs returns obscure parts literally named "RBS" on top, while BBa_B0034 (highest pagerank, the canonical RBS, ES's #1) lands at rank ~49.
Root cause
[flask/search.py:17]: TEXT_SORT_BY = '_text_match(buckets: 10):desc,pagerank:desc'. With 10 buckets, exact-name matches occupy the top text bucket and pagerank only breaks ties within a bucket, so it barely influences order. Old ES used a multiplicative model (BM25 × log(pagerank+1)) where pagerank had global influence.
Verified: buckets:1 brings BBa_B0034 to #1 (matches ES) but discards text relevance entirely — too blunt for all queries.
Proposed fix (decide via Issue 2 harness)
Option B (preferred): apply the multiplicative re-rank the SPARQL path already uses ([search.py:361-392], pagerank × percent_match) to the /search string endpoint too, instead of relying on Typesense sort_by bucketing.
Option A (quick): lower buckets — but tune the value against the Phase 0 metrics, not by eyeballing one query.
Acceptance
rbs → BBa_B0034 and GFP → BBa_E0040 at rank 1, without regressing NDCG across the Phase 0 query set.
Depends on
Issue 2 (need the harness to pick the config safely).