Собесов

CloudReports: SQL-рекомендации фильмов через коллаборативную фильтрацию

SQLСложные запросыСложнаяJunior

Условие

Дана таблица likes(user_id, movie_id) — история просмотров фильмов в онлайн-кинотеатре. Тысячи пользователей и фильмов. Напишите SQL, реализующий простую логику рекомендаций: «фильмы, которые вы ещё не смотрели, но смотрели похожие пользователи».

На выходе: пользователь, рекомендованный фильм, рейтинг рекомендации.

Решение

Подход

Простая item-based коллаборативная фильтрация: считаем «похожих» пользователей через долю общих фильмов (≥ 10%). Затем для каждого пользователя берём фильмы, просмотренные похожими, считаем сколько раз каждый фильм встретился у похожих и фильтруем те, что уже смотрел сам пользователь.

Реализация

WITH cross_pairs AS (
  -- Все пары пользователей и совпадения по фильму
  SELECT
    a.user_id  AS u1,
    b.user_id  AS u2,
    (a.movie_id = b.movie_id) AS common
  FROM likes a
  JOIN likes b ON a.user_id <> b.user_id
),
similar_users AS (
  SELECT u1, u2
  FROM cross_pairs
  GROUP BY u1, u2
  HAVING COUNT(*) FILTER (WHERE common)::float / COUNT(*) >= 0.1
),
candidate_movies AS (
  SELECT
    s.u1                            AS user_id,
    l.movie_id,
    COUNT(*)                        AS rating
  FROM similar_users s
  JOIN likes l ON l.user_id = s.u2
  GROUP BY s.u1, l.movie_id
)
SELECT c.user_id        AS "Пользователь",
       c.movie_id       AS "Рекомендованный фильм",
       c.rating         AS "Рейтинг рекомендации"
FROM candidate_movies c
LEFT JOIN likes seen
  ON seen.user_id = c.user_id AND seen.movie_id = c.movie_id
WHERE seen.movie_id IS NULL          -- фильм ещё не смотрели
ORDER BY c.user_id, c.rating DESC;

Подводные камни

  1. Сложность кросс-джойна — O(n²·k). На реальных данных нужно ограничить хотя бы количеством общих фильмов (COUNT(common) >= 5) или использовать WHERE a.movie_id = b.movie_id для построения только реально пересекающихся пар.
  2. Доля 10% — гиперпараметр. Малое число общих фильмов даёт ложные «совпадения» (user смотрел только 1 фильм, и тот же смотрел другой — 100% похожих).
  3. Фильмы, которые посмотрели все соседи, могут быть просто популярны, а не релевантны — лучше делить на популярность фильма (TF-IDF логика).
  4. Холодный старт: для нового пользователя без истории рекомендаций не будет.

Эталонный ответ

1) Найти похожих пользователей через долю общих фильмов; 2) собрать фильмы похожих и посчитать частоту; 3) исключить уже просмотренные.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти