# Как новые заказы меняют отчет о посетителях Вы сохраните историю связей посетителей сайта с покупателями магазина. На ее основе проверите, как новые связи меняют старые отчеты и что нужно, чтобы повторить прежний расчет. Факультатив доступен после ступени 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`.