refactor(dm): уточнены ограничения DAG и пояснения SQL
- Зачем: - Ревью выявило неясные причины ограничений и защитных условий в учебном образце. - Что: - Спекулятивный общий потолок задач заменен адресным лимитом размноженной замены с точным описанием OOM. - Объяснены нулевое значение непарного LEFT JOIN и опасность пустого DDS при замене партиций. - Добавлена ссылка на разбор области пересборки, а общий штамп про Context7 удален. - Проверка: - make lint, make config-test, make smoke; успешный запуск dm_transform.
This commit is contained in:
1 parent
da0477f0f1
commit
741820789f
3 files changed
+13
-9
No files matched your search
@@ -3,9 +3,6 @@
|
|||||||
Выручка наследует ритм заказов и заменяет дневные партиции изменяемого окна.
|
Выручка наследует ритм заказов и заменяет дневные партиции изменяемого окна.
|
||||||
Трафик наследует ретроспективность карты идентичностей и пересчитывает всю
|
Трафик наследует ретроспективность карты идентичностей и пересчитывает всю
|
||||||
историю новой версией. Объем каждого прогона выводится из состояния слоев.
|
историю новой версией. Объем каждого прогона выводится из состояния слоев.
|
||||||
|
|
||||||
Форма DAG и динамическая замена сверены с публичным API Airflow 3 через
|
|
||||||
Context7; DDL и REPLACE PARTITION — с документацией ClickHouse.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -26,7 +23,7 @@ CLICKHOUSE_CONNECTION = "clickhouse_default"
|
|||||||
|
|
||||||
|
|
||||||
def _days(first_day: datetime.date, last_day: datetime.date) -> list[str]:
|
def _days(first_day: datetime.date, last_day: datetime.date) -> list[str]:
|
||||||
"""Дни замены строками от левой до правой границы включительно."""
|
"""Дни отрезка строками - в таком виде их ждет замена партиции."""
|
||||||
return [
|
return [
|
||||||
(first_day + datetime.timedelta(days=shift)).isoformat()
|
(first_day + datetime.timedelta(days=shift)).isoformat()
|
||||||
for shift in range((last_day - first_day).days + 1)
|
for shift in range((last_day - first_day).days + 1)
|
||||||
@@ -49,7 +46,6 @@ def replacements(scope: dict[str, object]) -> list[dict[str, object]]:
|
|||||||
start_date=START_DATE,
|
start_date=START_DATE,
|
||||||
is_paused_upon_creation=False,
|
is_paused_upon_creation=False,
|
||||||
max_active_runs=1,
|
max_active_runs=1,
|
||||||
max_active_tasks=3,
|
|
||||||
template_searchpath=str(SQL_ROOT),
|
template_searchpath=str(SQL_ROOT),
|
||||||
tags=["dm"],
|
tags=["dm"],
|
||||||
)
|
)
|
||||||
@@ -70,7 +66,8 @@ def dm_transform():
|
|||||||
row = hook.get_first(query)
|
row = hook.get_first(query)
|
||||||
if row is None:
|
if row is None:
|
||||||
raise AirflowException(
|
raise AirflowException(
|
||||||
"нет слепка заказов в ODS или готовых заказов в DDS"
|
"нет слепка заказов в ODS или готовых заказов в DDS; "
|
||||||
|
"дождитесь загрузки слепка и сначала выполните dds_transform"
|
||||||
)
|
)
|
||||||
first_day, last_day = row
|
first_day, last_day = row
|
||||||
days = _days(first_day, last_day)
|
days = _days(first_day, last_day)
|
||||||
@@ -106,9 +103,10 @@ def dm_transform():
|
|||||||
conn_id=CLICKHOUSE_CONNECTION,
|
conn_id=CLICKHOUSE_CONNECTION,
|
||||||
sql="dm/revenue_daily_replace.sql",
|
sql="dm/revenue_daily_replace.sql",
|
||||||
do_xcom_push=False,
|
do_xcom_push=False,
|
||||||
# Каждая замена поднимает отдельный процесс работника. Три
|
# Airflow 3 применяет этот лимит и к размноженным экземплярам
|
||||||
# одновременные задачи выбили его по памяти на первом прогоне;
|
# (сверено через Context7). Каждая замена - отдельный процесс
|
||||||
# самим дням параллельность ничего не дает.
|
# LocalExecutor; три разом исчерпали память контейнера scheduler,
|
||||||
|
# а самим дням параллельность ничего не дает.
|
||||||
max_active_tis_per_dag=1,
|
max_active_tis_per_dag=1,
|
||||||
).expand_kwargs(replacements(days))
|
).expand_kwargs(replacements(days))
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ INSERT INTO dm.daily_traffic_dist
|
|||||||
SELECT
|
SELECT
|
||||||
sessions.session_date,
|
sessions.session_date,
|
||||||
uniqExact(sessions.client_id),
|
uniqExact(sessions.client_id),
|
||||||
|
-- При стендовом join_use_nulls=0 непарный UInt64 получает 0. Условие
|
||||||
|
-- не дает анонимной сессии превратиться в известного пользователя.
|
||||||
uniqExactIf(identities.user_id, identities.user_id != 0),
|
uniqExactIf(identities.user_id, identities.user_id != 0),
|
||||||
{load_id:String},
|
{load_id:String},
|
||||||
now64(3, 'UTC')
|
now64(3, 'UTC')
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
-- изменить. Сам агрегат читает только DDS; ODS здесь нужен лишь для границ.
|
-- изменить. Сам агрегат читает только DDS; ODS здесь нужен лишь для границ.
|
||||||
-- Первый запуск и повтор после частичного отказа расширяют левую границу до
|
-- Первый запуск и повтор после частичного отказа расширяют левую границу до
|
||||||
-- первого дня оплаченных заказов, которого еще нет в витрине.
|
-- первого дня оплаченных заказов, которого еще нет в витрине.
|
||||||
|
-- Почему хвост начинается с первого пропуска и чем за это платит ODS,
|
||||||
|
-- разобрано в sql/dds/order_scope.sql.
|
||||||
--
|
--
|
||||||
-- Файл кончается без точки с запятой: даг читает его одним запросом и ждет
|
-- Файл кончается без точки с запятой: даг читает его одним запросом и ждет
|
||||||
-- одну строку с границами.
|
-- одну строку с границами.
|
||||||
@@ -31,5 +33,7 @@ WITH
|
|||||||
SELECT
|
SELECT
|
||||||
least(window_start, coalesce(first_missing_day, window_start)) AS first_day,
|
least(window_start, coalesce(first_missing_day, window_start)) AS first_day,
|
||||||
window_end AS last_day
|
window_end AS last_day
|
||||||
|
-- Без ODS неизвестно окно. Без готового DDS донор останется пустым, а замена
|
||||||
|
-- сотрет уже собранные дни выручки. Поэтому для прогона нужны оба источника.
|
||||||
WHERE (SELECT count() FROM dds.order_v) > 0
|
WHERE (SELECT count() FROM dds.order_v) > 0
|
||||||
AND (SELECT count() FROM ods.order_dist) > 0
|
AND (SELECT count() FROM ods.order_dist) > 0
|
||||||
Reference in new issue
Block a user