Собесов

Учи.ру: разбиение событий на сессии с порогом 30 минут

SQLSessionizationСредняяMiddle

Условие

Дана таблица events(user_id, event, timest). Нужно добавить колонку session_id: если между двумя действиями пользователя проходит более 30 минут, они принадлежат разным сессиям. Иначе — одной.

Решение

Подход — gaps and islands

  1. Для каждой строки сравниваем timest с предыдущим timest того же пользователя (LAG).
  2. Если разница > 30 мин — это start новой сессии (флаг 1).
  3. Накопительная сумма флагов = session_id.

SQL

WITH lagged AS (
  SELECT
    user_id, event, timest,
    LAG(timest) OVER (PARTITION BY user_id ORDER BY timest) AS prev_t
  FROM events
),
breaks AS (
  SELECT
    user_id, event, timest,
    CASE
      WHEN prev_t IS NULL THEN 1
      WHEN EXTRACT(EPOCH FROM (timest - prev_t)) > 1800 THEN 1
      ELSE 0
    END AS is_new_session
  FROM lagged
),
sessions AS (
  SELECT
    user_id, event, timest,
    SUM(is_new_session) OVER (
      PARTITION BY user_id ORDER BY timest
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS session_seq
  FROM breaks
)
SELECT
  user_id, event, timest,
  user_id || '_' || session_seq AS session_id
FROM sessions
ORDER BY user_id, timest;

Альтернатива (Hive/SparkSQL)

Без EXTRACT(EPOCH ...) можно использовать unix_timestamp(timest) - unix_timestamp(prev_t) > 1800.

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

  1. 30 минут включительно или строго: обычно «более 30 мин» = > 1800 сек. В формулировке ≥ 30 мин могут хотеть >=.
  2. session_id уникален в пределах юзера — добавил user_id || '_' || для глобальной уникальности.
  3. Если у пользователя только одно событие — у него тоже сессия (is_new_session = 1).
  4. LAG без partition даст «глобальное прошлое», что неверно — обязательно PARTITION BY user_id.
  5. Производительность: индекс по (user_id, timest) обязателен.

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

Cum sum по флагу «разрыв > 30 мин» (gaps and islands): LAG-разница + SUM() OVER = порядковый номер сессии в пределах пользователя.

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

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

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