feat(dds): модель заказа и пересборка окна заменой партиций #164
No files matched your search
+2
-2
@@ -54,8 +54,8 @@ x-world-starting-days: &world-starting-days "8"
|
|||||||
# генератора значило бы разрешить менять физику мира снаружи, а опись мира
|
# генератора значило бы разрешить менять физику мира снаружи, а опись мира
|
||||||
# держится на её неизменности. Стенду копия нужна затем, что по этому же числу
|
# держится на её неизменности. Стенду копия нужна затем, что по этому же числу
|
||||||
# трансформация DDS решает, какие дни пересобирать. Разойдутся — пересборка
|
# трансформация DDS решает, какие дни пересобирать. Разойдутся — пересборка
|
||||||
# промахнётся по краю окна, и заметит это не проверка, а менти со вчерашней
|
# промахнётся по краю окна. Сверять копии некому, и это осознанно: слепые пятна
|
||||||
# выручкой.
|
# конвейера собраны в docs/architecture/etl.md и адресованы контуру DQ.
|
||||||
x-order-window-days: &order-window-days "7"
|
x-order-window-days: &order-window-days "7"
|
||||||
|
|
||||||
x-airflow-common: &airflow-common
|
x-airflow-common: &airflow-common
|
||||||
|
|||||||
+7
-16
@@ -8,17 +8,10 @@
|
|||||||
дневного конвейера, с кнопки менти и после падения
|
дневного конвейера, с кнопки менти и после падения
|
||||||
(docs/architecture/etl.md, «Объём прогона»).
|
(docs/architecture/etl.md, «Объём прогона»).
|
||||||
|
|
||||||
Идемпотентность здесь устроена не так, как в приёме заказов, и в этом весь
|
Повтор прогона гасит не колонка версии, а замена партиции целиком: день
|
||||||
урок сущности. Приём гасит повтор колонкой версии: ReplacingMergeTree
|
собирается в таблицу-двойник и подменяет собой партицию цели. Почему слой
|
||||||
оставляет позднюю строку. Трансформация версий не знает — она собирает день
|
устроен так — sql/ddl/45-dds-tables.sql; механика самой подмены —
|
||||||
заново в таблицу-двойник и атомарно подменяет им партицию цели. Поэтому
|
sql/dds/order_replace.sql.
|
||||||
повтор прогона не меняет делового содержимого слоя, а строки пересобранных
|
|
||||||
дней получают новый _load_id: видно, каким запуском собран каждый день.
|
|
||||||
|
|
||||||
Замена партиции идёт по локальным таблицам с ON CLUSTER: по Distributed
|
|
||||||
операции с партициями отвечают кодом 48 (docs/architecture/storage.md, «Что
|
|
||||||
проверено»). Форма двойника и цена ошибки в ключе шардирования разобраны в
|
|
||||||
sql/ddl/45-dds-tables.sql.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -38,11 +31,9 @@ START_DATE = datetime.datetime(2026, 1, 1, tzinfo=datetime.UTC)
|
|||||||
SQL_ROOT = Path("/opt/airflow/sql")
|
SQL_ROOT = Path("/opt/airflow/sql")
|
||||||
CLICKHOUSE_CONNECTION = "clickhouse_default"
|
CLICKHOUSE_CONNECTION = "clickhouse_default"
|
||||||
|
|
||||||
# Окно изменяемости заказа, модельные дни. Число мира, а не настройка стенда:
|
# Окно изменяемости заказа, модельные дни: по нему трансформация решает, какие
|
||||||
# владелец — generator/world.py (ORDER_WINDOW_DAYS), который этим окном
|
# дни ещё могут измениться. Число принадлежит миру, владелец — генератор;
|
||||||
# собирает слепок. Здесь оно читается, чтобы хранилище знало, какие дни ещё
|
# почему у стенда лежит копия и чем она рискует — compose.yaml.
|
||||||
# могут измениться. Разойдутся два объявления — пересборка промахнётся по краю
|
|
||||||
# окна, поэтому оба названы в compose.yaml рядом и с этой оговоркой.
|
|
||||||
ORDER_WINDOW_DAYS = int(os.environ["ORDER_WINDOW_DAYS"])
|
ORDER_WINDOW_DAYS = int(os.environ["ORDER_WINDOW_DAYS"])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/{table}', '{
|
|||||||
PARTITION BY order_date
|
PARTITION BY order_date
|
||||||
ORDER BY order_id;
|
ORDER BY order_id;
|
||||||
|
|
||||||
-- Двойник шардируется тем же ключом, что цель, и это не украшение: REPLACE
|
-- Двойник шардируется тем же ключом, что цель. REPLACE PARTITION идёт по
|
||||||
-- PARTITION идёт по локальным таблицам, шард за шардом. Ляг строка заказа в
|
-- локальным таблицам, шард за шардом. Ляг строка заказа в
|
||||||
-- доноре на другой шард, чем её место в цели, — подмена перенесла бы её не
|
-- доноре на другой шард, чем её место в цели, — подмена перенесла бы её не
|
||||||
-- туда, и заказ пропал бы с одного шарда и задвоился на другом.
|
-- туда, и заказ пропал бы с одного шарда и задвоился на другом.
|
||||||
CREATE TABLE IF NOT EXISTS dds.order_stage_dist ON CLUSTER clickstream_cluster
|
CREATE TABLE IF NOT EXISTS dds.order_stage_dist ON CLUSTER clickstream_cluster
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
-- раз на весь отрезок. Кто раскладывает строки по шардам — вставка через
|
-- раз на весь отрезок. Кто раскладывает строки по шардам — вставка через
|
||||||
-- Distributed, ключ cityHash64(order_id) — разобрано в DDL двойника.
|
-- Distributed, ключ cityHash64(order_id) — разобрано в DDL двойника.
|
||||||
--
|
--
|
||||||
-- Чистит двойник DROP PARTITION ALL, а не TRUNCATE, и это не вкусовщина:
|
-- Чистит двойник DROP PARTITION ALL, а не TRUNCATE: последнее — отдельное
|
||||||
-- TRUNCATE — отдельное право, роли etl оно не выдано, а снятие всех партиций
|
-- право, роли etl оно не выдано, а снятие всех партиций
|
||||||
-- входит в ALTER, который у неё есть (ADR 0007). Замерено: TRUNCATE отвечает
|
-- входит в ALTER, который у неё есть (ADR 0007). Замерено: TRUNCATE отвечает
|
||||||
-- ролью etl кодом 497, DROP PARTITION ALL проходит. Расширять права ради
|
-- ролью etl кодом 497, DROP PARTITION ALL проходит. Расширять права ради
|
||||||
-- операции, для которой уже есть разрешённая форма, значило бы платить
|
-- операции, для которой уже есть разрешённая форма, значило бы платить
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
-- задачами и падают порознь, поэтому упавший день оставляет дыру, пока
|
-- задачами и падают порознь, поэтому упавший день оставляет дыру, пока
|
||||||
-- соседние дни собираются дальше. Считай мы прогресс по максимуму собранного
|
-- соседние дни собираются дальше. Считай мы прогресс по максимуму собранного
|
||||||
-- дня, дыра позади окна не заросла бы никогда, а прогоны продолжали бы
|
-- дня, дыра позади окна не заросла бы никогда, а прогоны продолжали бы
|
||||||
-- зеленеть над щербатым слоем. Цена честного ответа — проход по дню заказа в
|
-- зеленеть над щербатым слоем. Цена честного ответа — проход по дню заказа
|
||||||
-- ODS; она того стоит.
|
-- в ODS.
|
||||||
--
|
--
|
||||||
-- Край окна берётся из делового поля, а не из ярлыков доставки: время
|
-- Край окна берётся из делового поля, а не из ярлыков доставки: время
|
||||||
-- создания заказа одинаково у всех его версий, а `snapshot_date` и `_load_id`
|
-- создания заказа одинаково у всех его версий, а `snapshot_date` и `_load_id`
|
||||||
|
|||||||
Reference in new issue
Block a user