Files
clickstream-data-platform/docs/labs/session-overview.md
T
ddadmin cffe1aeb73 docs(labs): обращение «вы» во всех учебных заданиях
- Зачем:
  - README и путеводитель обращаются к читателю на «вы», а ТЗ в docs/labs/
    были на «ты»; после пересборки индекса смесь стала заметна.
- Что:
  - во всех восьми файлах docs/labs/ местоимения, глаголы и повелительное
    наклонение переведены во второе лицо множественного числа.
  - названия ступеней в таблице README оставлены как в спеке.
- Проверка:
  - grep по формам «ты/твой», 'ё' и 'менти' по docs/labs/ молчит;
    git diff --check чистый; ревью диффа свежей сессией.
2026-09-03 17:29:13 -04:00

9.2 KiB
Raw Blame History

Задание 3: dm.session_overview

Чему учит: агрегат хранит слагаемые, а не готовые средние и доли. Среднее по строкам витрины не складывается никогда, а уникальных нельзя складывать даже тогда, когда на сегодняшних данных сумма сходится.

Роль витрины

Дневной портрет визитов в разрезе устройств: сколько было сессий, какие они были длинные, сколько страниц смотрели и как часто доходили до покупки. Вопрос витрины — «как люди ходят по магазину с телефона и с настольного компьютера, и чем эти визиты отличаются».

Сессия на стенде — расчетная сущность, ее уже нарезал слой DDS. Собирать визиты заново из событий не нужно и нельзя: это была бы вторая нарезка, которая тихо разойдется с первой.

Витрина с таким именем была и на прошлом стенде, но зерно у нее сменилось, и сменилось не по вкусу. Там визитов как сущности не было, и витрина нарезала их сама, строкой на визит. Здесь визит — сущность слоя DDS, и витрина, повторяющая его зерно, оказалась бы обычным представлением по правилу формы: копией сессий с другими именами колонок. Чтобы задание осталось про дневной агрегат, витрина поднялась на зерно выше — до дня и среза.

Зерно и форма

Зерно — день сессии × категория устройства. Источник — dds.session_v, у него зерно визита, значит зерно сменилось и витрина материализуется: dm.session_overview_rep / _dist, донор _stage_rep / _stage_dist, публичное dm.session_overview_v. Ключ партиции — день.

Категория устройства взята из сессии как есть: у куки она постоянна, и слой DDS уже перевел код источника в слово. Словарь расшифровки шире, чем мир стенда: слов в нем четыре, а встречаются три — desktop, mobile и tablet. Строку под tv заводить незачем, она возникнет сама, если такие визиты появятся.

Состав колонок

Колонка Тип Что это
report_date Date день сессии
device_category LowCardinality(String) категория устройства
sessions UInt64 число визитов
visitors UInt64 число разных client_id
bounce_sessions UInt64 визиты ровно из одного события
purchase_sessions UInt64 визиты, в которых была хотя бы одна покупка
duration_seconds_total UInt64 суммарная длительность визитов
events_total UInt64 событий во всех визитах
pageviews UInt64 просмотров страниц
cart_adds UInt64 добавлений в корзину
purchases UInt64 покупок
_load_id String запуск, собравший день
_load_ts DateTime64(3, 'UTC') когда собран

Средней длительности и доли отказов в витрине нет намеренно. Хранить avg_duration_seconds было бы удобнее ровно один раз — пока смотрят одну строку. Тот, кто захочет среднее по дню целиком, сложит средние по трем устройствам и получит неправду: средние не складываются, они взвешиваются. Пара «duration_seconds_total и sessions» дает верный ответ на любом срезе, а деление стоит потребителю один вызов. То же и с долей отказов: храним bounce_sessions и sessions, долю считает тот, кто спрашивает.

С visitors история тоньше, и в ней главная ловушка задания. Складывать уникальных по строкам нельзя: один и тот же посетитель, попавший в две строки, будет посчитан дважды. Проверьте на стенде — и увидите, что сумма visitors по устройствам за день сходится с dm.daily_traffic_v.

Это не отменяет правила, а показывает, откуда берется совпадение: в мире стенда устройство приписано куке на всю жизнь (словарь понятий, «Паспорт куки»), поэтому одна кука лежит ровно в одной строке дня, и пересекаться строкам не в чем.

Совпадение это — свойство мира, а не свойство витрины. Появятся визиты одной куки с двух устройств — сумма поедет, и ни одна проверка об этом не скажет: отчет просто начнет тихо завышать аудиторию. Отсюда правило, которое стоит унести с задания: складывать уникальных нельзя даже там, где сегодня получается. Число посетителей дня спрашивают у dm.daily_traffic_v, где оно посчитано на своем зерне.

Ритм пересборки

Источник — сессии: день замерзает, как только прожит. Объем прогона тот же, что в задании 2, — хвост от первого несобранного прожитого дня; механика та же: донор и замена дневных партиций.

Ключ шардирования

Ваше решение по правилу донора, «Раскладка по шардам». Здесь у измерения всего три встречающихся значения, и распределены они неровно: планшеты — тонкая полоса, а телефоны и настольные машины держат основную массу. Прежде чем брать хеш от одного device_category, посчитайте, сколько строк ляжет на каждый шард, и назовите, чем вас устраивает результат.

Как проверить себя

Деловой ключ — device_category внутри дня. Соберите прямой агрегат из dds.session_v за день, соедините с dm.session_overview_v полным внешним соединением и посчитайте строки, где ключа нет с одной из сторон или где расходится любой счетчик. Ноль — зеленый.

Две проверки покрупнее ловят грубую ошибку сразу:

  • сумма sessions за день равна числу строк dds.session_v этого дня: ни один визит не потерян и ни один не задвоен;
  • сумма events_total за день равна сумме events_total по сессиям того же дня.

Если суммы событий сходятся, а сумма сессий больше числа визитов — почти наверняка витрина собрана из событий, а не из сессий.

Приемка

  • пять объектов витрины созданы, донор объявлен через AS и шардируется ключом цели;
  • dm.session_overview_v перечисляет колонки явно;
  • источник витрины — dds.session_v, своей нарезки визитов в ней нет;
  • средних и долей в физической таблице нет;
  • задача session_overview в homework_check зеленая;
  • задача витрины добавлена в dm_transform.