MB rerank: prefer_known_duration is now a score boost, not a tiebreaker
Live smoke against `/api/musicbrainz/search_tracks?track=Coffee+Break&artist=Zeds+Dead` exposed the edge case the tiebreaker implementation couldn't reach: The canonical Zeds Dead "Coffee Break" recording (mbid 6e2d4a70, length 184000ms) lives on the Coffee Break Single release — album_type='single', which carries a 0.85 album_type_weight in `score_track`. A sibling length-less recording (mbid 3b89bf3c) lives on an Album release — album_type='album', weight 1.0. After multiplying by EXACT_ARTIST_BOOST the canonical sat at 1.275 while the length-less sibling sat at 1.5. The previous tiebreaker only kicked in on equal scores, so the length-less album edition wins and the user sees 0:00 first instead of the actionable 3:04 row. Bug reproduced: ordering came out length-less / canonical / Omar-LinX-collab. Switched `prefer_known_duration` to a 1.25x score boost on recordings with non-zero duration_ms. The multiplier is sized above the album-vs-single weight spread (0.176) so length-known recordings can overcome an album-type penalty when scores would otherwise tie on title + artist match, but stays small enough that cover/karaoke penalty (0.05) and variant-tag penalty (0.85) still dominate — a length-known tribute still loses to a length-less canonical. Post-fix live response: 6e2d4a70 (canonical, 184000ms) sits first, 8ec2ce3f (Zeds Dead + Omar LinX collab, 153000ms) second, 3b89bf3c (length-less album edition) third. Verified Björk diacritic fallback path unaffected — `Bjork` + `Army of Me` still cascades strict-empty → bare and returns all 10 Björk recordings. 122 metadata tests pass — the three `prefer_known_duration` cases were designed to pin behaviour, not the specific multiplier value, so they all still pass under the boost implementation: ties promote length-known, relevance still beats length-pref, default-off behaviour unchanged.
This commit is contained in:
parent
8dbbf13c61
commit
6125ef8834
1 changed files with 26 additions and 12 deletions
|
|
@ -306,13 +306,20 @@ def rerank_tracks(
|
|||
popularity signal is still useful as a tiebreak).
|
||||
|
||||
``prefer_known_duration``: when True, recordings with non-zero
|
||||
``duration_ms`` are ranked ahead of duplicate-score recordings
|
||||
that lack length data. Used for MusicBrainz which often has
|
||||
several recordings per song (single edition, album edition,
|
||||
compilations, remasters) where some carry length and some don't.
|
||||
Sort key sits between score and the stable-order tiebreaker so
|
||||
relevance still wins — length is only a tiebreaker on equal
|
||||
scores, not a global re-shuffle.
|
||||
``duration_ms`` get a score boost. Used for MusicBrainz, which
|
||||
often has several recordings per song (single edition, album
|
||||
edition, compilations, remasters) where some carry length data
|
||||
and some don't. The boost is set above the album_type weight
|
||||
spread so length-known recordings can beat length-less
|
||||
siblings even when the sibling sits on a higher-weighted
|
||||
album-type — real case: Zeds Dead "Coffee Break" canonical
|
||||
recording lives on the Single release (album_type='single',
|
||||
weight 0.85) while a length-less sibling lives on an Album
|
||||
release (weight 1.0). Without the boost, the length-less album
|
||||
edition wins and the user sees 0:00 instead of 3:04. Cover /
|
||||
karaoke penalties dominate the boost (their penalty is 0.05)
|
||||
so a length-known tribute still loses to a length-less
|
||||
canonical match.
|
||||
|
||||
No-op when both ``expected_title`` and ``expected_artist`` are
|
||||
empty (no signal to rank against — return input order)."""
|
||||
|
|
@ -323,11 +330,18 @@ def rerank_tracks(
|
|||
for idx, t in enumerate(tracks)
|
||||
]
|
||||
if prefer_known_duration:
|
||||
# Sort key: score desc, has-length first (0 before 1), idx asc.
|
||||
scored.sort(key=lambda x: (-x[0], 0 if (x[2].duration_ms or 0) > 0 else 1, x[1]))
|
||||
else:
|
||||
# Sort by score desc; idx asc as tiebreaker preserves stable order.
|
||||
scored.sort(key=lambda x: (-x[0], x[1]))
|
||||
# Multiplier sized above the album-type weight spread (album 1.0
|
||||
# vs single 0.85 = ~18%) so length-known recordings can overcome
|
||||
# the album-vs-single penalty when scores would otherwise tie on
|
||||
# title + artist match. Penalty multipliers (cover/karaoke=0.05,
|
||||
# variant=0.85) still dominate, so this only flips order among
|
||||
# close-relevance siblings — exactly the MB-duplicate case.
|
||||
scored = [
|
||||
(score * 1.25 if (t.duration_ms or 0) > 0 else score, idx, t)
|
||||
for score, idx, t in scored
|
||||
]
|
||||
# Sort by score desc; idx asc as tiebreaker preserves stable order.
|
||||
scored.sort(key=lambda x: (-x[0], x[1]))
|
||||
return [t for _score, _idx, t in scored]
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue