fix(db): split seed_info CTE so similar-artist works without seed genre
The combined seed_info CTE filtered the seed out when its genre was NULL/empty. Restored the spec's two-CTE design (seed_artist + seed_tags) so similar-artist matching works regardless of the seed's genre coverage. Drops the genre workaround from the SimilarArtist test.
This commit is contained in:
@@ -100,9 +100,13 @@ func (q *Queries) LoadRadioCandidates(ctx context.Context, arg LoadRadioCandidat
|
||||
const loadRadioCandidatesV2 = `-- name: LoadRadioCandidatesV2 :many
|
||||
|
||||
WITH
|
||||
seed_info AS (
|
||||
SELECT t.artist_id,
|
||||
trim(g)::text AS tag
|
||||
seed_artist AS (
|
||||
SELECT artist_id
|
||||
FROM tracks
|
||||
WHERE tracks.id = $2
|
||||
),
|
||||
seed_tags AS (
|
||||
SELECT trim(g) AS tag
|
||||
FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g(tag) ON true
|
||||
WHERE t.id = $2 AND trim(g) <> ''
|
||||
@@ -127,7 +131,7 @@ similar_artists AS (
|
||||
SELECT t.id AS track_id, asim.score * 0.5 AS sim_score
|
||||
FROM artist_similarity asim
|
||||
JOIN tracks t ON t.artist_id = asim.artist_b_id
|
||||
JOIN (SELECT DISTINCT artist_id FROM seed_info) sa ON asim.artist_a_id = sa.artist_id
|
||||
JOIN seed_artist sa ON asim.artist_a_id = sa.artist_id
|
||||
WHERE asim.source = 'listenbrainz'
|
||||
AND t.id NOT IN (SELECT id FROM excluded_ids)
|
||||
ORDER BY asim.score DESC, random()
|
||||
@@ -136,10 +140,10 @@ similar_artists AS (
|
||||
tag_overlap AS (
|
||||
SELECT t.id AS track_id,
|
||||
(count(DISTINCT trim(g))::float8
|
||||
/ GREATEST((SELECT count(DISTINCT tag) FROM seed_info), 1)) AS sim_score
|
||||
/ GREATEST((SELECT count(*) FROM seed_tags), 1)) AS sim_score
|
||||
FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g_split(g) ON true
|
||||
WHERE trim(g_split.g) IN (SELECT tag FROM seed_info)
|
||||
WHERE trim(g_split.g) IN (SELECT tag FROM seed_tags)
|
||||
AND t.id NOT IN (SELECT id FROM excluded_ids)
|
||||
AND t.id <> $2
|
||||
GROUP BY t.id
|
||||
@@ -156,7 +160,7 @@ likes_overlap AS (
|
||||
SELECT 1 FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g_overlap(g) ON true
|
||||
WHERE t.id = gl.track_id
|
||||
AND trim(g_overlap.g) IN (SELECT tag FROM seed_info)
|
||||
AND trim(g_overlap.g) IN (SELECT tag FROM seed_tags)
|
||||
)
|
||||
ORDER BY random()
|
||||
LIMIT $8
|
||||
|
||||
@@ -36,9 +36,13 @@ WHERE t.id <> $2
|
||||
-- Returns same shape as LoadRadioCandidates plus similarity_score column.
|
||||
|
||||
WITH
|
||||
seed_info AS (
|
||||
SELECT t.artist_id,
|
||||
trim(g)::text AS tag
|
||||
seed_artist AS (
|
||||
SELECT artist_id
|
||||
FROM tracks
|
||||
WHERE tracks.id = $2
|
||||
),
|
||||
seed_tags AS (
|
||||
SELECT trim(g) AS tag
|
||||
FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g(tag) ON true
|
||||
WHERE t.id = $2 AND trim(g) <> ''
|
||||
@@ -63,7 +67,7 @@ similar_artists AS (
|
||||
SELECT t.id AS track_id, asim.score * 0.5 AS sim_score
|
||||
FROM artist_similarity asim
|
||||
JOIN tracks t ON t.artist_id = asim.artist_b_id
|
||||
JOIN (SELECT DISTINCT artist_id FROM seed_info) sa ON asim.artist_a_id = sa.artist_id
|
||||
JOIN seed_artist sa ON asim.artist_a_id = sa.artist_id
|
||||
WHERE asim.source = 'listenbrainz'
|
||||
AND t.id NOT IN (SELECT id FROM excluded_ids)
|
||||
ORDER BY asim.score DESC, random()
|
||||
@@ -72,10 +76,10 @@ similar_artists AS (
|
||||
tag_overlap AS (
|
||||
SELECT t.id AS track_id,
|
||||
(count(DISTINCT trim(g))::float8
|
||||
/ GREATEST((SELECT count(DISTINCT tag) FROM seed_info), 1)) AS sim_score
|
||||
/ GREATEST((SELECT count(*) FROM seed_tags), 1)) AS sim_score
|
||||
FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g_split(g) ON true
|
||||
WHERE trim(g_split.g) IN (SELECT tag FROM seed_info)
|
||||
WHERE trim(g_split.g) IN (SELECT tag FROM seed_tags)
|
||||
AND t.id NOT IN (SELECT id FROM excluded_ids)
|
||||
AND t.id <> $2
|
||||
GROUP BY t.id
|
||||
@@ -92,7 +96,7 @@ likes_overlap AS (
|
||||
SELECT 1 FROM tracks t
|
||||
LEFT JOIN LATERAL regexp_split_to_table(coalesce(t.genre, ''), '[;,]') AS g_overlap(g) ON true
|
||||
WHERE t.id = gl.track_id
|
||||
AND trim(g_overlap.g) IN (SELECT tag FROM seed_info)
|
||||
AND trim(g_overlap.g) IN (SELECT tag FROM seed_tags)
|
||||
)
|
||||
ORDER BY random()
|
||||
LIMIT $8
|
||||
|
||||
@@ -73,11 +73,6 @@ func TestLoadCandidatesFromSimilarity_LBSimilarSourceContributes(t *testing.T) {
|
||||
func TestLoadCandidatesFromSimilarity_SimilarArtistTracksContribute(t *testing.T) {
|
||||
f := newFixture(t, 1) // creates 1 artist + 1 album + 1 track (the seed)
|
||||
seed := f.tracks[0]
|
||||
// seed_info CTE only emits artist_id rows when genre is non-NULL (it
|
||||
// uses a LATERAL regexp_split_to_table join filtered by trim(g) <> '').
|
||||
// Give the seed a genre so that seed_info is populated and the
|
||||
// similar_artists JOIN can find artist_a_id = seed.ArtistID.
|
||||
helperSetTrackGenre(t, f, seed.ID, "Rock")
|
||||
// Add a SECOND artist + track in that artist; relate the two artists via artist_similarity.
|
||||
otherArtist, _ := f.q.UpsertArtist(context.Background(), dbq.UpsertArtistParams{Name: "OtherArtist", SortName: "OtherArtist"})
|
||||
otherAlbum, _ := f.q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{Title: "OtherAlbum", SortTitle: "OtherAlbum", ArtistID: otherArtist.ID})
|
||||
|
||||
Reference in New Issue
Block a user