Unified search: rank within filtered set instead of pre-thresholding CLIP
When structured filters are present they're the constraint and CLIP only ranks within the candidate set, so drop the global similarity threshold for that case. Previously the 0.2 whole-library threshold ran BEFORE intersecting with the filters, discarding filter-matching photos that scored just under it (e.g. a 2022 beach photo at 0.18) — producing after_struct_filter=0 even when matches existed. Plain semantic (no filters) keeps the user's threshold. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+21
-7
@@ -364,13 +364,27 @@ pub async fn unified_search<TagD: TagDao>(
|
|||||||
// ── 4. Rank ──
|
// ── 4. Rank ──
|
||||||
match semantic {
|
match semantic {
|
||||||
Some(ref sem) => {
|
Some(ref sem) => {
|
||||||
// Semantic term present: CLIP-rank, then keep only hits that pass
|
// When structured filters are present they ARE the constraint —
|
||||||
// the structured filters (by content_hash).
|
// CLIP only ranks within the candidate set. So drop the global
|
||||||
let scored =
|
// similarity threshold (it's tuned for whole-library search and
|
||||||
match score_photos(&state, &exif_dao, sem, &library_ids, threshold, None).await {
|
// would pre-discard filter-matching photos that scored just under
|
||||||
Ok(s) => s,
|
// it — e.g. a 2022 beach photo at 0.18 — before the intersection
|
||||||
Err(e) => return score_error_response(e),
|
// ever runs). With no filters, keep the user's threshold for the
|
||||||
};
|
// plain semantic case.
|
||||||
|
let clip_threshold = if has_struct { -1.0 } else { threshold };
|
||||||
|
let scored = match score_photos(
|
||||||
|
&state,
|
||||||
|
&exif_dao,
|
||||||
|
sem,
|
||||||
|
&library_ids,
|
||||||
|
clip_threshold,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => return score_error_response(e),
|
||||||
|
};
|
||||||
let considered = scored.considered;
|
let considered = scored.considered;
|
||||||
let clip_hits = scored.hits.len();
|
let clip_hits = scored.hits.len();
|
||||||
let hits: Vec<(f32, String)> = if has_struct {
|
let hits: Vec<(f32, String)> = if has_struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user