- Зачем: начинающим трудно читать задания из-за необъясненных терминов и неестественных формулировок. - Что: переработаны вводная и 21 задание, названы темы разделов, объяснены термины и сокращены повторы; согласованы правила учебного текста и ссылки. - Проверка: сохранены 25 блоков SQL и команд и таблицы состава колонок; проверены 153 локальные ссылки и 32 входящие ссылки на разделы; git diff --check прошел.
145 lines
9.9 KiB
Markdown
145 lines
9.9 KiB
Markdown
# Как новые заказы меняют отчет о посетителях
|
||
|
||
Вы сохраните историю связей посетителей сайта с покупателями магазина.
|
||
На ее основе проверите, как новые связи меняют старые отчеты и что нужно,
|
||
чтобы повторить прежний расчет.
|
||
|
||
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
|
||
подключением `student` по [инструкции](../../../README.md#подключиться-из-dbeaver).
|
||
Результаты запросов сохраняйте в `default` через одно подключение:
|
||
ваши таблицы будут доступны только на узле этого подключения.
|
||
Если предложенное имя таблицы занято, выберите свое.
|
||
|
||
В событиях сайта посетитель обозначен `client_id` из cookie браузера,
|
||
а в заказах покупатель обозначен `user_id`. Сопоставив событие покупки
|
||
с заказом, можно связать эти идентификаторы. Тогда и к прежним визитам
|
||
этого `client_id` можно добавить
|
||
пользователя магазина. Вы проверите, как появление такой связи меняет число
|
||
известных пользователей в отчете за прошедший день.
|
||
|
||
## Связи посетителей с покупателями
|
||
|
||
Поставьте `world_live` на паузу, дождитесь завершения начатых прогонов
|
||
генерации и обработки. Запустите `etl_pipeline` и дождитесь успеха.
|
||
На время работы мир будете продвигать вручную; новые дни останутся в стенде.
|
||
|
||
Напишите запрос по двум источникам:
|
||
|
||
| Источник | Нужные поля |
|
||
|---|---|
|
||
| `dds.event_v` | `event_type`, `event_time`, `client_id`, `purchase_id` |
|
||
| `dds.order_v` | `order_id`, `user_id` |
|
||
|
||
В результате нужна одна строка на пару `client_id`, `user_id`. Для каждой пары
|
||
найдите самое раннее время события покупки, которое удалось сопоставить
|
||
с заказом. Назовите эту колонку `first_purchase_at`.
|
||
В событии `purchase` массив `purchase_id` содержит один номер заказа.
|
||
Статус заказа не ограничивайте: отмена покупки не меняет найденную связь
|
||
посетителя с покупателем.
|
||
|
||
Источники распределены по разным ключам. Для соединения используйте
|
||
`GLOBAL INNER JOIN`, заключив выборки событий и заказов в подзапросы.
|
||
Устройство источников описано в [карте идентичностей](../../architecture/dds/identity.md).
|
||
|
||
Проверьте уникальность пар и совпадение их полного набора с
|
||
`dds.identity_map_v`: одного равенства количества недостаточно.
|
||
Для одной пары покажите номера заказов и события, по которым получили
|
||
`first_purchase_at`.
|
||
|
||
## История связей
|
||
|
||
Создайте таблицу:
|
||
|
||
```sql
|
||
CREATE TABLE default.lab_identity_history
|
||
(
|
||
observation_day Date,
|
||
client_id UInt64,
|
||
user_id UInt64,
|
||
first_purchase_at DateTime('Europe/Samara')
|
||
)
|
||
ENGINE = MergeTree
|
||
ORDER BY (observation_day, client_id, user_id);
|
||
```
|
||
|
||
Каждая копия списка должна содержать все найденные пары. В колонку
|
||
`observation_day` запишите последний обработанный день событий:
|
||
|
||
```sql
|
||
SELECT max(event_date) AS observation_day FROM dds.event_v;
|
||
```
|
||
|
||
Обозначим полученную дату **H0**. Она показывает, после обработки какого
|
||
модельного дня сохранен список; календарная дата запуска Airflow здесь
|
||
не используется. Сохраните полный результат своего запроса через
|
||
`INSERT INTO ... SELECT`, добавив H0 в `observation_day` каждой строки.
|
||
Сверьте число записанных строк с результатом исходного запроса и проверьте
|
||
уникальность пар для этой даты.
|
||
|
||
Затем дважды выполните последовательность:
|
||
|
||
1. Запустите `world_next_day` с `days = 1` и дождитесь успеха.
|
||
2. Запустите `etl_pipeline` и дождитесь успеха.
|
||
3. Получите новую `observation_day`, сохраните полный набор связей и проверьте его.
|
||
|
||
Получатся три копии списка: после дней **H0**, **H1** и **H2**.
|
||
Для каждой даты сохраняйте список один раз: обычный `MergeTree`
|
||
не устраняет повторы вставки. Сохраните и проверьте список перед тем,
|
||
как запускать следующий модельный день.
|
||
|
||
## Дата покупки и дата появления связи
|
||
|
||
Сравните списки за соседние даты: H0 с H1, затем H1 с H2. Найдите пары,
|
||
которых не было в прежнем списке. Для нескольких таких пар покажите
|
||
`client_id`, `user_id`, `first_purchase_at` и первую `observation_day`,
|
||
в которой пара появилась. Найдите пример, где покупка произошла раньше
|
||
этой даты.
|
||
|
||
Для одной такой связи вернитесь к заказу и событию. По данным и
|
||
[порядку доставки заказов](../../architecture/orders/ingestion.md) объясните,
|
||
почему пары не было в прежнем списке. Какие данные понадобились для ее
|
||
появления и когда они стали доступны?
|
||
|
||
Для пары, которая присутствовала уже в H0, нельзя определить дату появления:
|
||
у вас нет более ранних копий списка. Для новой пары можно установить
|
||
интервал между двумя сохранениями, но не точное время внутри него.
|
||
|
||
## Пересчет прежних отчетов
|
||
|
||
Возьмите один и тот же набор сессий из `dds.session_v` за даты до H0
|
||
включительно. Постройте два дневных расчета:
|
||
|
||
- со списком связей на H0;
|
||
- со списком связей на H2.
|
||
|
||
Для каждого дня посчитайте посетителей по разным `client_id` и известных
|
||
пользователей по разным `user_id`. Сессии без связи должны остаться в расчете,
|
||
но неизвестный пользователь не должен увеличивать число известных.
|
||
В соединении сессий с вашей таблицей используйте `GLOBAL LEFT JOIN`.
|
||
В таблице связей заранее отберите одну `observation_day`, чтобы копии
|
||
списка за разные дни не смешались.
|
||
|
||
Найдите день с разным числом известных пользователей. Проследите изменение
|
||
до конкретных связей и прежних сессий. Проверьте, что число посетителей
|
||
не изменилось, а число известных пользователей не больше числа посетителей.
|
||
|
||
Теперь проверьте, можно ли воспроизвести расчет на H0 без сохраненного
|
||
списка за эту дату. Возьмите список на H2 и оставьте только пары,
|
||
у которых `first_purchase_at` приходится на H0 или более ранний день.
|
||
Сравните полный набор пар с копией на H0. Выведите пары, которые есть
|
||
только в одном из списков.
|
||
На примере найденных различий объясните, какие данные нужно сохранять,
|
||
чтобы повторить прежний расчет.
|
||
|
||
## Результат работы
|
||
|
||
У вас есть запрос сопоставления посетителей с покупателями, три сохраненных
|
||
списка связей и сравнение двух расчетов на одном наборе сессий. На конкретных
|
||
парах вы можете показать разницу между датой покупки и датой появления пары
|
||
в сохраненном списке, а также объяснить, что нужно для повторения прежнего
|
||
расчета.
|
||
|
||
Сохраните SQL и таблицу `lab_identity_history`: они нужны в продолжении
|
||
[«Как обновлять витрину без полной пересборки»](incremental-daily-traffic.md).
|
||
Если продолжать не планируете, удалите свою таблицу через `DROP TABLE`.
|