docs(warehouse): упрощены объяснения витрин, сессий и пересчета
Зачем: читателю ступеней 1–4 нужно проследить выбор дней, расчет строки и публикацию результата без расшифровки метафор. Что: согласованы справочники DM, сессий, ETL и два раздела хранилища с комментариями шести SQL-примеров. Уточнены ограничения повторного запуска и выбора атрибутов при равном времени событий. Проверка: make lint, git diff --check, локальные Markdown-ссылки и якоря. SQL без комментариев совпадает; AST Python без строк документации совпадает. Исторические разделы и материалы вне границ задачи сохранены. Refs: #249
This commit is contained in:
1 parent
84dc718f62
commit
5f317ba8d2
11 files changed
+440
-490
No files matched your search
+15
-35
@@ -1,50 +1,30 @@
|
||||
-- DDS: объём пересборки сессий — какие дни собирает этот запуск.
|
||||
-- DDS: дни для сборки сессий, от first_day до last_day включительно.
|
||||
-- Пустой ответ означает пустой ODS; NULL в first_day — отсутствие работы.
|
||||
--
|
||||
-- Ответ — две даты, границы непрерывного отрезка; список дней между ними
|
||||
-- разворачивает даг. Пустой ответ означает пустой источник. Пустой первый
|
||||
-- день — что собирать нечего: все прожитые дни уже в слое, и прогон честно
|
||||
-- пропускает сборку.
|
||||
-- position — номер следующего дня для генерации. Последний прожитый день
|
||||
-- равен min(EventDate) + position - 1. В отличие от max(EventDate), эта
|
||||
-- граница исключает еще идущий день. Ранние события ODS не удаляются по TTL,
|
||||
-- поэтому min(EventDate) сохраняет начало модельного календаря.
|
||||
--
|
||||
-- Файл кончается без точки с запятой: почему — sql/dds/order_scope.sql.
|
||||
-- До этого запроса даг ждет чтения hits и опустошения очереди ods.event_dist.
|
||||
-- Позиция мира сама по себе не подтверждает доставку событий.
|
||||
--
|
||||
-- Правый край — последний прожитый день, и знает его только позиция мира.
|
||||
-- События живой день от прожитого не отличают: и посреди дня D, и сразу после
|
||||
-- его конца max(EventDate) = D. А разница несущая — визит, начатый в 23:50,
|
||||
-- посреди дня ещё идёт, и собранная сессия оказалась бы обрезанной навсегда:
|
||||
-- пересобирать замёрзший день слой не станет
|
||||
-- (docs/architecture/dds/session.md, «Движок и наполнение»).
|
||||
--
|
||||
-- Позиция — номер первого несыгранного дня, счётчик прожитого. Своей копии
|
||||
-- начала оси стенд из-за неё не заводит: начало он спрашивает у данных, и
|
||||
-- дата дня N в них — константа, начало оси плюс N. Держится якорь на том, что
|
||||
-- ранние дни из ods.event не исчезают: срок жизни назначен сырым данным и таблицам
|
||||
-- ошибок, самому событию — нет (sql/ddl/20-ods-tables.sql).
|
||||
--
|
||||
-- За «доехал» позиция не отвечает — только за «прожит». Перед расчётом объёма
|
||||
-- первый шаг дага дожидается хвоста потока и очереди доставки: иначе
|
||||
-- недожеванный хвост заморозил бы недособранный день
|
||||
-- (docs/architecture/etl.md, «Готовность источника»).
|
||||
-- Точки с запятой в конце нет: драйвер добавляет FORMAT к этому запросу.
|
||||
WITH
|
||||
(SELECT min(EventDate) FROM ods.event_dist) AS first_source_day,
|
||||
first_source_day + ({position:UInt16} - 1) AS last_lived_day,
|
||||
-- Хвост считается от первой дыры, а не от последнего собранного дня:
|
||||
-- замены партиций падают порознь, и счёт по максимуму собранного дня
|
||||
-- дыру позади себя не заметил бы (доводы целиком — sql/dds/order_scope.sql).
|
||||
-- У сессий это единственный способ дыру найти: дышащего окна, которое
|
||||
-- пересобрало бы день заодно, здесь нет.
|
||||
--
|
||||
-- GLOBAL обязателен: обе таблицы распределённые, и обычный NOT IN сверял
|
||||
-- бы дни источника с локальной частью слоя на каждом шарде.
|
||||
-- minOrNull отличает «дыр нет» от даты по умолчанию.
|
||||
-- Ищем первый день ODS, которого нет в DDS: максимум собранного дня
|
||||
-- пропустил бы более ранний пробел. Частично заполненный день так не найти.
|
||||
-- GLOBAL сравнивает со списком дней всего DDS, а не одного шарда.
|
||||
-- minOrNull возвращает NULL, если пропусков нет.
|
||||
(
|
||||
SELECT minOrNull(day)
|
||||
FROM (SELECT DISTINCT EventDate AS day FROM ods.event_dist)
|
||||
WHERE day GLOBAL NOT IN (SELECT session_date FROM dds.session_dist)
|
||||
) AS first_missing_day
|
||||
SELECT
|
||||
-- Живой день в слое отсутствует всегда, и работой это не считается:
|
||||
-- дырой он станет, только когда мир его проживёт.
|
||||
-- Отсутствующий день попадет в сборку только после его завершения.
|
||||
if(first_missing_day <= last_lived_day, first_missing_day, NULL) AS first_day,
|
||||
last_lived_day AS last_day
|
||||
-- FINAL не нужен: повтор доставки не двигает ни край оси, ни набор дней.
|
||||
-- FINAL не нужен: повтор доставки не меняет начало календаря и набор дат.
|
||||
WHERE (SELECT count() FROM ods.event_dist) > 0
|
||||
Reference in new issue
Block a user