feat(ods): версией заказа стала дата слепка, окно DDS — из данных
- Зачем:
- ярлык snapshot_date выжившей строки доставался жребием, а объём
пересборки DDS держался на константе окна с двумя несверяемыми копиями
(ADR 0014, развилка #163).
- Что:
- ods.order_rep переведена на ReplacingMergeTree(snapshot_date): выживает
строка позднейшего слепка, ярлык стал правдивым.
- order_scope.sql выводит окно из дней последнего слепка; ORDER_WINDOW_DAYS
и параметр window_days сняты со стенда, мёртвая защита краем источника
убрана.
- документы и комментарии SQL приведены к ADR 0014: роль ODS, условие
«одна дата — один слепок», объём прогона и слепые пятна конвейера.
- Проверка:
- make lint; make rebuild-storage, затем make smoke, make check-clickhouse,
make check-services — зелёные.
- после двух слепков snapshot_date всех 1917 строк ods.order_v равен
последнему слепку заказа, расхождений ноль; деловые поля построчно
совпали с эталоном argMax по updated_at из сырья.
- dds_transform без K: первый прогон 06-01…06-07, после нового дня мира
06-02…06-08, повтор прогона содержимого не изменил.
Closes #165
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
650efacc3f
commit
a82c75705d
13 files changed
+140
-141
No files matched your search
+26
-28
@@ -10,11 +10,11 @@
|
||||
-- запросом, дописывая формат ответа, — точка с запятой сделала бы из этого
|
||||
-- мультизапрос, который ClickHouse не принимает.
|
||||
--
|
||||
-- Объём складывается из двух частей. Первая — дышащее окно: K последних дней
|
||||
-- источника, состояние которых слепок ещё может изменить. Вторая — хвост от
|
||||
-- первого дня, которого в слое нет: первая сборка застаёт слой пустым и
|
||||
-- собирает весь стартовый мир, а после разгона мира пачкой слой догоняет
|
||||
-- уехавший вперёд источник.
|
||||
-- Объём складывается из двух частей. Первая — дышащее окно: дни, которые нёс
|
||||
-- последний слепок, то есть те, чьё состояние источник ещё может изменить.
|
||||
-- Вторая — хвост от первого дня, которого в слое нет: первая сборка застаёт
|
||||
-- слой пустым и собирает весь стартовый мир, а после разгона мира пачкой слой
|
||||
-- догоняет уехавший вперёд источник.
|
||||
--
|
||||
-- **Хвост считается от первого недостающего дня, а не от последнего
|
||||
-- собранного.** Разница не косметическая: замены партиций идут отдельными
|
||||
@@ -24,22 +24,26 @@
|
||||
-- зеленеть над щербатым слоем. Цена честного ответа — проход по дню заказа
|
||||
-- в ODS.
|
||||
--
|
||||
-- Край окна берётся из делового поля, а не из ярлыков доставки: время
|
||||
-- создания заказа одинаково у всех его версий, а `snapshot_date` и `_load_id`
|
||||
-- выжившей строки достаются жребием (docs/architecture/etl.md, «Объём
|
||||
-- прогона», и docs/architecture/orders/ingestion.md, «Роль ODS»).
|
||||
-- Окно читается из ярлыка слепка, а не вычисляется вычитанием окна
|
||||
-- изменяемости: у выжившей строки snapshot_date — последний слепок, который
|
||||
-- нёс этот заказ (ADR 0014). Поэтому оба края окна знает сам источник, а
|
||||
-- копии его константы на стороне стенда больше нет.
|
||||
--
|
||||
-- Известная неточность края: если в самый свежий день источника не родилось
|
||||
-- ни одного заказа, окно съезжает на день назад — лишний замёрзший день
|
||||
-- пересоберётся впустую, а пустой день не тронется. Данные от этого не
|
||||
-- страдают, меняется только ярлык загрузки лишнего дня. Точный ответ здесь
|
||||
-- дала бы дата слепка, но она и есть тот самый жребий.
|
||||
-- FINAL не нужен ни здесь, ни ниже: время рождения заказа у всех его версий
|
||||
-- одно, а строки последнего слепка несут максимум колонки версии — мерж
|
||||
-- оставляет как раз их.
|
||||
WITH
|
||||
-- FINAL не нужен: время рождения заказа версии не различают.
|
||||
(SELECT max(toDate(toTimeZone(created_at, 'Europe/Samara')))
|
||||
FROM ods.order_dist) AS last_source_day,
|
||||
(SELECT min(toDate(toTimeZone(created_at, 'Europe/Samara')))
|
||||
FROM ods.order_dist) AS first_source_day,
|
||||
(SELECT max(snapshot_date) FROM ods.order_dist) AS last_snapshot,
|
||||
(
|
||||
SELECT min(toDate(toTimeZone(created_at, 'Europe/Samara')))
|
||||
FROM ods.order_dist
|
||||
WHERE snapshot_date = last_snapshot
|
||||
) AS window_start,
|
||||
(
|
||||
SELECT max(toDate(toTimeZone(created_at, 'Europe/Samara')))
|
||||
FROM ods.order_dist
|
||||
WHERE snapshot_date = last_snapshot
|
||||
) AS window_end,
|
||||
-- GLOBAL обязателен: обе таблицы распределённые, и обычный NOT IN сверял
|
||||
-- бы дни источника с локальной частью слоя на каждом шарде — день, чьи
|
||||
-- заказы легли на соседний шард, показался бы недостающим.
|
||||
@@ -51,15 +55,9 @@ WITH
|
||||
FROM ods.order_dist
|
||||
)
|
||||
WHERE day GLOBAL NOT IN (SELECT order_date FROM dds.order_dist)
|
||||
) AS first_missing_day,
|
||||
last_source_day - ({window_days:UInt16} - 1) AS window_start
|
||||
) AS first_missing_day
|
||||
SELECT
|
||||
-- Дыр нет — начинаем с окна; есть — с первой из них, если она старше окна.
|
||||
-- greatest держит левый край не раньше первого дня, известного источнику:
|
||||
-- у молодого мира окно шире самого мира.
|
||||
greatest(
|
||||
least(window_start, coalesce(first_missing_day, window_start)),
|
||||
first_source_day
|
||||
) AS first_day,
|
||||
last_source_day AS last_day
|
||||
least(window_start, coalesce(first_missing_day, window_start)) AS first_day,
|
||||
window_end AS last_day
|
||||
WHERE (SELECT count() FROM ods.order_dist) > 0
|
||||
Reference in new issue
Block a user