Зачем: начинающим ученикам трудно читать главы без пояснений терминов и ожидаемого результата примеров. Что: уточнены заголовки и объяснения в пяти главах и вводной, добавлена сверка графика с SQL, обновлены ссылки из заданий и документации генератора. Проверка: SQL и команды сохранены, локальные ссылки проверены; git diff --check пройден. Ревью смысла Sol 6.1 high замечаний не выявило, новые пояснения дополнительно сверены с кодом и настройками.
117 lines
8.3 KiB
Markdown
117 lines
8.3 KiB
Markdown
# Задание 2: показатели страниц по дням, `dm.top_pages_daily`
|
||
|
||
В этой работе вы рассчитаете показатели страниц за каждый день и сохраните
|
||
их в таблице. Затем подключите обновление витрины к `dm_transform`:
|
||
новый расчет будет заменять дневные партиции таблицы.
|
||
|
||
## Подготовка
|
||
|
||
- [«Хранилище и его слои»](../handbook/storage-layers.md);
|
||
- [«Генерация и обработка данных в Airflow»](../handbook/airflow-dags.md).
|
||
|
||
## Дневные показатели страниц
|
||
|
||
По дневным показателям страниц аналитик сравнивает просмотры, посетителей и
|
||
действия с товарами. Добавление в корзину происходит на карточке товара,
|
||
покупка — на странице подтверждения заказа. Отношение добавлений к
|
||
просмотрам карточки показывает ее конверсию.
|
||
|
||
Для воронки «просмотр → корзина → покупка» этих данных недостаточно:
|
||
действия происходят на разных страницах, а связи между ними в агрегате нет.
|
||
Путь человека исследуют по событиям или сессиям.
|
||
|
||
## Создание витрины
|
||
|
||
Читайте события из `dds.event_v`. В результате нужна одна строка на страницу
|
||
за день. Например, все просмотры одной карточки товара за один день попадут
|
||
в одну строку. Витрина задания 1 для этого расчета не нужна.
|
||
|
||
Сохраните рассчитанные показатели в таблице, чтобы отчеты читали готовые
|
||
итоги. Создайте пять объектов:
|
||
|
||
- основные таблицы `dm.top_pages_daily_rep` и `dm.top_pages_daily_dist`;
|
||
- промежуточные таблицы `dm.top_pages_daily_stage_rep` и `dm.top_pages_daily_stage_dist`;
|
||
- представление для чтения `dm.top_pages_daily_v`.
|
||
|
||
Их назначение и порядок обновления разобраны во вводной:
|
||
[«Создание и обновление витрин»](README.md#создание-и-обновление-витрин).
|
||
Разбейте данные на партиции по дням, чтобы можно было заменить результат
|
||
одного дня целиком.
|
||
|
||
### Состав колонок
|
||
|
||
| Колонка | Тип | Значение |
|
||
|---|---|---|
|
||
| `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`, запишите расчет за все выбранные дни в промежуточную
|
||
таблицу одной вставкой. Затем замените дневные партиции основной таблицы по
|
||
одной. Добавьте запуск этих запросов в `dm_transform`.
|
||
|
||
### Ключ шардирования
|
||
|
||
Выберите ключ самостоятельно. У `revenue_daily` строки сгруппированы по дню
|
||
и категории товара; категорий всего шесть. Здесь страниц много, и число
|
||
событий на них сильно различается.
|
||
|
||
У основной и промежуточной таблиц используйте одинаковый ключ шардирования.
|
||
Замена партиции не перераспределяет строки между шардами. Подробнее об этом
|
||
в разделе [«Раскладка по шардам»](../architecture/storage.md#раскладка-по-шардам).
|
||
|
||
## Типичная ошибка
|
||
|
||
Из-за имени витрины хочется отобрать только просмотры. Но фильтр источника
|
||
по `event_type = 'pageview'` обнулит `cart_adds` и `purchases`, а запрос не
|
||
завершится ошибкой. Конверсия карточек станет нулевой. Проверка одной суммы
|
||
`pageviews` не обнаружит этот фильтр: все просмотры остались на месте.
|
||
Ошибку покажет сверка `purchases` или `cart_adds` с источником, если за день
|
||
были покупки или добавления в корзину.
|
||
|
||
Выбирайте проверку под возможную ошибку. Этот подход описан в
|
||
[справочнике проверок](../architecture/testing.md).
|
||
|
||
## Проверка результата
|
||
|
||
Рассчитайте те же показатели по `dds.event_v` за выбранный день.
|
||
Сопоставьте результат со строками `dm.top_pages_daily_v` за этот день
|
||
через `FULL OUTER JOIN` по `page_path`. Найдите страницы, которые есть
|
||
только с одной стороны, и строки, где различается хотя бы один из четырех
|
||
счетчиков. Расхождений должно быть ноль.
|
||
|
||
Перед полным сравнением проверьте дневные суммы:
|
||
|
||
- сумма `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` и убедились, что повторный
|
||
прогон конвейера не меняет результат.
|