docs(labs): добавлены история связей и инкрементальный пересчет
Зачем: дать практику учета новых связей пользователей при обновлении прежних дней витрины. Что: добавлены две связанные лабораторные с наблюдениями через Airflow, собственными таблицами student и повтором частично записанной загрузки. Обновлены программа, индекс и ссылки из справочников DDS и DM. Проверка: DDL и SQL под student на ClickHouse 26.3.17.56, четыре модельных дня через Airflow, полные сверки и повтор незавершенной загрузки; config-test, lint, локальные ссылки и независимое ревью.
This commit is contained in:
1 parent
c1d3a6db9b
commit
b839a671a1
6 files changed
+335
-9
No files matched your search
@@ -30,7 +30,7 @@
|
|||||||
`first_matched_at` нет. Запланированные витрины его не читают, а два возможных
|
`first_matched_at` нет. Запланированные витрины его не читают, а два возможных
|
||||||
смысла — «первая покупка вообще» и «момент, с которого связь была известна
|
смысла — «первая покупка вообще» и «момент, с которого связь была известна
|
||||||
хранилищу» — требуют разных исторических моделей. Этот вопрос оставлен
|
хранилищу» — требуют разных исторических моделей. Этот вопрос оставлен
|
||||||
[самостоятельной работе](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/145),
|
[самостоятельной работе](../../labs/optional/identity-over-time.md),
|
||||||
а текущий стенд не выдаёт один смысл за другой.
|
а текущий стенд не выдаёт один смысл за другой.
|
||||||
|
|
||||||
Статус заказа связь не меняет: любой заказ, сопоставленный с событием покупки,
|
Статус заказа связь не меняет: любой заказ, сопоставленный с событием покупки,
|
||||||
|
|||||||
@@ -281,7 +281,10 @@ business_key`.
|
|||||||
- **Инкрементальный пересчёт затронутых дней по `first_matched_at`.**
|
- **Инкрементальный пересчёт затронутых дней по `first_matched_at`.**
|
||||||
Производственный ход, но на объёмах стенда его экономия неизмерима, а
|
Производственный ход, но на объёмах стенда его экономия неизмерима, а
|
||||||
след новых связок требует вернуть колонку, выкинутую в #133. Стал лабой
|
след новых связок требует вернуть колонку, выкинутую в #133. Стал лабой
|
||||||
повышенной сложности — issue #149.
|
повышенной сложности —
|
||||||
|
[«Как обновлять витрину без полной пересборки»](../labs/optional/incremental-daily-traffic.md).
|
||||||
|
В ней новые связи находятся сравнением наблюдений: время покупки
|
||||||
|
не заменяет момент обнаружения связи.
|
||||||
- **Superset поверх DDS без слоя DM.** Терялся бы урок «витрина — контракт
|
- **Superset поверх DDS без слоя DM.** Терялся бы урок «витрина — контракт
|
||||||
под потребителя», против раздела 7 спеки.
|
под потребителя», против раздела 7 спеки.
|
||||||
|
|
||||||
|
|||||||
+11
-2
@@ -140,8 +140,13 @@ Airflow; для нее вы сохраняете состояния заказо
|
|||||||
|
|
||||||
### Тонкий анализ данных
|
### Тонкий анализ данных
|
||||||
|
|
||||||
Открывается после ступени 1. Знание о пользователе на дату и обогащение
|
Открывается после ступени 1.
|
||||||
отчета своим словарем.
|
|
||||||
|
- [Когда хранилище узнало пользователя](optional/identity-over-time.md):
|
||||||
|
сохранить историю связей, сравнить расчеты на прежних сессиях и определить,
|
||||||
|
какие сведения нужны для воспроизведения результата.
|
||||||
|
|
||||||
|
Обогащение отчета своим словарем регионов пока описано только в программе.
|
||||||
|
|
||||||
### Superset и BI
|
### Superset и BI
|
||||||
|
|
||||||
@@ -157,6 +162,10 @@ Airflow; для нее вы сохраняете состояния заказо
|
|||||||
Открывается после ступени 1. Прием и хранение данных, раскладка по шардам,
|
Открывается после ступени 1. Прием и хранение данных, раскладка по шардам,
|
||||||
повторная обработка дня и обновление витрин.
|
повторная обработка дня и обновление витрин.
|
||||||
|
|
||||||
|
- [Как обновлять витрину без полной пересборки](optional/incremental-daily-traffic.md):
|
||||||
|
продолжить работу о связях пользователей, пересчитать затронутые дни
|
||||||
|
и проверить повтор незавершенной загрузки. Повышенная сложность.
|
||||||
|
|
||||||
### Что делать, когда стенд сломался
|
### Что делать, когда стенд сломался
|
||||||
|
|
||||||
Открывается после ступени 7. Поломки стенда и инструкции по восстановлению
|
Открывается после ступени 7. Поломки стенда и инструкции по восстановлению
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# Когда хранилище узнало пользователя
|
||||||
|
|
||||||
|
**Чему учит:** различать время события и время появления связи в хранилище,
|
||||||
|
выбирать сведения для обогащения данных на дату расчета.
|
||||||
|
|
||||||
|
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
|
||||||
|
подключением `student` по [инструкции](../../../README.md#подключиться-из-dbeaver).
|
||||||
|
Наблюдения сохраняйте в `default` через одно подключение: ваши таблицы
|
||||||
|
локальны узлу. Если предложенное имя занято, выберите свое.
|
||||||
|
|
||||||
|
На сайте посетителя узнают по куке `client_id`, а магазин знает покупателя
|
||||||
|
по `user_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`: одного равенства количества недостаточно.
|
||||||
|
Для одной пары покажите номера заказов и события, по которым нашли время.
|
||||||
|
|
||||||
|
## Сохраните три наблюдения
|
||||||
|
|
||||||
|
Создайте таблицу:
|
||||||
|
|
||||||
|
```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);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для метки наблюдения используйте последний обработанный день событий:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT max(event_date) AS observation_day FROM dds.event_v;
|
||||||
|
```
|
||||||
|
|
||||||
|
Обозначим начальную дату **H0**. Это модельная дата, а не календарный день
|
||||||
|
запуска Airflow. После успешного `etl_pipeline` сохраните полный результат
|
||||||
|
своего запроса через `INSERT INTO ... SELECT`, добавив эту дату.
|
||||||
|
Проверьте число строк и уникальность пар за H0.
|
||||||
|
|
||||||
|
Затем дважды выполните последовательность:
|
||||||
|
|
||||||
|
1. Запустите `world_next_day` с `days = 1` и дождитесь успеха.
|
||||||
|
2. Запустите `etl_pipeline` и дождитесь успеха.
|
||||||
|
3. Получите новую `observation_day`, сохраните полный набор связей и проверьте его.
|
||||||
|
|
||||||
|
Получатся наблюдения **H0**, **H1** и **H2**. Каждую дату записывайте один раз:
|
||||||
|
обычный `MergeTree` не устраняет повторы вставки. Между этими действиями
|
||||||
|
не запускайте генерацию отдельно от наблюдения.
|
||||||
|
|
||||||
|
## Сопоставьте два времени
|
||||||
|
|
||||||
|
Сравните наборы пар в соседних наблюдениях. Для нескольких новых связей
|
||||||
|
покажите `client_id`, `user_id`, `first_purchase_at` и первую дату наблюдения,
|
||||||
|
в которой пара появилась. Найдите связь, покупка которой произошла до дня
|
||||||
|
ее обнаружения.
|
||||||
|
|
||||||
|
Для одной такой связи вернитесь к заказу и событию. По данным и
|
||||||
|
[порядку доставки заказов](../../architecture/orders/ingestion.md) объясните,
|
||||||
|
почему связь отсутствовала в прежнем наблюдении. Был ли момент покупки
|
||||||
|
достаточным основанием считать ее уже известной хранилищу?
|
||||||
|
|
||||||
|
У пары, которая присутствовала уже в H0, тоже получится минимальная дата
|
||||||
|
наблюдения. В этом случае она означает «пара была известна к началу опыта»:
|
||||||
|
истории до H0 у вас нет. Для новых пар ежедневные наблюдения устанавливают
|
||||||
|
интервал появления связи, а не точное время внутри него.
|
||||||
|
|
||||||
|
## Пересчитайте прежние визиты
|
||||||
|
|
||||||
|
Возьмите один и тот же набор сессий из `dds.session_v` за даты до H0
|
||||||
|
включительно. Постройте два дневных расчета:
|
||||||
|
|
||||||
|
- со связями, сохраненными в H0;
|
||||||
|
- со связями, сохраненными в H2.
|
||||||
|
|
||||||
|
Для каждого дня посчитайте посетителей по разным `client_id` и известных
|
||||||
|
пользователей по разным `user_id`. Сессии без связи должны остаться в расчете,
|
||||||
|
но неизвестный пользователь не должен увеличивать число известных.
|
||||||
|
В соединении распределенных сессий с локальной историей используйте
|
||||||
|
`GLOBAL LEFT JOIN` и заранее отберите в истории одну дату наблюдения.
|
||||||
|
|
||||||
|
Найдите день с разным числом известных пользователей. Проследите изменение
|
||||||
|
до конкретных связей и прежних сессий. Проверьте, что число посетителей
|
||||||
|
не изменилось и известные пользователи не превышают его.
|
||||||
|
|
||||||
|
Напишите, какой вариант нужен для двух требований к витрине:
|
||||||
|
|
||||||
|
- «пересчитать прошлые визиты с учетом всех сведений, доступных сейчас»;
|
||||||
|
- «воспроизвести расчет, сделанный при наблюдении H0».
|
||||||
|
|
||||||
|
Для второго требования проверьте еще один способ: взять текущие связи,
|
||||||
|
оставив только `first_purchase_at` до конца H0. Совпадет ли полный набор
|
||||||
|
пар с сохраненным в H0? Найденным расхождением обоснуйте выбор истории
|
||||||
|
для воспроизводимого расчета.
|
||||||
|
|
||||||
|
## Что должно получиться
|
||||||
|
|
||||||
|
У вас есть запрос связей с подтверждающими покупками, три сохраненных
|
||||||
|
наблюдения и сравнение двух расчетов на одном наборе сессий. Вы можете
|
||||||
|
показать, когда новая связь стала видна в наблюдениях, и объяснить,
|
||||||
|
какие данные понадобятся для воспроизведения прежнего расчета.
|
||||||
|
|
||||||
|
Сохраните SQL и таблицу наблюдений: они нужны в продолжении
|
||||||
|
[«Как обновлять витрину без полной пересборки»](incremental-daily-traffic.md).
|
||||||
|
Если продолжать не планируете, удалите свою таблицу через `DROP TABLE`.
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# Как обновлять витрину без полной пересборки
|
||||||
|
|
||||||
|
**Чему учит:** выбирать дни для пересчета по новым данным, проверять результат
|
||||||
|
и повторять незавершенную загрузку.
|
||||||
|
|
||||||
|
Факультатив повышенной сложности продолжает работу
|
||||||
|
[«Когда хранилище узнало пользователя»](identity-over-time.md).
|
||||||
|
Понадобятся ее запрос сохранения связей и таблица `default.lab_identity_history`.
|
||||||
|
Работайте под `student` через то же подключение DBeaver.
|
||||||
|
|
||||||
|
Стенд пересчитывает `dm.daily_traffic_v` целиком: новая связь может изменить
|
||||||
|
число известных пользователей в старом дне. Вы построите рядом свою витрину,
|
||||||
|
которая пересчитывает только затронутые дни и дает тот же результат.
|
||||||
|
|
||||||
|
В опыте появляются новые дни сессий и новые связи. Мир стенда не отзывает
|
||||||
|
связи и не исправляет старые сессии при обычном продвижении времени.
|
||||||
|
Удаление данных, исправления старых сессий и пересоздание мира потребовали бы
|
||||||
|
другого способа обнаружения изменений.
|
||||||
|
|
||||||
|
## Подготовьте витрину и журнал загрузок
|
||||||
|
|
||||||
|
Создайте две локальные таблицы. Если имена заняты, выберите свои.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
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`, если они больше не нужны.
|
||||||
@@ -207,11 +207,27 @@
|
|||||||
|
|
||||||
Открывается после ступени 1 основной программы.
|
Открывается после ступени 1 основной программы.
|
||||||
|
|
||||||
- **Что мы знали о пользователе в тот день (#145).** Текущее знание и знание на
|
- **[Когда хранилище узнало пользователя](../labs/optional/identity-over-time.md) (#145).**
|
||||||
дату дают разные отчеты; сведения из будущего меняют прошлое.
|
Учащийся собирает связи с подтверждающими покупками и сохраняет три
|
||||||
|
ежедневных наблюдения. На одном наборе прежних сессий сравнивает расчет
|
||||||
|
с прежними и новыми связями, выбирает историю для воспроизведения расчета.
|
||||||
- **Добавь названия регионов в отчет (#143).** Менти собирает свой словарь по
|
- **Добавь названия регионов в отчет (#143).** Менти собирает свой словарь по
|
||||||
образцу каталога и обогащает отчет через `dictGet`.
|
образцу каталога и обогащает отчет через `dictGet`.
|
||||||
|
|
||||||
|
Работа о связях продолжается в инженерном разделе лабораторной про
|
||||||
|
инкрементальный `daily_traffic`. В обеих учащийся продвигает мир через
|
||||||
|
`world_next_day` и `etl_pipeline`, сохраняет наблюдения под `student` в
|
||||||
|
свои локальные таблицы `default` и сравнивает их SQL-запросами.
|
||||||
|
|
||||||
|
Время первой подтверждающей покупки и время обнаружения связи разделены.
|
||||||
|
Минимум времени `purchase` не принят за границу появления новых связей:
|
||||||
|
заказ может поступить позже события. Нужные изменения определяются по
|
||||||
|
разности сохраненных наборов пар. Ежедневное наблюдение ограничивает момент
|
||||||
|
появления связи интервалом; для пар начального наблюдения более ранняя
|
||||||
|
история неизвестна. История сессий в этом опыте растет без исправлений
|
||||||
|
прошлых дней, а связи не отзываются — поэтому сохраненных наборов связей
|
||||||
|
достаточно для сравнения расчетов на прежних сессиях.
|
||||||
|
|
||||||
### Superset и BI
|
### Superset и BI
|
||||||
|
|
||||||
Открывается после ступени 2 основной программы.
|
Открывается после ступени 2 основной программы.
|
||||||
@@ -267,9 +283,28 @@
|
|||||||
- **Что будет, если день заменился не на всех шардах.** Замена дня завершается
|
- **Что будет, если день заменился не на всех шардах.** Замена дня завершается
|
||||||
отдельно на каждом шарде, поэтому целостность результата подтверждает
|
отдельно на каждом шарде, поэтому целостность результата подтверждает
|
||||||
отдельная сверка.
|
отдельная сверка.
|
||||||
- **Как обновлять витрину без полной пересборки (#149) — повышенная
|
- **[Как обновлять витрину без полной пересборки](../labs/optional/incremental-daily-traffic.md)
|
||||||
сложность.** Экономия на пересчете требует хранить историю изменений, которую
|
(#149) — повышенная сложность.** Продолжение работы о связях пользователей:
|
||||||
полная пересборка стирает.
|
учащийся строит свою витрину, выбирает затронутые дни по новым сессиям
|
||||||
|
и связям, сверяет весь результат с `dm.daily_traffic_v`. Журнал успешных
|
||||||
|
загрузок позволяет повторить опыт с частично записанным результатом.
|
||||||
|
|
||||||
|
Инкрементальная работа начинается с полной загрузки текущего состояния,
|
||||||
|
затем охватывает два новых модельных дня. Обновление собственной витрины
|
||||||
|
выполнено вставкой версий в `ReplacingMergeTree`, чтение — с `FINAL`.
|
||||||
|
Это оставляет права `student` прежними и не требует менять конвейер стенда.
|
||||||
|
Версия — дата наблюдения; ключ — день отчета. История связей хранится
|
||||||
|
отдельно от версий витрины. Выбор опирается на
|
||||||
|
[договор движка](https://clickhouse.com/docs/engines/table-engines/mergetree-family/replacingmergetree):
|
||||||
|
максимальная версия по ключу и удаление прежних версий при слияниях.
|
||||||
|
DDL, обновление вставкой и чтение с `FINAL` проверены под `student`
|
||||||
|
на ClickHouse 26.3.17.56.
|
||||||
|
|
||||||
|
Полный пересчет остается эталоном, а экономия оценивается числом выбранных
|
||||||
|
дней. На малом объеме ускорение не обещано. Поиск связей продолжает читать
|
||||||
|
историю источников целиком; инкрементальным становится расчет дневной витрины.
|
||||||
|
Полная замена стендового ETL отклонена: для учебного сравнения достаточно
|
||||||
|
своей витрины и журнала рядом с работающим конвейером.
|
||||||
|
|
||||||
### Что делать, когда стенд сломался
|
### Что делать, когда стенд сломался
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user