feat(recommendations): collect demographics and advance age cohorts
ci / ts / ts (packages + web) (push) Successful in 3m19s
ci / db / db (push) Successful in 53s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 51s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m3s
ci / recommender / recommender (push) Failing after 16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m15s
ci / ts / ts (packages + web) (push) Successful in 3m19s
ci / db / db (push) Successful in 53s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 51s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m3s
ci / recommender / recommender (push) Failing after 16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m15s
This commit is contained in:
1 parent
e158558da3
commit
fff91c446b
24 files changed
+778
-324
No files matched your search
@@ -373,7 +373,18 @@ func (h *Handler) record(ctx context.Context, s session, picks []Pick, modelVer
|
||||
// без дизлайков, недавно игравших и уже выданных; один трек исполнителя на пачку.
|
||||
func (h *Handler) fallback(ctx context.Context, s session, served []string) ([]Pick, error) {
|
||||
rows, err := h.pool.Query(ctx, `
|
||||
WITH liked AS (
|
||||
WITH own AS (
|
||||
SELECT onboarding FROM user_profiles_rec WHERE user_id = $1
|
||||
), cohort AS (
|
||||
SELECT r.track_id FROM track_reactions r
|
||||
JOIN user_profiles_rec p ON p.user_id = r.user_id
|
||||
JOIN users u ON u.id = p.user_id, own
|
||||
WHERE r.reaction = 'like' AND p.user_id <> $1 AND NOT u.is_blocked
|
||||
AND (own.onboarding->>'gender' IS NOT NULL OR rec_age_group(own.onboarding) IS NOT NULL)
|
||||
AND (own.onboarding->>'gender' IS NULL OR p.onboarding->>'gender' = own.onboarding->>'gender')
|
||||
AND (rec_age_group(own.onboarding) IS NULL OR rec_age_group(p.onboarding) = rec_age_group(own.onboarding))
|
||||
GROUP BY r.track_id HAVING count(DISTINCT r.user_id) >= 2
|
||||
), liked AS (
|
||||
SELECT track_id FROM track_reactions WHERE user_id = $1 AND reaction = 'like'
|
||||
), fav_artists AS (
|
||||
SELECT DISTINCT ta.artist_id FROM track_artists ta JOIN liked l ON l.track_id = ta.track_id
|
||||
@@ -384,7 +395,12 @@ func (h *Handler) fallback(ctx context.Context, s session, served []string) ([]P
|
||||
CASE WHEN t.id IN (SELECT track_id FROM liked) THEN 'liked'
|
||||
WHEN EXISTS (SELECT 1 FROM track_artists ta WHERE ta.track_id = t.id
|
||||
AND ta.artist_id IN (SELECT artist_id FROM fav_artists)) THEN 'artist'
|
||||
ELSE 'random' END AS source
|
||||
WHEN EXISTS (SELECT 1 FROM own, track_artists ta
|
||||
WHERE ta.track_id = t.id AND own.onboarding->'artist_ids' ? ta.artist_id::text) THEN 'onboarding'
|
||||
WHEN EXISTS (SELECT 1 FROM own, track_genres tg JOIN genres g ON g.id = tg.genre_id
|
||||
WHERE tg.track_id = t.id AND own.onboarding->'genres' ? g.name) THEN 'onboarding'
|
||||
WHEN t.id IN (SELECT track_id FROM cohort) THEN 'cohort'
|
||||
ELSE 'random' END AS source
|
||||
FROM tracks t
|
||||
JOIN albums al ON al.id = t.album_id
|
||||
JOIN media_files f ON f.id = t.primary_file_id AND f.missing_since IS NULL
|
||||
@@ -395,7 +411,7 @@ func (h *Handler) fallback(ctx context.Context, s session, served []string) ([]P
|
||||
AND e.type = 'play_start' AND e.occurred_at > now() - interval '3 hours')
|
||||
)
|
||||
SELECT DISTINCT ON (artist_id) id::text, source FROM (
|
||||
SELECT * FROM pool ORDER BY CASE source WHEN 'liked' THEN 0 WHEN 'artist' THEN 1 ELSE 2 END, random() LIMIT 200
|
||||
SELECT * FROM pool ORDER BY CASE source WHEN 'liked' THEN 0 WHEN 'artist' THEN 1 WHEN 'onboarding' THEN 2 WHEN 'cohort' THEN 3 ELSE 4 END, random() LIMIT 200
|
||||
) c
|
||||
ORDER BY artist_id, random()
|
||||
LIMIT 50`, s.UserID, served)
|
||||
@@ -410,7 +426,7 @@ func (h *Handler) fallback(ctx context.Context, s session, served []string) ([]P
|
||||
return nil, fmt.Errorf("wave: fallback: %w", err)
|
||||
}
|
||||
// DISTINCT ON упорядочил по исполнителю — перемешиваем, предпочитая лайки и любимых исполнителей.
|
||||
rank := map[string]int{"liked": 0, "artist": 1, "random": 2}
|
||||
rank := map[string]int{"liked": 0, "artist": 1, "onboarding": 2, "cohort": 3, "random": 4}
|
||||
shuffled := shuffle(picks)
|
||||
stableSort(shuffled, func(a, b Pick) bool { return rank[a.Source] < rank[b.Source] })
|
||||
// Половина пачки — любимое, половина — случайное: запасная волна не должна быть одними лайками.
|
||||
|
||||
Reference in new issue
Block a user