- Зачем:
- README и путеводитель обращаются к читателю на «вы», а ТЗ в docs/labs/
были на «ты»; после пересборки индекса смесь стала заметна.
- Что:
- во всех восьми файлах docs/labs/ местоимения, глаголы и повелительное
наклонение переведены во второе лицо множественного числа.
- названия ступеней в таблице README оставлены как в спеке.
- Проверка:
- grep по формам «ты/твой», 'ё' и 'менти' по docs/labs/ молчит;
git diff --check чистый; ревью диффа свежей сессией.
9.2 KiB
Задание 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.