Files
clickstream-data-platform/docs/labs/optional/incremental-daily-traffic.md
T
ddadmin b839a671a1 docs(labs): добавлены история связей и инкрементальный пересчет
Зачем: дать практику учета новых связей пользователей при обновлении
прежних дней витрины.

Что: добавлены две связанные лабораторные с наблюдениями через Airflow,
собственными таблицами student и повтором частично записанной загрузки.
Обновлены программа, индекс и ссылки из справочников DDS и DM.

Проверка: DDL и SQL под student на ClickHouse 26.3.17.56, четыре модельных
дня через Airflow, полные сверки и повтор незавершенной загрузки;
config-test, lint, локальные ссылки и независимое ревью.
2026-09-22 05:57:11 -04:00

10 KiB
Raw Blame History

Как обновлять витрину без полной пересборки

Чему учит: выбирать дни для пересчета по новым данным, проверять результат и повторять незавершенную загрузку.

Факультатив повышенной сложности продолжает работу «Когда хранилище узнало пользователя». Понадобятся ее запрос сохранения связей и таблица default.lab_identity_history. Работайте под student через то же подключение DBeaver.

Стенд пересчитывает dm.daily_traffic_v целиком: новая связь может изменить число известных пользователей в старом дне. Вы построите рядом свою витрину, которая пересчитывает только затронутые дни и дает тот же результат.

В опыте появляются новые дни сессий и новые связи. Мир стенда не отзывает связи и не исправляет старые сессии при обычном продвижении времени. Удаление данных, исправления старых сессий и пересоздание мира потребовали бы другого способа обнаружения изменений.

Подготовьте витрину и журнал загрузок

Создайте две локальные таблицы. Если имена заняты, выберите свои.

CREATE TABLE default.lab_daily_traffic
(
    report_date Date,
    visitors UInt64,
    known_users UInt64,
    observation_day Date
)
ENGINE = ReplacingMergeTree(observation_day)
ORDER BY report_date;

CREATE TABLE default.lab_traffic_runs
(
    observation_day Date
)
ENGINE = MergeTree
ORDER BY observation_day;

В витрине одна актуальная строка на день. Для обновления вставляйте полный новый результат дня с новой observation_day; читайте его с FINAL. Движок выбирает максимальную observation_day для каждого report_date. Старая версия может исчезнуть при слиянии: эта таблица хранит текущий расчет, а не историю наблюдений.

Журнал хранит даты успешно завершенных загрузок. Добавляйте дату только после записи всех выбранных дней и успешной сверки. Последняя строка журнала будет границей, от которой вы ищете новые связи в следующем прогоне.

Выполните первую загрузку целиком

Убедитесь, что world_live стоит на паузе и нет активных прогонов генерации и обработки. Запустите etl_pipeline и дождитесь успеха. Получите текущую observation_day способом из первой работы. Если такого наблюдения еще нет в вашей истории, сохраните его; уже сохраненную дату повторно не вставляйте.

Напишите INSERT INTO ... SELECT, который рассчитывает все даты сессий из dds.session_v со связями текущего наблюдения. Правила результата:

Колонка Что считать
report_date session_date
visitors число разных client_id
known_users число разных известных user_id
observation_day дата текущего наблюдения

Сессии без известного пользователя сохраняйте. Несколько кук одного пользователя не должны увеличивать known_users. Для соединения с локальной историей связей используйте GLOBAL LEFT JOIN.

Построчно сверьте свои report_date, visitors, known_users с dm.daily_traffic_v. Сверка должна находить лишние и отсутствующие даты и различия обоих показателей. Учебную витрину читайте с FINAL. После совпадения запишите дату наблюдения в журнал один раз.

Выберите дни следующего пересчета

Продвиньте мир на один день: world_next_day с days = 1, затем etl_pipeline; после каждого запуска дождитесь успеха. Сохраните новое наблюдение связей запросом из первой работы.

Обозначим дату последней успешной загрузки из журнала P, текущую дату наблюдения — H. До записи результата составьте запрос, возвращающий разные даты для пересчета. Он должен учесть два изменения:

  • в сессиях появились дни, которых еще нет в вашей витрине;
  • в карте появились пары, которых не было при P; у этих кук есть сессии, в том числе за прежние дни.

Сначала выведите даты и разберите одну старую дату: какая новая пара привела к ее выбору и какие сессии с ней связаны? Рядом посчитайте, сколько дат пересчитала бы полная загрузка. Зафиксируйте оба числа; равенство тоже возможно, если новые связи затронули всю историю.

Проверьте альтернативу: искать изменения по first_purchase_at, взяв покупки только после конца P. Сравните полученный набор пар с разностью наблюдений. Покажите пару, которую такое ограничение пропускает.

Обновите выбранные дни

Напишите второй INSERT INTO ... SELECT. Для выбранных дат он должен рассчитать все сессии с полной картой связей на H. Прибавление числа новых связей к прежнему known_users не заменяет пересчет разных пользователей.

Вставьте результаты с версией H. Полностью сверьте актуальную учебную витрину со стендовой, включая дни, которые не пересчитывали. Только после совпадения добавьте H в журнал.

Без продвижения мира повторите выбор дат. После успешной загрузки новых дат и пар быть не должно, а результат витрины должен остаться прежним. Повторно записывать H в журнал не требуется.

Повторите незавершенную загрузку

Снова запустите world_next_day с days = 1, затем etl_pipeline, дожидаясь успеха каждого. Сохраните новое наблюдение связей. Получите даты для пересчета, но запишите результат только за одну из них. Остальные пока не загружайте и дату в журнал не добавляйте. Так вы воспроизведете остановку между записями дней, не ломая стенд.

Запустите свой обычный расчет еще раз, определив P по журналу. Он должен довести загрузку до совпадения со стендовой витриной без очистки уже записанных строк. После сверки запишите H в журнал.

Объясните на этом опыте, почему последнее сохраненное наблюдение нельзя автоматически считать загруженным в витрину. Что изменится, если записать H в журнал до обновления витрины?

Что должно получиться

Сохраните SQL первой загрузки, выбора дат, обновления и сверки. После двух новых модельных дней ваша витрина совпадает со стендовой, повтор без новых данных сохраняет результат, а незавершенную загрузку можно продолжить без полной пересборки.

Сравните цену двух вариантов: сколько дней вы пересчитывали и какие дополнительные данные хранили. По этому опыту можно судить об объеме работы, но не об ускорении: на небольшом стенде полный пересчет может быть дешевле. В вашей реализации поиск связей пока читает всю историю покупок — инкрементальным стал именно пересчет дневной витрины.

После работы удалите свои lab_daily_traffic, lab_traffic_runs и lab_identity_history через DROP TABLE, если они больше не нужны.