- Зачем:
- в docs/labs/ будет много заданий; номер ступени и номер задания в имени
делают папку оглавлением программы и избавляют от поиска по README (#230).
- Что:
- шесть ТЗ переименованы через git mv: 1-1…1-5 для ступени 1,
2-1-superset-chart.md для ступени 2; факультатив superset-dashboard.md
остался без номера.
- обновлены ссылки в docs/labs/README.md, 2-1-superset-chart.md,
docs/architecture/dds/session.md и пути в dags/homework_check.py.
- правило имен для docs/labs/ в AGENTS.md переписано под S-N-slug.
- Проверка:
- make lint; скрипт обхода относительных ссылок в docs/ и AGENTS.md —
битых нет.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
111 lines
7.3 KiB
Markdown
111 lines
7.3 KiB
Markdown
# Задание 2: `dm.top_pages_daily`
|
||
|
||
**Чему учит:** создавать витрину с новым зерном: пять объектов, донор и
|
||
замена дневных партиций. Включать ее пересборку в `dm_transform`.
|
||
|
||
## Сначала прочитать
|
||
|
||
- [«Хранилище и его слои»](../handbook/storage-layers.md);
|
||
- [«Потоки Airflow и даги модельного времени»](../handbook/airflow-dags.md).
|
||
|
||
## Роль витрины
|
||
|
||
По дневным показателям страниц аналитик сравнивает просмотры, посетителей и
|
||
действия с товарами. Добавление в корзину происходит на карточке товара,
|
||
покупка — на странице подтверждения заказа. Отношение добавлений к
|
||
просмотрам карточки показывает ее конверсию.
|
||
|
||
Для воронки «просмотр → корзина → покупка» этих данных недостаточно:
|
||
действия происходят на разных страницах, а связи между ними в агрегате нет.
|
||
Путь человека исследуют по событиям или сессиям.
|
||
|
||
## Что сделать
|
||
|
||
Источник — `dds.event_v`. Зерно витрины — **день события × страница**.
|
||
Читайте DDS напрямую: так выполнение задания не зависит от витрины
|
||
задания 1.
|
||
|
||
На стенде витрину с новым зерном хранят как готовый агрегат, чтобы не
|
||
рассчитывать ее заново для каждого запроса. Причины описаны в разделе
|
||
[«Как принято на ступени 1»](README.md#как-принято-на-ступени-1). Создайте
|
||
пять объектов:
|
||
`dm.top_pages_daily_rep` / `_dist`, донор `_stage_rep` / `_stage_dist` и
|
||
публичное представление `dm.top_pages_daily_v`. Ключ партиции — день, он же
|
||
единица пересборки.
|
||
|
||
### Состав колонок
|
||
|
||
| Колонка | Тип | Значение |
|
||
|---|---|---|
|
||
| `report_date` | `Date` | День события |
|
||
| `page_path` | `LowCardinality(String)` | Путь страницы |
|
||
| `pageviews` | `UInt64` | Число событий `pageview` на странице |
|
||
| `visitors` | `UInt64` | Число разных `client_id` на странице |
|
||
| `cart_adds` | `UInt64` | Число событий `add_to_cart` на странице |
|
||
| `purchases` | `UInt64` | Число событий `purchase` на странице |
|
||
| `_load_id` | `String` | Идентификатор запуска, собравшего день |
|
||
| `_load_ts` | `DateTime64(3, 'UTC')` | Время сборки |
|
||
|
||
Вычислите `page_path` из `url`, убрав домен и параметры запроса. Полный
|
||
адрес разделил бы показатели одной страницы на сотни строк. Учитывайте все
|
||
три типа событий, а их счетчики вычисляйте через `countIf`.
|
||
|
||
### Ритм пересборки
|
||
|
||
События прожитого дня больше не меняются. Определяйте объем прогона по
|
||
состоянию витрины: от первого несобранного прожитого дня до последнего
|
||
прожитого. Отсчет от последнего собранного дня оставит пропуски после
|
||
частичного сбоя.
|
||
|
||
Как у `revenue_daily`, заполните донор за весь диапазон одной вставкой,
|
||
затем замените дневные партиции по одной.
|
||
|
||
### Ключ шардирования
|
||
|
||
Выберите ключ самостоятельно. У `revenue_daily` кроме дня одно измерение с
|
||
шестью близкими по объему значениями. Здесь страниц много, и число событий
|
||
на них сильно различается.
|
||
|
||
У цели и донора используйте одинаковый ключ: иначе при замене партиции
|
||
строка потеряется на одном шарде и удвоится на другом. О том, [как устроен
|
||
донор](../architecture/storage.md), читайте в разделе «Раскладка по шардам».
|
||
|
||
## Типичная ошибка
|
||
|
||
Из-за имени витрины хочется отобрать только просмотры. Но фильтр источника
|
||
по `event_type = 'pageview'` обнулит `cart_adds` и `purchases`, а запрос не
|
||
завершится ошибкой. Конверсия карточек станет нулевой. Проверка одной суммы
|
||
`pageviews` не обнаружит этот фильтр: все просмотры остались на месте.
|
||
Ошибку покажет сверка `purchases` или `cart_adds` с источником, если за день
|
||
были покупки или добавления в корзину.
|
||
|
||
Выбирайте проверку под возможную ошибку. Этот подход описан в
|
||
[справочнике проверок](../architecture/testing.md).
|
||
|
||
## Как проверить себя
|
||
|
||
Деловой ключ — `page_path` внутри дня. Получите прямой агрегат из
|
||
`dds.event_v` за день и соедините его с `dm.top_pages_daily_v` полным
|
||
внешним соединением по ключу. Посчитайте строки, где ключ отсутствует с
|
||
одной из сторон или различается любой из четырех счетчиков. Расхождений
|
||
должно быть ноль.
|
||
|
||
Перед полным сравнением проверьте дневные суммы:
|
||
|
||
- сумма `pageviews` равна числу событий `pageview` в `dds.event_v`;
|
||
- сумма `purchases` равна числу событий `purchase` в том же источнике.
|
||
|
||
Сумма `visitors` по страницам повторно учитывает посетителя, открывшего
|
||
несколько страниц. Число посетителей за день берите из `dm.daily_traffic_v`.
|
||
|
||
## Приемка
|
||
|
||
- [ ] созданы пять объектов, донор объявлен через `AS` и шардируется ключом
|
||
цели;
|
||
- [ ] в `dm.top_pages_daily_v` явно перечислены колонки, включая `_load_id`
|
||
и `_load_ts`;
|
||
- [ ] объем прогона определяется по состоянию витрины без ручного задания;
|
||
- [ ] задача `top_pages_daily` в `homework_check` завершилась успешно;
|
||
- [ ] задача витрины добавлена в `dm_transform`, повторный прогон конвейера
|
||
не меняет результат.
|