docs(map): упрощен язык интерактивной карты хранилища

Зачем: помочь учащемуся понять назначение объектов и обработку данных по стрелкам карты.

Что: вычитаны карточки и подписи, пояснены термины, удалены повторы. Описания обработки уточнены по SQL, HTML пересобран.

Проверка: сохранены 17 объектов и 17 стрелок, проверены 85 ссылок. В Chromium проверены карточки, фильтры, подсветка, Escape и отображение при ширине 1920 и 1280 пикселей. make lint и git diff --cached --check прошли.
This commit is contained in:
ddadmin committed 2026-09-13 13:20:58 -04:00
1 parent 915e976fc2
commit f3373f1e8f
3 files changed
+309 -313

No files matched your search

+152 -154
View File
@@ -149,15 +149,14 @@
<script> <script>
const MAP = { const MAP = {
"title": "Карта слоев хранилища", "title": "Карта слоев хранилища",
"lead": "Проследите, как один смысл меняет имя и поверхность между слоями.", "lead": "Проследите путь событий и заказов от Kafka до отчетов.",
"chapter_url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/handbook/storage-layers.md#user-content-хранилище-и-его-слои", "chapter_url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/handbook/storage-layers.md#user-content-хранилище-и-его-слои",
"intro": [ "intro": [
"Эта карта показывает путь событий и заказов от Kafka до витрин DM.", "Выберите объект, чтобы узнать, что он хранит, как его читать и откуда в него поступают данные.",
"Щелкните по узлу, чтобы увидеть его назначение, устройство и ключи.", "Выберите стрелку, чтобы посмотреть способ обработки и открыть SQL-запрос.",
"Щелкните по стрелке, чтобы узнать, кто и каким запросом переносит данные.", "Для выбранного объекта подсвечиваются все пути, по которым данные поступают в него и используются дальше.",
"Когда вы выбираете узел, карта подсвечивает все пути к нему и от него.", "Кнопки «События» и «Заказы» выделяют нужный поток. Остальные объекты остаются на месте, но становятся бледнее.",
"Переключатель потока приглушает другую часть карты, но не меняет раскладку.", "Если вы впервые знакомитесь со слоями хранилища, начните с главы по ссылке ниже."
"Сначала прочитайте главу «Хранилище и его слои», затем вернитесь к карте и рассмотрите объекты."
], ],
"streams": { "streams": {
"all": "Все", "all": "Все",
@@ -166,39 +165,39 @@
}, },
"dictionary": { "dictionary": {
"title": "Словарь", "title": "Словарь",
"caption": "сбоку цепочки: справочники" "caption": "справочные данные"
}, },
"layers": [ "layers": [
{ {
"id": "kafka", "id": "kafka",
"title": "Kafka", "title": "Kafka",
"caption": "откуда приходит" "caption": "сообщения источников"
}, },
{ {
"id": "stg", "id": "stg",
"title": "STG", "title": "STG",
"caption": "как поступило" "caption": "исходные сообщения"
}, },
{ {
"id": "ods", "id": "ods",
"title": "ODS", "title": "ODS",
"caption": "язык источника" "caption": "данные разобраны по полям"
}, },
{ {
"id": "dds", "id": "dds",
"title": "DDS", "title": "DDS",
"caption": "язык бизнеса" "caption": "события, заказы и сессии"
}, },
{ {
"id": "dm", "id": "dm",
"title": "DM", "title": "DM",
"caption": "данные для дашбордов" "caption": "витрины для отчетов"
} }
], ],
"mechanisms": [ "mechanisms": [
{ {
"id": "materialized_view", "id": "materialized_view",
"label": "матвью", "label": "материализованное представление",
"line": "solid", "line": "solid",
"rhythm": "непрерывно, по мере прихода сообщений" "rhythm": "непрерывно, по мере прихода сообщений"
}, },
@@ -206,13 +205,13 @@
"id": "airflow_dag", "id": "airflow_dag",
"label": "даг Airflow", "label": "даг Airflow",
"line": "dashed", "line": "dashed",
"rhythm": "пачкой: раз в модельные сутки (`orders_ingest`) или на каждом прогоне конвейера" "rhythm": "пакетно: раз в модельные сутки (`orders_ingest`) или при каждом запуске конвейера"
}, },
{ {
"id": "view", "id": "view",
"label": "представление", "label": "представление",
"line": "dotted", "line": "dotted",
"rhythm": "без копии, данные читаются на месте" "rhythm": "при запросе к представлению, без копирования данных"
} }
], ],
"nodes": [ "nodes": [
@@ -225,9 +224,9 @@
"events" "events"
], ],
"what": "Топик Kafka с событиями кликстрима. Каждое сообщение содержит одно событие.", "what": "Топик Kafka с событиями кликстрима. Каждое сообщение содержит одно событие.",
"read": "Топик напрямую не читают: таблица `stg.hits_raw_kafka` забирает сообщения из топика. Для данных событий используйте `stg.hits_raw_dist`.", "read": "Для просмотра загруженных сообщений используйте `stg.hits_raw_dist`. Таблица `stg.hits_raw_kafka` служит для приема из топика.",
"fill": [ "fill": [
"Источник событий пишет сообщения в топик в темпе выбранного режима мира." "Генератор отправляет события без пауз в пакетном режиме или постепенно в живом режиме."
], ],
"links": [ "links": [
{ {
@@ -248,10 +247,10 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Топик Kafka со слепками заказов магазина. После модельного дня приходит снимок изменяемого окна.", "what": "Топик Kafka с дневными выгрузками заказов — слепками. Каждый слепок содержит состояние заказов за последние семь модельных дней.",
"read": "Топик напрямую не читают: таблица `stg.orders_raw_kafka` забирает сообщения из топика. Для заказов используйте `stg.orders_raw_dist`.", "read": "Для просмотра загруженных сообщений используйте `stg.orders_raw_dist`. Таблица `stg.orders_raw_kafka` служит для приема из топика.",
"fill": [ "fill": [
"Источник заказов публикует слепок пачкой после каждого модельного дня." "После генерации событий дня D источник отправляет слепок заказов за предыдущий день D−1."
], ],
"links": [ "links": [
{ {
@@ -272,17 +271,17 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Сырая строка события и метаданные доставки. STG сохраняет сообщение без разбора.", "what": "Исходное сообщение события и сведения о его доставке из Kafka. Содержимое сохраняется целой строкой, без разбора на поля.",
"read": "Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.", "read": "Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.",
"parts": [ "parts": [
"`stg.hits_raw_kafka` — чтец топика `hits`.", "`stg.hits_raw_kafka` — таблица для чтения сообщений топика `hits`.",
"`stg.hits_raw_rep` — реплицируемая таблица на шарде.", "`stg.hits_raw_rep` — реплицируемая таблица на шарде.",
"`stg.hits_raw_dist` — распределенная поверхность записи и чтения.", "`stg.hits_raw_dist` — распределенная таблица для записи и чтения.",
"`stg.hits_raw_mv` — матвью приема сообщений из чтеца." "`stg.hits_raw_mv` — материализованное представление, которое записывает сообщения из Kafka в STG."
], ],
"fill": [ "fill": [
"`stg.hits_raw_mv` пишет непрерывно, по мере прихода сообщений.", "`stg.hits_raw_mv` пишет непрерывно, по мере прихода сообщений.",
"Сырые строки живут трое суток реального времени плюс хвост до суток." "Строки хранятся не менее трех суток от загрузки. Удаление целыми частями таблицы добавляет до суток к этому сроку; оно выполняется при очередном слиянии по TTL."
], ],
"links": [ "links": [
{ {
@@ -294,7 +293,7 @@
"url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/10-stg-tables.sql" "url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/10-stg-tables.sql"
}, },
{ {
"label": "DDL матвью", "label": "DDL материализованного представления",
"url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql" "url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql"
} }
] ]
@@ -307,16 +306,16 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Сырые строки слепка заказов, метаданные доставки и идентификатор пачки `_load_id`.", "what": "Исходные строки выгрузки заказов, сведения о доставке и идентификатор загруженной партии `_load_id`.",
"read": "Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.", "read": "Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.",
"parts": [ "parts": [
"`stg.orders_raw_kafka` — чтец топика `orders` на первой ноде.", "`stg.orders_raw_kafka` — таблица для чтения топика `orders` на первом узле.",
"`stg.orders_raw_rep` — реплицируемая таблица на шарде.", "`stg.orders_raw_rep` — реплицируемая таблица на шарде.",
"`stg.orders_raw_dist` — распределенная поверхность записи и чтения." "`stg.orders_raw_dist` — распределенная таблица для записи и чтения."
], ],
"fill": [ "fill": [
"Задача `pull_batch` дага `orders_ingest` забирает слепок пачкой раз в модельные сутки.", "Задача `pull_batch` дага `orders_ingest` загружает слепок раз в модельные сутки.",
"Сырые строки живут трое суток реального времени плюс хвост до суток." "Строки хранятся не менее трех суток от загрузки. Удаление целыми частями таблицы добавляет до суток к этому сроку; оно выполняется при очередном слиянии по TTL."
], ],
"links": [ "links": [
{ {
@@ -337,13 +336,13 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Типизированное широкое событие с именами полей источника. Запрос представления с `FINAL` возвращает актуальную версию события.", "what": "События, разобранные на колонки с типами данных. Имена полей сохранены как в источнике.",
"read": "Читайте `ods.event_v`: запрос представления с `FINAL` возвращает актуальные строки вместо физических версий.", "read": "Читайте `ods.event_v`: представление использует `FINAL` и возвращает последнюю версию каждого события.",
"parts": [ "parts": [
"`ods.event_rep` — реплицируемая таблица версий события на шарде.", "`ods.event_rep` — реплицируемая таблица версий события на шарде.",
"`ods.event_dist` — распределенная поверхность записи и диагностики.", "`ods.event_dist` — распределенная таблица записи и диагностики.",
"`ods.event_v` — представление актуального состояния с `FINAL`.", "`ods.event_v` — представление актуального состояния с `FINAL`.",
"`ods.event_mv` — матвью разбора годных строк STG." "`ods.event_mv` — материализованное представление для разбора сообщений STG без ошибок."
], ],
"keys": [ "keys": [
"`WatchID` — тот же идентификатор, что `event_id` в DDS.", "`WatchID` — тот же идентификатор, что `event_id` в DDS.",
@@ -377,16 +376,16 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Сырые события, которые не прошли строгий прием, с классом ошибки и метаданными доставки.", "what": "Сообщения событий, которые не удалось разобрать по правилам ODS. Сохранены исходная строка, класс ошибки и сведения о доставке.",
"read": "Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.", "read": "Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.",
"parts": [ "parts": [
"`ods.event_errors_rep` — реплицируемая таблица ошибок на шарде.", "`ods.event_errors_rep` — реплицируемая таблица ошибок на шарде.",
"`ods.event_errors_dist` — распределенная поверхность чтения и записи.", "`ods.event_errors_dist` — распределенная таблица чтения и записи.",
"`ods.event_errors_mv` — матвью, которое отбирает негодные строки STG." "`ods.event_errors_mv` — материализованное представление для отбора сообщений STG с ошибками."
], ],
"fill": [ "fill": [
"`ods.event_errors_mv` пишет непрерывно, по мере записи в STG.", "`ods.event_errors_mv` пишет непрерывно, по мере записи в STG.",
"Ошибки живут один месяц и не останавливают прием годных событий." "Ошибки хранятся один месяц. Остальные события продолжают загружаться."
], ],
"links": [ "links": [
{ {
@@ -398,7 +397,7 @@
"url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/20-ods-tables.sql" "url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/20-ods-tables.sql"
}, },
{ {
"label": "DDL матвью", "label": "DDL материализованного представления",
"url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql" "url": "https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql"
} }
] ]
@@ -411,11 +410,11 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Текущая версия заказа на языке источника. Позиции пока остаются сырым фрагментом JSON.", "what": "Последняя загруженная версия заказа с именами полей из источника. Состав заказа пока хранится как фрагмент JSON.",
"read": "Читайте `ods.order_v`: запрос представления с `FINAL` возвращает последнюю версию по `snapshot_date`.", "read": "Читайте `ods.order_v`: запрос представления с `FINAL` возвращает последнюю версию по `snapshot_date`.",
"parts": [ "parts": [
"`ods.order_rep` — реплицируемая таблица версий заказа на шарде.", "`ods.order_rep` — реплицируемая таблица версий заказа на шарде.",
"`ods.order_dist` — распределенная поверхность записи и диагностики.", "`ods.order_dist` — распределенная таблица записи и диагностики.",
"`ods.order_v` — представление текущего состояния с `FINAL`." "`ods.order_v` — представление текущего состояния с `FINAL`."
], ],
"keys": [ "keys": [
@@ -423,7 +422,7 @@
"`user_id` — пользователь магазина, который переходит в заказ DDS." "`user_id` — пользователь магазина, который переходит в заказ DDS."
], ],
"fill": [ "fill": [
"Задача `parse_batch` дага `orders_ingest` разбирает пачку раз в модельные сутки.", "Задача `parse_batch` дага `orders_ingest` разбирает загруженный слепок раз в модельные сутки.",
"`ReplacingMergeTree(snapshot_date)` оставляет версию из последнего принятого слепка." "`ReplacingMergeTree(snapshot_date)` оставляет версию из последнего принятого слепка."
], ],
"links": [ "links": [
@@ -449,15 +448,15 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Сырые строки слепка, которые не прошли строгий прием, с классом ошибки и `_load_id`.", "what": "Строки выгрузки заказов, которые не удалось разобрать по правилам ODS. Сохранены исходная строка, класс ошибки и `_load_id`.",
"read": "Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.", "read": "Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.",
"parts": [ "parts": [
"`ods.order_errors_rep` — реплицируемая таблица ошибок на шарде.", "`ods.order_errors_rep` — реплицируемая таблица ошибок на шарде.",
"`ods.order_errors_dist` — распределенная поверхность чтения и записи." "`ods.order_errors_dist` — распределенная таблица чтения и записи."
], ],
"fill": [ "fill": [
"Задача `parse_batch` дага `orders_ingest` пишет ошибки из той же пачки, что и годные заказы.", "Задача `parse_batch` дага `orders_ingest` сохраняет строки с ошибками при разборе той же выгрузки, из которой загружаются заказы.",
"Ошибки живут один месяц и не останавливают прием годных заказов." "Ошибки хранятся один месяц. Остальные заказы продолжают загружаться."
], ],
"links": [ "links": [
{ {
@@ -478,8 +477,8 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Публичное представление события на языке бизнеса. Его запрос переименовывает поля и расшифровывает категорию устройства.", "what": "События с названиями полей, принятыми в DDS. Например, `WatchID` переименован в `event_id`, а числовой код устройства заменен названием категории.",
"read": "Читайте `dds.event_v`: запрос представления возвращает явный список колонок DDS.", "read": "Читайте `dds.event_v`: представление возвращает явно перечисленные колонки DDS.",
"parts": [ "parts": [
"`dds.event_v` — только представление над `ods.event_v`; своей таблицы в DDS нет." "`dds.event_v` — только представление над `ods.event_v`; своей таблицы в DDS нет."
], ],
@@ -490,7 +489,7 @@
"`purchase_id[1]` — тот же заказ, что `order_id` в DDS и DM." "`purchase_id[1]` — тот же заказ, что `order_id` в DDS и DM."
], ],
"fill": [ "fill": [
"Данные для `dds.event_v` читаются из актуальных событий ODS без копии и отдельного расписания." "При запросе к `dds.event_v` данные читаются из актуальных событий ODS. Отдельная загрузка в DDS не нужна."
], ],
"links": [ "links": [
{ {
@@ -511,22 +510,22 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Сессия, которую запрос дага `dds_transform` собирает из последовательных событий одной куки. В источнике готовой сессии нет.", "what": "Сессии, рассчитанные дагом `dds_transform` по событиям посетителя. Новая сессия начинается после паузы дольше 30 минут или при смене модельной даты.",
"read": "Читайте `dds.session_v`: запрос представления возвращает деловые и служебные колонки.", "read": "Читайте `dds.session_v`: здесь есть начало, конец, длительность сессии, показатели событий и служебные поля загрузки.",
"parts": [ "parts": [
"`dds.session_rep` — реплицируемая таблица сессий на шарде.", "`dds.session_rep` — реплицируемая таблица сессий на шарде.",
"`dds.session_dist` — распределенная поверхность загрузки и диагностики.", "`dds.session_dist` — распределенная таблица загрузки и диагностики.",
"`dds.session_stage_rep` — донор дневных партиций на шарде.", "`dds.session_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.",
"`dds.session_stage_dist` — распределенная поверхность донора.", "`dds.session_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.",
"`dds.session_v` — публичное представление." "`dds.session_v` — представление для чтения готовых данных."
], ],
"keys": [ "keys": [
"`client_id` — тот же посетитель, что в событии DDS и карте идентичностей.", "`client_id` — тот же посетитель, что в событии DDS и карте идентичностей.",
"`session_date` — день, который в `dm.daily_traffic_v` называется `report_date`." "`session_date` — день, который в `dm.daily_traffic_v` называется `report_date`."
], ],
"fill": [ "fill": [
"Даг `dds_transform` пересобирает данные прожитых дней при каждом прогоне конвейера.", "При каждом запуске `dds_transform` выбирает дни от первого пропущенного в DDS до последнего дня с завершенной генерацией.",
"Задачи `session.rebuild` и `session.replace` собирают день в доноре и заменяют партицию." "Задача `session.rebuild` рассчитывает данные в промежуточной таблице (доноре). `session.replace` заменяет ими дневные партиции основной таблицы."
], ],
"links": [ "links": [
{ {
@@ -551,14 +550,14 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Заказ в текущем состоянии на языке бизнеса. Артикулы, количества и цены позиций хранятся в согласованных массивах.", "what": "Последнее известное состояние заказа, подготовленное для анализа. Артикулы, количества и цены товаров хранятся в массивах; элементы с одинаковым индексом относятся к одной позиции заказа.",
"read": "Читайте `dds.order_v`: запрос представления возвращает данные без таблиц и донора партиций.", "read": "Читайте `dds.order_v`, чтобы получить готовые заказы из основной таблицы.",
"parts": [ "parts": [
"`dds.order_rep` — реплицируемая таблица заказов на шарде.", "`dds.order_rep` — реплицируемая таблица заказов на шарде.",
"`dds.order_dist` — распределенная поверхность загрузки и диагностики.", "`dds.order_dist` — распределенная таблица загрузки и диагностики.",
"`dds.order_stage_rep` — донор дневных партиций на шарде.", "`dds.order_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.",
"`dds.order_stage_dist` — распределенная поверхность донора.", "`dds.order_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.",
"`dds.order_v` — публичное представление." "`dds.order_v` — представление для чтения готовых данных."
], ],
"keys": [ "keys": [
"`order_id` — тот же заказ, что в ODS, событии покупки и витрине сверки.", "`order_id` — тот же заказ, что в ODS, событии покупки и витрине сверки.",
@@ -567,8 +566,8 @@
"`order_date` — день, который в витринах называется `report_date` или `order_day`." "`order_date` — день, который в витринах называется `report_date` или `order_day`."
], ],
"fill": [ "fill": [
"Даг `dds_transform` пересобирает изменяемое окно при каждом прогоне конвейера.", "При каждом запуске `dds_transform` пересчитывает дни заказов из последнего слепка и заполняет пропуски в DDS.",
"Задачи `order.rebuild` и `order.replace` собирают дни в доноре и заменяют партиции." "Задача `order.rebuild` рассчитывает данные в промежуточной таблице (доноре). `order.replace` заменяет ими дневные партиции основной таблицы."
], ],
"links": [ "links": [
{ {
@@ -594,20 +593,20 @@
"events", "events",
"orders" "orders"
], ],
"what": "Известные пары куки трекера и пользователя магазина. Связь появляется после сопоставленной покупки.", "what": "Связи между посетителем сайта и пользователем магазина. Они появляются, когда событие покупки сопоставлено с заказом по его номеру.",
"read": "Читайте `dds.identity_map_v`: запрос представления с `FINAL` возвращает актуальные строки полного пересчета.", "read": "Читайте `dds.identity_map_v`: представление с `FINAL` возвращает последнюю версию каждой пары посетителя и пользователя.",
"parts": [ "parts": [
"`dds.identity_map_rep` — реплицируемая таблица версий пар на шарде.", "`dds.identity_map_rep` — реплицируемая таблица версий пар на шарде.",
"`dds.identity_map_dist` — распределенная поверхность записи.", "`dds.identity_map_dist` — распределенная таблица записи.",
"`dds.identity_map_v` — точное публичное представление с `FINAL`." "`dds.identity_map_v` — представление последних версий строк с `FINAL`."
], ],
"keys": [ "keys": [
"`client_id` — кука из события и сессии DDS.", "`client_id` — идентификатор посетителя из cookie браузера, как в событии и сессии DDS.",
"`user_id` — пользователь магазина из заказа DDS." "`user_id` — пользователь магазина из заказа DDS."
], ],
"fill": [ "fill": [
"Задача `identity_map` дага `dds_transform` пересчитывает все известные пары после обновления заказов.", "Задача `identity_map` дага `dds_transform` пересчитывает все известные пары после обновления заказов.",
"Новая версия полного набора пишется при каждом прогоне; `FINAL` скрывает физические повторы." "При каждом запуске записывается новая версия набора связей."
], ],
"links": [ "links": [
{ {
@@ -632,19 +631,18 @@
"streams": [ "streams": [
"events" "events"
], ],
"what": "Дневные счетчики посетителей и известных пользователей после склейки идентичностей.", "what": "Число посетителей и известных пользователей за каждый день. Известными считаются пользователи магазина, связанные с посетителями сайта через карту идентичностей.",
"read": "Читайте `dm.daily_traffic_v`: запрос представления с `FINAL` возвращает актуальные строки полного пересчета.", "read": "Читайте `dm.daily_traffic_v`: представление с `FINAL` возвращает последний результат расчета за каждый день.",
"parts": [ "parts": [
"`dm.daily_traffic_rep` — реплицируемая таблица версий счетчиков.", "`dm.daily_traffic_rep` — реплицируемая таблица версий счетчиков.",
"`dm.daily_traffic_dist` — распределенная поверхность записи.", "`dm.daily_traffic_dist` — распределенная таблица записи.",
"`dm.daily_traffic_v` — точное публичное представление с `FINAL`." "`dm.daily_traffic_v` — представление последних версий строк с `FINAL`."
], ],
"keys": [ "keys": [
"`report_date` — тот же день, что `session_date` в сессии DDS." "`report_date` — тот же день, что `session_date` в сессии DDS."
], ],
"fill": [ "fill": [
"Задача `daily_traffic` дага `dm_transform` при каждом прогоне пересчитывает всю историю и записывает новую версию.", "Задача `daily_traffic` дага `dm_transform` при каждом запуске пересчитывает всю историю и записывает новую версию."
"`FINAL` оставляет текущую строку каждого дня."
], ],
"links": [ "links": [
{ {
@@ -669,22 +667,22 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Дневная выручка, число заказов и единиц товара по категориям.", "what": "Выручка, число заказов и единиц товара за день по категориям. В расчет входят оплаченные заказы.",
"read": "Читайте `dm.revenue_daily_v`: это публичное представление готовой дневной витрины.", "read": "Читайте `dm.revenue_daily_v`, чтобы получить готовые показатели по дням и категориям товаров.",
"parts": [ "parts": [
"`dm.revenue_daily_rep` — реплицируемая таблица витрины на шарде.", "`dm.revenue_daily_rep` — реплицируемая таблица витрины на шарде.",
"`dm.revenue_daily_dist` — распределенная поверхность загрузки.", "`dm.revenue_daily_dist` — распределенная таблица загрузки.",
"`dm.revenue_daily_stage_rep` — донор дневных партиций на шарде.", "`dm.revenue_daily_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.",
"`dm.revenue_daily_stage_dist` — распределенная поверхность донора.", "`dm.revenue_daily_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.",
"`dm.revenue_daily_v` — публичное представление." "`dm.revenue_daily_v` — представление для чтения готовых данных."
], ],
"keys": [ "keys": [
"`report_date` — тот же день, что `order_date` в заказе DDS.", "`report_date` — тот же день, что `order_date` в заказе DDS.",
"`product_category` — категория, найденная по `item_sku` заказа и ключу `sku` словаря." "`product_category` — категория, найденная по `item_sku` заказа и ключу `sku` словаря."
], ],
"fill": [ "fill": [
"Даг `dm_transform` пересобирает изменяемое окно заказов при каждом прогоне конвейера.", "При каждом запуске `dm_transform` пересчитывает дни заказов из последнего слепка и заполняет пропущенные дни витрины.",
"Задачи `revenue_daily.rebuild` и `revenue_daily.replace` собирают дни в доноре и заменяют партиции." "Задача `revenue_daily.rebuild` рассчитывает данные в промежуточной таблице (доноре). `revenue_daily.replace` заменяет ими дневные партиции витрины."
], ],
"links": [ "links": [
{ {
@@ -710,22 +708,22 @@
"events", "events",
"orders" "orders"
], ],
"what": "Сверка события покупки с заказом магазина. Одна строка показывает совпадение или класс расхождения.", "what": "Результат сверки покупок из кликстрима с заказами магазина. Для каждого номера заказа указано, совпали ли данные двух источников и какое расхождение найдено.",
"read": "Читайте `dm.purchase_vs_orders_v`: в результате запроса отсутствующей стороне соответствует `NULL`.", "read": "Читайте `dm.purchase_vs_orders_v`: если покупка или заказ отсутствует, поля этой стороны содержат `NULL`.",
"parts": [ "parts": [
"`dm.purchase_vs_orders_rep` — реплицируемая таблица сверки на шарде.", "`dm.purchase_vs_orders_rep` — реплицируемая таблица сверки на шарде.",
"`dm.purchase_vs_orders_dist` — распределенная поверхность загрузки.", "`dm.purchase_vs_orders_dist` — распределенная таблица загрузки.",
"`dm.purchase_vs_orders_stage_rep` — донор дневных партиций на шарде.", "`dm.purchase_vs_orders_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.",
"`dm.purchase_vs_orders_stage_dist` — распределенная поверхность донора.", "`dm.purchase_vs_orders_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.",
"`dm.purchase_vs_orders_v` — публичное представление." "`dm.purchase_vs_orders_v` — представление для чтения готовых данных."
], ],
"keys": [ "keys": [
"`order_id` — тот же заказ, что `purchase_id[1]` в событии и `order_id` в заказе DDS.", "`order_id` — тот же заказ, что `purchase_id[1]` в событии и `order_id` в заказе DDS.",
"`order_day` — общий день события покупки и заказа." "`order_day` — дата заказа; если заказа еще нет, берется дата события покупки."
], ],
"fill": [ "fill": [
"Даг `dm_transform` пересобирает изменяемый хвост обоих источников при каждом прогоне конвейера.", "При каждом запуске `dm_transform` пересчитывает дни последнего слепка, добавляет новые дни покупок, заполняет пропуски и повторяет сверку дней с покупками без заказа.",
"Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` собирают дни в доноре и заменяют партиции." "Задача `purchase_vs_orders.rebuild` рассчитывает данные в промежуточной таблице (доноре). `purchase_vs_orders.replace` заменяет ими дневные партиции витрины."
], ],
"links": [ "links": [
{ {
@@ -751,19 +749,19 @@
"events", "events",
"orders" "orders"
], ],
"what": "Текущее состояние пяти атомарных проверок качества по дням. История запусков остается в Airflow.", "what": "Последние результаты пяти проверок качества данных за каждый день. Историю запусков можно посмотреть в Airflow.",
"read": "Читайте `dm.dq_summary_v`: запрос к публичному представлению возвращает последнюю опубликованную сводку дня.", "read": "Читайте `dm.dq_summary_v`, чтобы увидеть результат каждой проверки за день.",
"parts": [ "parts": [
"`dm.dq_summary_rep` — реплицируемая таблица опубликованной сводки.", "`dm.dq_summary_rep` — реплицируемая таблица опубликованной сводки.",
"`dm.dq_summary_dist` — распределенная поверхность чтения и записи.", "`dm.dq_summary_dist` — распределенная таблица чтения и записи.",
"`dm.dq_summary_stage_rep` — общий донор дневных партиций.", "`dm.dq_summary_stage_rep` — промежуточная таблица для результатов всех проверок за день.",
"`dm.dq_summary_stage_dist` — распределенная поверхность донора.", "`dm.dq_summary_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.",
"`dm.dq_summary_v` — публичное представление." "`dm.dq_summary_v` — представление для чтения готовых данных."
], ],
"fill": [ "fill": [
"Даг `dq_check` при каждом прогоне сначала выполняет все пять проверок, затем заменяет готовые дневные партиции.", "Даг `dq_check` сначала рассчитывает результаты всех пяти проверок в промежуточной таблице, затем заменяет ими дневные партиции сводки.",
"`sessions_vs_reference` — `sql/dq/sessions_vs_reference.sql`.", "`sessions_vs_reference` — `sql/dq/sessions_vs_reference.sql`.",
"`classes_vs_inventory` — `sql/dq/classes_vs_inventory.sql` и паспорт мира.", "`classes_vs_inventory` — `sql/dq/classes_vs_inventory.sql` и эталонные числа из паспорта мира `data/world-inventory.json`.",
"`revenue_daily_vs_dds` — `sql/dq/revenue_daily_vs_dds.sql`.", "`revenue_daily_vs_dds` — `sql/dq/revenue_daily_vs_dds.sql`.",
"`purchase_vs_orders_vs_dds` — `sql/dq/purchase_vs_orders_vs_dds.sql`.", "`purchase_vs_orders_vs_dds` — `sql/dq/purchase_vs_orders_vs_dds.sql`.",
"`daily_traffic_vs_dds` — `sql/dq/daily_traffic_vs_dds.sql`." "`daily_traffic_vs_dds` — `sql/dq/daily_traffic_vs_dds.sql`."
@@ -791,17 +789,17 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"what": "Словарь товаров вне цепочки слоев. По артикулу доступны название, бренд, категория и цена.", "what": "Словарь товаров. По артикулу можно получить название, бренд, категорию и цену. Эти данные доступны для расчетов в разных слоях.",
"read": "Читайте `dic.products`: у словаря одна поверхность без суффикса.", "read": "Читайте `dic.products`: к словарю обращаются напрямую, суффикса `_v` у него нет.",
"parts": [ "parts": [
"`dic.products_file` — чтец CSV-каталога из файла репозитория.", "`dic.products_file` — таблица, которая читает каталог товаров из CSV-файла репозитория.",
"`dic.products` — словарь в памяти поверх подложки." "`dic.products` — словарь в памяти, загруженный из этой таблицы."
], ],
"keys": [ "keys": [
"`sku` — тот же артикул, что `item_sku` в позиции заказа DDS." "`sku` — тот же артикул, что `item_sku` в позиции заказа DDS."
], ],
"fill": [ "fill": [
"ClickHouse перечитывает подложку каждые 60–90 секунд по настройке `LIFETIME`." "ClickHouse обновляет словарь из `dic.products_file` каждые 60–90 секунд согласно настройке `LIFETIME`."
], ],
"links": [ "links": [
{ {
@@ -825,8 +823,8 @@
"events" "events"
], ],
"rhythm": "непрерывно, по мере прихода сообщений", "rhythm": "непрерывно, по мере прихода сообщений",
"actor": "Чтец `stg.hits_raw_kafka` и матвью `stg.hits_raw_mv`.", "actor": "Таблица `stg.hits_raw_kafka` и материализованное представление `stg.hits_raw_mv`.",
"join": "Соединения нет: сообщение кладется строкой целиком.", "join": "Каждое сообщение Kafka записывается целой строкой, без разбора на поля.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -847,8 +845,8 @@
"events" "events"
], ],
"rhythm": "непрерывно, по мере прихода сообщений", "rhythm": "непрерывно, по мере прихода сообщений",
"actor": "Матвью `ods.event_mv` разбирает годные строки.", "actor": "Материализованное представление `ods.event_mv` разбирает сообщения без ошибок.",
"join": "Соединения нет: матвью разбирает строку в колонки.", "join": "Материализованное представление разбирает сообщение из STG на колонки с нужными типами данных.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -869,8 +867,8 @@
"events" "events"
], ],
"rhythm": "непрерывно, по мере прихода сообщений", "rhythm": "непрерывно, по мере прихода сообщений",
"actor": "Матвью `ods.event_errors_mv` отбирает строки, которые не прошли строгий прием.", "actor": "Материализованное представление `ods.event_errors_mv` отбирает сообщения с ошибками.",
"join": "Соединения нет: негодная строка уходит целиком вместе с классом ошибки.", "join": "Сообщение, которое не удалось разобрать по правилам ODS, сохраняется целиком вместе с классом ошибки.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -890,9 +888,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, раз в модельные сутки", "rhythm": "одной выгрузкой, раз в модельные сутки",
"actor": "Задача `pull_batch` дага `orders_ingest` читает `stg.orders_raw_kafka`.", "actor": "Задача `pull_batch` дага `orders_ingest` читает `stg.orders_raw_kafka`.",
"join": "Соединения нет: сообщение слепка кладется целиком, пачка помечена `_load_id`.", "join": "Строки выгрузки сохраняются целиком. Общий `_load_id` позволяет найти все строки одной загрузки.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -912,9 +910,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, раз в модельные сутки", "rhythm": "одной выгрузкой, раз в модельные сутки",
"actor": "Задача `parse_batch` дага `orders_ingest` пишет годные версии заказа.", "actor": "Задача `parse_batch` дага `orders_ingest` записывает версии заказов без ошибок разбора.",
"join": "Соединения нет: строка разбирается в колонки, версия задается `snapshot_date`.", "join": "Строка разбирается на колонки заказа. Версия определяется датой слепка `snapshot_date`.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -934,9 +932,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, раз в модельные сутки", "rhythm": "одной выгрузкой, раз в модельные сутки",
"actor": "Задача `parse_batch` дага `orders_ingest` пишет негодные строки той же пачки.", "actor": "Задача `parse_batch` дага `orders_ingest` записывает строки с ошибками из загруженной выгрузки.",
"join": "Соединения нет: негодная строка пачки уходит целиком.", "join": "Строка с ошибкой сохраняется целиком вместе с классом ошибки и идентификатором загрузки.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -956,9 +954,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "без копии, данные читаются на месте", "rhythm": "при запросе к представлению, без копирования данных",
"actor": "Запрос `dds.event_v` читает данные из `ods.event_v` и переименовывает поля на языке бизнеса.", "actor": "Представление `dds.event_v` читает данные из `ods.event_v`.",
"join": "Соединения нет: представление переименовывает колонки той же строки.", "join": "Колонки события переименовываются по правилам DDS. Данные не копируются в отдельную таблицу.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -978,9 +976,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "пачкой, при каждом прогоне `dds_transform`", "rhythm": "при каждом запуске `dds_transform`",
"actor": "Задачи `session.rebuild` и `session.replace` дага `dds_transform`.", "actor": "Задачи `session.rebuild` и `session.replace` дага `dds_transform`.",
"join": "События одной `client_id` за `event_date` режутся по паузам; `session_id` - `cityHash64(client_id, min(event_time))`.", "join": "События одного `client_id` за день `event_date` упорядочиваются по времени. Пауза дольше 30 минут начинает новую сессию. Ее `session_id` рассчитывается как `cityHash64(client_id, min(event_time))`.",
"links": [ "links": [
{ {
"label": "SQL сборки", "label": "SQL сборки",
@@ -1004,9 +1002,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, при каждом прогоне `dds_transform`", "rhythm": "при каждом запуске `dds_transform`",
"actor": "Задачи `order.rebuild` и `order.replace` дага `dds_transform`.", "actor": "Задачи `order.rebuild` и `order.replace` дага `dds_transform`.",
"join": "Соединения нет: из заказа берутся поля и позиции, `order_date` выводится из `created_at`.", "join": "Поля заказа приводятся к типам DDS, а позиции из JSON разбираются в массивы. Дата `order_date` рассчитывается из `created_at`.",
"links": [ "links": [
{ {
"label": "SQL сборки", "label": "SQL сборки",
@@ -1030,9 +1028,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "пачкой, при каждом прогоне `dds_transform`", "rhythm": "при каждом запуске `dds_transform`",
"actor": "Задача `identity_map` дага `dds_transform` соединяет покупки с заказами.", "actor": "Задача `identity_map` дага `dds_transform` соединяет покупки с заказами.",
"join": "Строки покупки и заказа соединяются по `purchase_id[1] = order_id`.", "join": "Событие покупки соединяется с заказом по `purchase_id[1] = order_id`. В результате связываются посетитель сайта и пользователь магазина.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -1052,9 +1050,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, при каждом прогоне `dds_transform`", "rhythm": "при каждом запуске `dds_transform`",
"actor": "Задача `identity_map` дага `dds_transform` соединяет заказы с покупками.", "actor": "Задача `identity_map` дага `dds_transform` соединяет заказы с покупками.",
"join": "Строки заказа и покупки соединяются по `order_id = purchase_id[1]`; берется `user_id`.", "join": "Заказ соединяется с событием покупки по `order_id = purchase_id[1]`. Из заказа берется `user_id` пользователя магазина.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -1074,9 +1072,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Задача `daily_traffic` дага `dm_transform` считает посетителей по сессиям.", "actor": "Задача `daily_traffic` дага `dm_transform` считает посетителей по сессиям.",
"join": "Соединения нет: сессии группируются по `session_date`, который становится `report_date`.", "join": "К сессиям присоединяется карта идентичностей по `client_id`, затем данные группируются по `session_date`. Эта дата записывается в `report_date`.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -1096,9 +1094,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Задача `daily_traffic` дага `dm_transform` считает известных пользователей по `client_id`.", "actor": "Задача `daily_traffic` дага `dm_transform` считает известных пользователей по `client_id`.",
"join": "GLOBAL LEFT JOIN по `client_id`; сессии без пары остаются в витрине.", "join": "`GLOBAL LEFT JOIN` присоединяет карту идентичностей к сессиям по `client_id`. Сессии без известного пользователя тоже участвуют в расчете посетителей.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -1118,9 +1116,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Задачи `revenue_daily.rebuild` и `revenue_daily.replace` дага `dm_transform`.", "actor": "Задачи `revenue_daily.rebuild` и `revenue_daily.replace` дага `dm_transform`.",
"join": "Соединения таблиц нет: ARRAY JOIN раскрывает `item_sku`, `item_quantity`, `item_price`; `order_date` становится `report_date`.", "join": "`ARRAY JOIN` разворачивает массивы `item_sku`, `item_quantity`, `item_price` в строки позиций заказа. Выручка считается по оплаченным заказам; `order_date` записывается в `report_date`.",
"links": [ "links": [
{ {
"label": "SQL сборки", "label": "SQL сборки",
@@ -1144,9 +1142,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Даг `dm_transform` получает категорию через `dictGet` по `item_sku`; ключ словаря — `sku`.", "actor": "Задача `revenue_daily.rebuild` дага `dm_transform`.",
"join": "Категория читается через `dictGet` по `item_sku`; ключ справочника - `sku`.", "join": "Функция `dictGet` получает категорию товара по артикулу `item_sku` из заказа. В словаре этому артикулу соответствует ключ `sku`.",
"links": [ "links": [
{ {
"label": "SQL", "label": "SQL",
@@ -1166,9 +1164,9 @@
"streams": [ "streams": [
"events" "events"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают покупки.", "actor": "Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают покупки.",
"join": "Покупки группируются по `purchase_id[1]` как `purchase_order_id`; `event_date` становится `purchase_day`, затем GLOBAL FULL OUTER JOIN `purchase_order_id = backend_order_id`.", "join": "События покупки группируются по номеру `purchase_id[1]`, который получает имя `purchase_order_id`. Дата `event_date` записывается в `purchase_day`. Затем `GLOBAL FULL OUTER JOIN` сопоставляет покупки с заказами по `purchase_order_id = backend_order_id`.",
"links": [ "links": [
{ {
"label": "SQL сборки", "label": "SQL сборки",
@@ -1192,9 +1190,9 @@
"streams": [ "streams": [
"orders" "orders"
], ],
"rhythm": "пачкой, при каждом прогоне `dm_transform`", "rhythm": "при каждом запуске `dm_transform`",
"actor": "Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают заказы.", "actor": "Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают заказы.",
"join": "GLOBAL FULL OUTER JOIN: `purchase_order_id = backend_order_id` (`purchase_id[1]` и `order_id`); отсутствующая сторона получает NULL.", "join": "`order_id` заказа получает имя `backend_order_id`, а `purchase_id[1]` покупки — `purchase_order_id`. `GLOBAL FULL OUTER JOIN` соединяет их по `purchase_order_id = backend_order_id`. Покупки без заказа и заказы без покупки сохраняются; поля отсутствующей стороны содержат `NULL`.",
"links": [ "links": [
{ {
"label": "SQL сборки", "label": "SQL сборки",
@@ -1308,9 +1306,9 @@
details.append(heading, meta); details.append(heading, meta);
addSection("Что это", node.what); addSection("Что это", node.what);
addSection("Как читать", node.read); addSection("Как читать", node.read);
addSection("Из чего состоит", node.parts); addSection("Связанные таблицы и представления", node.parts);
addSection("Ключи", node.keys); addSection("Как связать данные", node.keys);
addSection("Кто наполняет и как часто", node.fill); addSection("Как обновляются данные", node.fill);
addLinks(node.links); addLinks(node.links);
} }
function renderEdgeCard(edge) { function renderEdgeCard(edge) {
@@ -1318,10 +1316,10 @@
const heading = document.createElement("h2"); const heading = document.createElement("h2");
heading.textContent = `${nodeById.get(edge.from).name} → ${nodeById.get(edge.to).name}`; heading.textContent = `${nodeById.get(edge.from).name} → ${nodeById.get(edge.to).name}`;
details.append(heading); details.append(heading);
addSection("Механизм", mechanismById.get(edge.mechanism).label); addSection("Способ обработки", mechanismById.get(edge.mechanism).label);
addSection("Ритм", edge.rhythm); addSection("Когда выполняется", edge.rhythm);
addSection("Кто именно", edge.actor); addSection("Что выполняет обработку", edge.actor);
addSection("Как соединяет", edge.join); addSection("Что происходит с данными", edge.join);
addLinks(edge.links); addLinks(edge.links);
} }
function layoutMap() { function layoutMap() {
+150 -152
View File
@@ -1,13 +1,12 @@
title: Карта слоев хранилища title: Карта слоев хранилища
lead: Проследите, как один смысл меняет имя и поверхность между слоями. lead: Проследите путь событий и заказов от Kafka до отчетов.
chapter_url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/handbook/storage-layers.md#user-content-хранилище-и-его-слои chapter_url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/handbook/storage-layers.md#user-content-хранилище-и-его-слои
intro: intro:
- Эта карта показывает путь событий и заказов от Kafka до витрин DM. - Выберите объект, чтобы узнать, что он хранит, как его читать и откуда в него поступают данные.
- Щелкните по узлу, чтобы увидеть его назначение, устройство и ключи. - Выберите стрелку, чтобы посмотреть способ обработки и открыть SQL-запрос.
- Щелкните по стрелке, чтобы узнать, кто и каким запросом переносит данные. - Для выбранного объекта подсвечиваются все пути, по которым данные поступают в него и используются дальше.
- Когда вы выбираете узел, карта подсвечивает все пути к нему и от него. - Кнопки «События» и «Заказы» выделяют нужный поток. Остальные объекты остаются на месте, но становятся бледнее.
- Переключатель потока приглушает другую часть карты, но не меняет раскладку. - Если вы впервые знакомитесь со слоями хранилища, начните с главы по ссылке ниже.
- Сначала прочитайте главу «Хранилище и его слои», затем вернитесь к карте и рассмотрите объекты.
streams: streams:
all: Все all: Все
@@ -16,38 +15,38 @@ streams:
dictionary: dictionary:
title: Словарь title: Словарь
caption: 'сбоку цепочки: справочники' caption: справочные данные
layers: layers:
- id: kafka - id: kafka
title: Kafka title: Kafka
caption: откуда приходит caption: сообщения источников
- id: stg - id: stg
title: STG title: STG
caption: как поступило caption: исходные сообщения
- id: ods - id: ods
title: ODS title: ODS
caption: язык источника caption: данные разобраны по полям
- id: dds - id: dds
title: DDS title: DDS
caption: язык бизнеса caption: события, заказы и сессии
- id: dm - id: dm
title: DM title: DM
caption: данные для дашбордов caption: витрины для отчетов
mechanisms: mechanisms:
- id: materialized_view - id: materialized_view
label: матвью label: материализованное представление
line: solid line: solid
rhythm: непрерывно, по мере прихода сообщений rhythm: непрерывно, по мере прихода сообщений
- id: airflow_dag - id: airflow_dag
label: даг Airflow label: даг Airflow
line: dashed line: dashed
rhythm: 'пачкой: раз в модельные сутки (`orders_ingest`) или на каждом прогоне конвейера' rhythm: 'пакетно: раз в модельные сутки (`orders_ingest`) или при каждом запуске конвейера'
- id: view - id: view
label: представление label: представление
line: dotted line: dotted
rhythm: без копии, данные читаются на месте rhythm: при запросе к представлению, без копирования данных
nodes: nodes:
- id: kafka_hits - id: kafka_hits
@@ -56,9 +55,9 @@ nodes:
order: 0 order: 0
streams: [events] streams: [events]
what: Топик Kafka с событиями кликстрима. Каждое сообщение содержит одно событие. what: Топик Kafka с событиями кликстрима. Каждое сообщение содержит одно событие.
read: 'Топик напрямую не читают: таблица `stg.hits_raw_kafka` забирает сообщения из топика. Для данных событий используйте `stg.hits_raw_dist`.' read: "Для просмотра загруженных сообщений используйте `stg.hits_raw_dist`. Таблица `stg.hits_raw_kafka` служит для приема из топика."
fill: fill:
- Источник событий пишет сообщения в топик в темпе выбранного режима мира. - "Генератор отправляет события без пауз в пакетном режиме или постепенно в живом режиме."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-при%D1%91м-поток-и-его-свойства url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-при%D1%91м-поток-и-его-свойства
@@ -70,10 +69,10 @@ nodes:
layer: kafka layer: kafka
order: 1 order: 1
streams: [orders] streams: [orders]
what: Топик Kafka со слепками заказов магазина. После модельного дня приходит снимок изменяемого окна. what: "Топик Kafka с дневными выгрузками заказов — слепками. Каждый слепок содержит состояние заказов за последние семь модельных дней."
read: 'Топик напрямую не читают: таблица `stg.orders_raw_kafka` забирает сообщения из топика. Для заказов используйте `stg.orders_raw_dist`.' read: "Для просмотра загруженных сообщений используйте `stg.orders_raw_dist`. Таблица `stg.orders_raw_kafka` служит для приема из топика."
fill: fill:
- Источник заказов публикует слепок пачкой после каждого модельного дня. - "После генерации событий дня D источник отправляет слепок заказов за предыдущий день D−1."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/orders/ingestion.md#user-content-поток-данных url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/orders/ingestion.md#user-content-поток-данных
@@ -85,22 +84,22 @@ nodes:
layer: stg layer: stg
order: 0 order: 0
streams: [events] streams: [events]
what: Сырая строка события и метаданные доставки. STG сохраняет сообщение без разбора. what: "Исходное сообщение события и сведения о его доставке из Kafka. Содержимое сохраняется целой строкой, без разбора на поля."
read: 'Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.' read: 'Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.'
parts: parts:
- '`stg.hits_raw_kafka` — чтец топика `hits`.' - "`stg.hits_raw_kafka` — таблица для чтения сообщений топика `hits`."
- '`stg.hits_raw_rep` — реплицируемая таблица на шарде.' - "`stg.hits_raw_rep` — реплицируемая таблица на шарде."
- '`stg.hits_raw_dist` — распределенная поверхность записи и чтения.' - "`stg.hits_raw_dist` — распределенная таблица для записи и чтения."
- '`stg.hits_raw_mv` — матвью приема сообщений из чтеца.' - "`stg.hits_raw_mv` — материализованное представление, которое записывает сообщения из Kafka в STG."
fill: fill:
- '`stg.hits_raw_mv` пишет непрерывно, по мере прихода сообщений.' - '`stg.hits_raw_mv` пишет непрерывно, по мере прихода сообщений.'
- Сырые строки живут трое суток реального времени плюс хвост до суток. - Строки хранятся не менее трех суток от загрузки. Удаление целыми частями таблицы добавляет до суток к этому сроку; оно выполняется при очередном слиянии по TTL.
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-при%D1%91м-поток-и-его-свойства url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-при%D1%91м-поток-и-его-свойства
- label: DDL таблиц - label: DDL таблиц
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/10-stg-tables.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/10-stg-tables.sql
- label: DDL матвью - label: DDL материализованного представления
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql
- id: stg_orders - id: stg_orders
@@ -108,15 +107,15 @@ nodes:
layer: stg layer: stg
order: 1 order: 1
streams: [orders] streams: [orders]
what: Сырые строки слепка заказов, метаданные доставки и идентификатор пачки `_load_id`. what: "Исходные строки выгрузки заказов, сведения о доставке и идентификатор загруженной партии `_load_id`."
read: 'Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.' read: 'Читайте `_dist`: у STG нет представления `_v`, а распределенная таблица показывает оба шарда.'
parts: parts:
- '`stg.orders_raw_kafka` — чтец топика `orders` на первой ноде.' - "`stg.orders_raw_kafka` — таблица для чтения топика `orders` на первом узле."
- '`stg.orders_raw_rep` — реплицируемая таблица на шарде.' - "`stg.orders_raw_rep` — реплицируемая таблица на шарде."
- '`stg.orders_raw_dist` — распределенная поверхность записи и чтения.' - "`stg.orders_raw_dist` — распределенная таблица для записи и чтения."
fill: fill:
- Задача `pull_batch` дага `orders_ingest` забирает слепок пачкой раз в модельные сутки. - Задача `pull_batch` дага `orders_ingest` загружает слепок раз в модельные сутки.
- Сырые строки живут трое суток реального времени плюс хвост до суток. - Строки хранятся не менее трех суток от загрузки. Удаление целыми частями таблицы добавляет до суток к этому сроку; оно выполняется при очередном слиянии по TTL.
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/orders/ingestion.md#user-content-поток-данных url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/orders/ingestion.md#user-content-поток-данных
@@ -128,13 +127,13 @@ nodes:
layer: ods layer: ods
order: 0 order: 0
streams: [events] streams: [events]
what: Типизированное широкое событие с именами полей источника. Запрос представления с `FINAL` возвращает актуальную версию события. what: "События, разобранные на колонки с типами данных. Имена полей сохранены как в источнике."
read: 'Читайте `ods.event_v`: запрос представления с `FINAL` возвращает актуальные строки вместо физических версий.' read: "Читайте `ods.event_v`: представление использует `FINAL` и возвращает последнюю версию каждого события."
parts: parts:
- '`ods.event_rep` — реплицируемая таблица версий события на шарде.' - '`ods.event_rep` — реплицируемая таблица версий события на шарде.'
- '`ods.event_dist` — распределенная поверхность записи и диагностики.' - '`ods.event_dist` — распределенная таблица записи и диагностики.'
- '`ods.event_v` — представление актуального состояния с `FINAL`.' - '`ods.event_v` — представление актуального состояния с `FINAL`.'
- '`ods.event_mv` — матвью разбора годных строк STG.' - '`ods.event_mv` — материализованное представление для разбора сообщений STG без ошибок.'
keys: keys:
- '`WatchID` — тот же идентификатор, что `event_id` в DDS.' - '`WatchID` — тот же идентификатор, что `event_id` в DDS.'
- '`ClientID` — тот же посетитель, что `client_id` в DDS.' - '`ClientID` — тот же посетитель, что `client_id` в DDS.'
@@ -155,21 +154,21 @@ nodes:
layer: ods layer: ods
order: 1 order: 1
streams: [events] streams: [events]
what: Сырые события, которые не прошли строгий прием, с классом ошибки и метаданными доставки. what: "Сообщения событий, которые не удалось разобрать по правилам ODS. Сохранены исходная строка, класс ошибки и сведения о доставке."
read: 'Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.' read: 'Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.'
parts: parts:
- '`ods.event_errors_rep` — реплицируемая таблица ошибок на шарде.' - '`ods.event_errors_rep` — реплицируемая таблица ошибок на шарде.'
- '`ods.event_errors_dist` — распределенная поверхность чтения и записи.' - '`ods.event_errors_dist` — распределенная таблица чтения и записи.'
- '`ods.event_errors_mv` — матвью, которое отбирает негодные строки STG.' - '`ods.event_errors_mv` — материализованное представление для отбора сообщений STG с ошибками.'
fill: fill:
- '`ods.event_errors_mv` пишет непрерывно, по мере записи в STG.' - '`ods.event_errors_mv` пишет непрерывно, по мере записи в STG.'
- Ошибки живут один месяц и не останавливают прием годных событий. - Ошибки хранятся один месяц. Остальные события продолжают загружаться.
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-таблица-ошибок url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-таблица-ошибок
- label: DDL таблиц - label: DDL таблиц
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/20-ods-tables.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/20-ods-tables.sql
- label: DDL матвью - label: DDL материализованного представления
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql
- id: ods_order - id: ods_order
@@ -177,17 +176,17 @@ nodes:
layer: ods layer: ods
order: 2 order: 2
streams: [orders] streams: [orders]
what: Текущая версия заказа на языке источника. Позиции пока остаются сырым фрагментом JSON. what: "Последняя загруженная версия заказа с именами полей из источника. Состав заказа пока хранится как фрагмент JSON."
read: 'Читайте `ods.order_v`: запрос представления с `FINAL` возвращает последнюю версию по `snapshot_date`.' read: 'Читайте `ods.order_v`: запрос представления с `FINAL` возвращает последнюю версию по `snapshot_date`.'
parts: parts:
- '`ods.order_rep` — реплицируемая таблица версий заказа на шарде.' - '`ods.order_rep` — реплицируемая таблица версий заказа на шарде.'
- '`ods.order_dist` — распределенная поверхность записи и диагностики.' - '`ods.order_dist` — распределенная таблица записи и диагностики.'
- '`ods.order_v` — представление текущего состояния с `FINAL`.' - '`ods.order_v` — представление текущего состояния с `FINAL`.'
keys: keys:
- '`order_id` — тот же заказ в `dds.order_v` и `dm.purchase_vs_orders_v`.' - '`order_id` — тот же заказ в `dds.order_v` и `dm.purchase_vs_orders_v`.'
- '`user_id` — пользователь магазина, который переходит в заказ DDS.' - '`user_id` — пользователь магазина, который переходит в заказ DDS.'
fill: fill:
- Задача `parse_batch` дага `orders_ingest` разбирает пачку раз в модельные сутки. - Задача `parse_batch` дага `orders_ingest` разбирает загруженный слепок раз в модельные сутки.
- '`ReplacingMergeTree(snapshot_date)` оставляет версию из последнего принятого слепка.' - '`ReplacingMergeTree(snapshot_date)` оставляет версию из последнего принятого слепка.'
links: links:
- label: Справочник - label: Справочник
@@ -202,14 +201,14 @@ nodes:
layer: ods layer: ods
order: 3 order: 3
streams: [orders] streams: [orders]
what: Сырые строки слепка, которые не прошли строгий прием, с классом ошибки и `_load_id`. what: "Строки выгрузки заказов, которые не удалось разобрать по правилам ODS. Сохранены исходная строка, класс ошибки и `_load_id`."
read: 'Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.' read: 'Читайте `_dist`: представления `_v` нет, а распределенная таблица показывает ошибки с обоих шардов.'
parts: parts:
- '`ods.order_errors_rep` — реплицируемая таблица ошибок на шарде.' - '`ods.order_errors_rep` — реплицируемая таблица ошибок на шарде.'
- '`ods.order_errors_dist` — распределенная поверхность чтения и записи.' - '`ods.order_errors_dist` — распределенная таблица чтения и записи.'
fill: fill:
- Задача `parse_batch` дага `orders_ingest` пишет ошибки из той же пачки, что и годные заказы. - Задача `parse_batch` дага `orders_ingest` сохраняет строки с ошибками при разборе той же выгрузки, из которой загружаются заказы.
- Ошибки живут один месяц и не останавливают прием годных заказов. - Ошибки хранятся один месяц. Остальные заказы продолжают загружаться.
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-таблица-ошибок url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-таблица-ошибок
@@ -221,8 +220,8 @@ nodes:
layer: dds layer: dds
order: 0 order: 0
streams: [events] streams: [events]
what: Публичное представление события на языке бизнеса. Его запрос переименовывает поля и расшифровывает категорию устройства. what: "События с названиями полей, принятыми в DDS. Например, `WatchID` переименован в `event_id`, а числовой код устройства заменен названием категории."
read: 'Читайте `dds.event_v`: запрос представления возвращает явный список колонок DDS.' read: "Читайте `dds.event_v`: представление возвращает явно перечисленные колонки DDS."
parts: parts:
- '`dds.event_v` — только представление над `ods.event_v`; своей таблицы в DDS нет.' - '`dds.event_v` — только представление над `ods.event_v`; своей таблицы в DDS нет.'
keys: keys:
@@ -231,7 +230,7 @@ nodes:
- '`event_date` — тот же день, что `EventDate` в ODS.' - '`event_date` — тот же день, что `EventDate` в ODS.'
- '`purchase_id[1]` — тот же заказ, что `order_id` в DDS и DM.' - '`purchase_id[1]` — тот же заказ, что `order_id` в DDS и DM.'
fill: fill:
- Данные для `dds.event_v` читаются из актуальных событий ODS без копии и отдельного расписания. - "При запросе к `dds.event_v` данные читаются из актуальных событий ODS. Отдельная загрузка в DDS не нужна."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/event.md#user-content-форма url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/event.md#user-content-форма
@@ -243,20 +242,20 @@ nodes:
layer: dds layer: dds
order: 1 order: 1
streams: [events] streams: [events]
what: Сессия, которую запрос дага `dds_transform` собирает из последовательных событий одной куки. В источнике готовой сессии нет. what: "Сессии, рассчитанные дагом `dds_transform` по событиям посетителя. Новая сессия начинается после паузы дольше 30 минут или при смене модельной даты."
read: 'Читайте `dds.session_v`: запрос представления возвращает деловые и служебные колонки.' read: "Читайте `dds.session_v`: здесь есть начало, конец, длительность сессии, показатели событий и служебные поля загрузки."
parts: parts:
- '`dds.session_rep` — реплицируемая таблица сессий на шарде.' - '`dds.session_rep` — реплицируемая таблица сессий на шарде.'
- '`dds.session_dist` — распределенная поверхность загрузки и диагностики.' - '`dds.session_dist` — распределенная таблица загрузки и диагностики.'
- '`dds.session_stage_rep` — донор дневных партиций на шарде.' - '`dds.session_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.'
- '`dds.session_stage_dist` — распределенная поверхность донора.' - '`dds.session_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.'
- '`dds.session_v` — публичное представление.' - '`dds.session_v` — представление для чтения готовых данных.'
keys: keys:
- '`client_id` — тот же посетитель, что в событии DDS и карте идентичностей.' - '`client_id` — тот же посетитель, что в событии DDS и карте идентичностей.'
- '`session_date` — день, который в `dm.daily_traffic_v` называется `report_date`.' - '`session_date` — день, который в `dm.daily_traffic_v` называется `report_date`.'
fill: fill:
- Даг `dds_transform` пересобирает данные прожитых дней при каждом прогоне конвейера. - "При каждом запуске `dds_transform` выбирает дни от первого пропущенного в DDS до последнего дня с завершенной генерацией."
- Задачи `session.rebuild` и `session.replace` собирают день в доноре и заменяют партицию. - "Задача `session.rebuild` рассчитывает данные в промежуточной таблице (доноре). `session.replace` заменяет ими дневные партиции основной таблицы."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/session.md#user-content-движок-и-наполнение url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/session.md#user-content-движок-и-наполнение
@@ -270,22 +269,22 @@ nodes:
layer: dds layer: dds
order: 2 order: 2
streams: [orders] streams: [orders]
what: Заказ в текущем состоянии на языке бизнеса. Артикулы, количества и цены позиций хранятся в согласованных массивах. what: "Последнее известное состояние заказа, подготовленное для анализа. Артикулы, количества и цены товаров хранятся в массивах; элементы с одинаковым индексом относятся к одной позиции заказа."
read: 'Читайте `dds.order_v`: запрос представления возвращает данные без таблиц и донора партиций.' read: "Читайте `dds.order_v`, чтобы получить готовые заказы из основной таблицы."
parts: parts:
- '`dds.order_rep` — реплицируемая таблица заказов на шарде.' - '`dds.order_rep` — реплицируемая таблица заказов на шарде.'
- '`dds.order_dist` — распределенная поверхность загрузки и диагностики.' - '`dds.order_dist` — распределенная таблица загрузки и диагностики.'
- '`dds.order_stage_rep` — донор дневных партиций на шарде.' - '`dds.order_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.'
- '`dds.order_stage_dist` — распределенная поверхность донора.' - '`dds.order_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.'
- '`dds.order_v` — публичное представление.' - '`dds.order_v` — представление для чтения готовых данных.'
keys: keys:
- '`order_id` — тот же заказ, что в ODS, событии покупки и витрине сверки.' - '`order_id` — тот же заказ, что в ODS, событии покупки и витрине сверки.'
- '`user_id` — пользователь магазина, который входит в карту идентичностей.' - '`user_id` — пользователь магазина, который входит в карту идентичностей.'
- '`item_sku` — тот же артикул, что `sku` в `dic.products`.' - '`item_sku` — тот же артикул, что `sku` в `dic.products`.'
- '`order_date` — день, который в витринах называется `report_date` или `order_day`.' - '`order_date` — день, который в витринах называется `report_date` или `order_day`.'
fill: fill:
- Даг `dds_transform` пересобирает изменяемое окно при каждом прогоне конвейера. - "При каждом запуске `dds_transform` пересчитывает дни заказов из последнего слепка и заполняет пропуски в DDS."
- Задачи `order.rebuild` и `order.replace` собирают дни в доноре и заменяют партиции. - "Задача `order.rebuild` рассчитывает данные в промежуточной таблице (доноре). `order.replace` заменяет ими дневные партиции основной таблицы."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/order.md#user-content-движок-и-наполнение url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/order.md#user-content-движок-и-наполнение
@@ -299,18 +298,18 @@ nodes:
layer: dds layer: dds
order: 3 order: 3
streams: [events, orders] streams: [events, orders]
what: Известные пары куки трекера и пользователя магазина. Связь появляется после сопоставленной покупки. what: "Связи между посетителем сайта и пользователем магазина. Они появляются, когда событие покупки сопоставлено с заказом по его номеру."
read: 'Читайте `dds.identity_map_v`: запрос представления с `FINAL` возвращает актуальные строки полного пересчета.' read: "Читайте `dds.identity_map_v`: представление с `FINAL` возвращает последнюю версию каждой пары посетителя и пользователя."
parts: parts:
- '`dds.identity_map_rep` — реплицируемая таблица версий пар на шарде.' - '`dds.identity_map_rep` — реплицируемая таблица версий пар на шарде.'
- '`dds.identity_map_dist` — распределенная поверхность записи.' - '`dds.identity_map_dist` — распределенная таблица записи.'
- '`dds.identity_map_v` — точное публичное представление с `FINAL`.' - '`dds.identity_map_v` — представление последних версий строк с `FINAL`.'
keys: keys:
- '`client_id` — кука из события и сессии DDS.' - "`client_id` — идентификатор посетителя из cookie браузера, как в событии и сессии DDS."
- '`user_id` — пользователь магазина из заказа DDS.' - "`user_id` — пользователь магазина из заказа DDS."
fill: fill:
- Задача `identity_map` дага `dds_transform` пересчитывает все известные пары после обновления заказов. - "Задача `identity_map` дага `dds_transform` пересчитывает все известные пары после обновления заказов."
- Новая версия полного набора пишется при каждом прогоне; `FINAL` скрывает физические повторы. - "При каждом запуске записывается новая версия набора связей."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/identity.md#user-content-сборка url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dds/identity.md#user-content-сборка
@@ -324,17 +323,16 @@ nodes:
layer: dm layer: dm
order: 0 order: 0
streams: [events] streams: [events]
what: Дневные счетчики посетителей и известных пользователей после склейки идентичностей. what: "Число посетителей и известных пользователей за каждый день. Известными считаются пользователи магазина, связанные с посетителями сайта через карту идентичностей."
read: 'Читайте `dm.daily_traffic_v`: запрос представления с `FINAL` возвращает актуальные строки полного пересчета.' read: "Читайте `dm.daily_traffic_v`: представление с `FINAL` возвращает последний результат расчета за каждый день."
parts: parts:
- '`dm.daily_traffic_rep` — реплицируемая таблица версий счетчиков.' - '`dm.daily_traffic_rep` — реплицируемая таблица версий счетчиков.'
- '`dm.daily_traffic_dist` — распределенная поверхность записи.' - '`dm.daily_traffic_dist` — распределенная таблица записи.'
- '`dm.daily_traffic_v` — точное публичное представление с `FINAL`.' - '`dm.daily_traffic_v` — представление последних версий строк с `FINAL`.'
keys: keys:
- '`report_date` — тот же день, что `session_date` в сессии DDS.' - '`report_date` — тот же день, что `session_date` в сессии DDS.'
fill: fill:
- Задача `daily_traffic` дага `dm_transform` при каждом прогоне пересчитывает всю историю и записывает новую версию. - "Задача `daily_traffic` дага `dm_transform` при каждом запуске пересчитывает всю историю и записывает новую версию."
- '`FINAL` оставляет текущую строку каждого дня.'
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmdaily_traffic_v url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmdaily_traffic_v
@@ -348,20 +346,20 @@ nodes:
layer: dm layer: dm
order: 1 order: 1
streams: [orders] streams: [orders]
what: Дневная выручка, число заказов и единиц товара по категориям. what: "Выручка, число заказов и единиц товара за день по категориям. В расчет входят оплаченные заказы."
read: 'Читайте `dm.revenue_daily_v`: это публичное представление готовой дневной витрины.' read: "Читайте `dm.revenue_daily_v`, чтобы получить готовые показатели по дням и категориям товаров."
parts: parts:
- '`dm.revenue_daily_rep` — реплицируемая таблица витрины на шарде.' - '`dm.revenue_daily_rep` — реплицируемая таблица витрины на шарде.'
- '`dm.revenue_daily_dist` — распределенная поверхность загрузки.' - '`dm.revenue_daily_dist` — распределенная таблица загрузки.'
- '`dm.revenue_daily_stage_rep` — донор дневных партиций на шарде.' - '`dm.revenue_daily_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.'
- '`dm.revenue_daily_stage_dist` — распределенная поверхность донора.' - '`dm.revenue_daily_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.'
- '`dm.revenue_daily_v` — публичное представление.' - '`dm.revenue_daily_v` — представление для чтения готовых данных.'
keys: keys:
- '`report_date` — тот же день, что `order_date` в заказе DDS.' - '`report_date` — тот же день, что `order_date` в заказе DDS.'
- '`product_category` — категория, найденная по `item_sku` заказа и ключу `sku` словаря.' - '`product_category` — категория, найденная по `item_sku` заказа и ключу `sku` словаря.'
fill: fill:
- Даг `dm_transform` пересобирает изменяемое окно заказов при каждом прогоне конвейера. - "При каждом запуске `dm_transform` пересчитывает дни заказов из последнего слепка и заполняет пропущенные дни витрины."
- Задачи `revenue_daily.rebuild` и `revenue_daily.replace` собирают дни в доноре и заменяют партиции. - "Задача `revenue_daily.rebuild` рассчитывает данные в промежуточной таблице (доноре). `revenue_daily.replace` заменяет ими дневные партиции витрины."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmrevenue_daily_v url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmrevenue_daily_v
@@ -375,20 +373,20 @@ nodes:
layer: dm layer: dm
order: 2 order: 2
streams: [events, orders] streams: [events, orders]
what: Сверка события покупки с заказом магазина. Одна строка показывает совпадение или класс расхождения. what: "Результат сверки покупок из кликстрима с заказами магазина. Для каждого номера заказа указано, совпали ли данные двух источников и какое расхождение найдено."
read: 'Читайте `dm.purchase_vs_orders_v`: в результате запроса отсутствующей стороне соответствует `NULL`.' read: "Читайте `dm.purchase_vs_orders_v`: если покупка или заказ отсутствует, поля этой стороны содержат `NULL`."
parts: parts:
- '`dm.purchase_vs_orders_rep` — реплицируемая таблица сверки на шарде.' - '`dm.purchase_vs_orders_rep` — реплицируемая таблица сверки на шарде.'
- '`dm.purchase_vs_orders_dist` — распределенная поверхность загрузки.' - '`dm.purchase_vs_orders_dist` — распределенная таблица загрузки.'
- '`dm.purchase_vs_orders_stage_rep` — донор дневных партиций на шарде.' - '`dm.purchase_vs_orders_stage_rep` — промежуточная таблица для пересчета данных по дням на шарде.'
- '`dm.purchase_vs_orders_stage_dist` — распределенная поверхность донора.' - '`dm.purchase_vs_orders_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.'
- '`dm.purchase_vs_orders_v` — публичное представление.' - '`dm.purchase_vs_orders_v` — представление для чтения готовых данных.'
keys: keys:
- '`order_id` — тот же заказ, что `purchase_id[1]` в событии и `order_id` в заказе DDS.' - "`order_id` — тот же заказ, что `purchase_id[1]` в событии и `order_id` в заказе DDS."
- '`order_day` — общий день события покупки и заказа.' - "`order_day` — дата заказа; если заказа еще нет, берется дата события покупки."
fill: fill:
- Даг `dm_transform` пересобирает изменяемый хвост обоих источников при каждом прогоне конвейера. - "При каждом запуске `dm_transform` пересчитывает дни последнего слепка, добавляет новые дни покупок, заполняет пропуски и повторяет сверку дней с покупками без заказа."
- Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` собирают дни в доноре и заменяют партиции. - "Задача `purchase_vs_orders.rebuild` рассчитывает данные в промежуточной таблице (доноре). `purchase_vs_orders.replace` заменяет ими дневные партиции витрины."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmpurchase_vs_orders_v url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/dm.md#user-content-dmpurchase_vs_orders_v
@@ -402,18 +400,18 @@ nodes:
layer: dm layer: dm
order: 3 order: 3
streams: [events, orders] streams: [events, orders]
what: Текущее состояние пяти атомарных проверок качества по дням. История запусков остается в Airflow. what: "Последние результаты пяти проверок качества данных за каждый день. Историю запусков можно посмотреть в Airflow."
read: 'Читайте `dm.dq_summary_v`: запрос к публичному представлению возвращает последнюю опубликованную сводку дня.' read: "Читайте `dm.dq_summary_v`, чтобы увидеть результат каждой проверки за день."
parts: parts:
- '`dm.dq_summary_rep` — реплицируемая таблица опубликованной сводки.' - '`dm.dq_summary_rep` — реплицируемая таблица опубликованной сводки.'
- '`dm.dq_summary_dist` — распределенная поверхность чтения и записи.' - '`dm.dq_summary_dist` — распределенная таблица чтения и записи.'
- '`dm.dq_summary_stage_rep` — общий донор дневных партиций.' - '`dm.dq_summary_stage_rep` — промежуточная таблица для результатов всех проверок за день.'
- '`dm.dq_summary_stage_dist` — распределенная поверхность донора.' - '`dm.dq_summary_stage_dist` — распределенная таблица для записи и чтения промежуточных данных.'
- '`dm.dq_summary_v` — публичное представление.' - '`dm.dq_summary_v` — представление для чтения готовых данных.'
fill: fill:
- Даг `dq_check` при каждом прогоне сначала выполняет все пять проверок, затем заменяет готовые дневные партиции. - Даг `dq_check` сначала рассчитывает результаты всех пяти проверок в промежуточной таблице, затем заменяет ими дневные партиции сводки.
- '`sessions_vs_reference` — `sql/dq/sessions_vs_reference.sql`.' - '`sessions_vs_reference` — `sql/dq/sessions_vs_reference.sql`.'
- '`classes_vs_inventory` — `sql/dq/classes_vs_inventory.sql` и паспорт мира.' - '`classes_vs_inventory` — `sql/dq/classes_vs_inventory.sql` и эталонные числа из паспорта мира `data/world-inventory.json`.'
- '`revenue_daily_vs_dds` — `sql/dq/revenue_daily_vs_dds.sql`.' - '`revenue_daily_vs_dds` — `sql/dq/revenue_daily_vs_dds.sql`.'
- '`purchase_vs_orders_vs_dds` — `sql/dq/purchase_vs_orders_vs_dds.sql`.' - '`purchase_vs_orders_vs_dds` — `sql/dq/purchase_vs_orders_vs_dds.sql`.'
- '`daily_traffic_vs_dds` — `sql/dq/daily_traffic_vs_dds.sql`.' - '`daily_traffic_vs_dds` — `sql/dq/daily_traffic_vs_dds.sql`.'
@@ -430,15 +428,15 @@ nodes:
layer: dic layer: dic
order: 0 order: 0
streams: [orders] streams: [orders]
what: Словарь товаров вне цепочки слоев. По артикулу доступны название, бренд, категория и цена. what: "Словарь товаров. По артикулу можно получить название, бренд, категорию и цену. Эти данные доступны для расчетов в разных слоях."
read: 'Читайте `dic.products`: у словаря одна поверхность без суффикса.' read: "Читайте `dic.products`: к словарю обращаются напрямую, суффикса `_v` у него нет."
parts: parts:
- '`dic.products_file` — чтец CSV-каталога из файла репозитория.' - "`dic.products_file` — таблица, которая читает каталог товаров из CSV-файла репозитория."
- '`dic.products` — словарь в памяти поверх подложки.' - "`dic.products` — словарь в памяти, загруженный из этой таблицы."
keys: keys:
- '`sku` — тот же артикул, что `item_sku` в позиции заказа DDS.' - '`sku` — тот же артикул, что `item_sku` в позиции заказа DDS.'
fill: fill:
- ClickHouse перечитывает подложку каждые 60–90 секунд по настройке `LIFETIME`. - "ClickHouse обновляет словарь из `dic.products_file` каждые 60–90 секунд согласно настройке `LIFETIME`."
links: links:
- label: Справочник - label: Справочник
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-справочники url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/storage.md#user-content-справочники
@@ -452,8 +450,8 @@ edges:
mechanism: materialized_view mechanism: materialized_view
streams: [events] streams: [events]
rhythm: непрерывно, по мере прихода сообщений rhythm: непрерывно, по мере прихода сообщений
actor: Чтец `stg.hits_raw_kafka` и матвью `stg.hits_raw_mv`. actor: "Таблица `stg.hits_raw_kafka` и материализованное представление `stg.hits_raw_mv`."
join: 'Соединения нет: сообщение кладется строкой целиком.' join: "Каждое сообщение Kafka записывается целой строкой, без разбора на поля."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/40-stg-views.sql
@@ -466,8 +464,8 @@ edges:
mechanism: materialized_view mechanism: materialized_view
streams: [events] streams: [events]
rhythm: непрерывно, по мере прихода сообщений rhythm: непрерывно, по мере прихода сообщений
actor: Матвью `ods.event_mv` разбирает годные строки. actor: Материализованное представление `ods.event_mv` разбирает сообщения без ошибок.
join: 'Соединения нет: матвью разбирает строку в колонки.' join: "Материализованное представление разбирает сообщение из STG на колонки с нужными типами данных."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql
@@ -480,8 +478,8 @@ edges:
mechanism: materialized_view mechanism: materialized_view
streams: [events] streams: [events]
rhythm: непрерывно, по мере прихода сообщений rhythm: непрерывно, по мере прихода сообщений
actor: Матвью `ods.event_errors_mv` отбирает строки, которые не прошли строгий прием. actor: "Материализованное представление `ods.event_errors_mv` отбирает сообщения с ошибками."
join: 'Соединения нет: негодная строка уходит целиком вместе с классом ошибки.' join: "Сообщение, которое не удалось разобрать по правилам ODS, сохраняется целиком вместе с классом ошибки."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/30-ods-views.sql
@@ -493,9 +491,9 @@ edges:
to: stg_orders to: stg_orders
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, раз в модельные сутки rhythm: одной выгрузкой, раз в модельные сутки
actor: Задача `pull_batch` дага `orders_ingest` читает `stg.orders_raw_kafka`. actor: Задача `pull_batch` дага `orders_ingest` читает `stg.orders_raw_kafka`.
join: 'Соединения нет: сообщение слепка кладется целиком, пачка помечена `_load_id`.' join: "Строки выгрузки сохраняются целиком. Общий `_load_id` позволяет найти все строки одной загрузки."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/stg/orders_raw_load.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/stg/orders_raw_load.sql
@@ -507,9 +505,9 @@ edges:
to: ods_order to: ods_order
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, раз в модельные сутки rhythm: одной выгрузкой, раз в модельные сутки
actor: Задача `parse_batch` дага `orders_ingest` пишет годные версии заказа. actor: Задача `parse_batch` дага `orders_ingest` записывает версии заказов без ошибок разбора.
join: 'Соединения нет: строка разбирается в колонки, версия задается `snapshot_date`.' join: "Строка разбирается на колонки заказа. Версия определяется датой слепка `snapshot_date`."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ods/order_parse.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ods/order_parse.sql
@@ -521,9 +519,9 @@ edges:
to: ods_order_errors to: ods_order_errors
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, раз в модельные сутки rhythm: одной выгрузкой, раз в модельные сутки
actor: Задача `parse_batch` дага `orders_ingest` пишет негодные строки той же пачки. actor: Задача `parse_batch` дага `orders_ingest` записывает строки с ошибками из загруженной выгрузки.
join: 'Соединения нет: негодная строка пачки уходит целиком.' join: "Строка с ошибкой сохраняется целиком вместе с классом ошибки и идентификатором загрузки."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ods/order_parse.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ods/order_parse.sql
@@ -535,9 +533,9 @@ edges:
to: dds_event to: dds_event
mechanism: view mechanism: view
streams: [events] streams: [events]
rhythm: без копии, данные читаются на месте rhythm: при запросе к представлению, без копирования данных
actor: Запрос `dds.event_v` читает данные из `ods.event_v` и переименовывает поля на языке бизнеса. actor: "Представление `dds.event_v` читает данные из `ods.event_v`."
join: 'Соединения нет: представление переименовывает колонки той же строки.' join: "Колонки события переименовываются по правилам DDS. Данные не копируются в отдельную таблицу."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/50-dds-views.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/ddl/50-dds-views.sql
@@ -549,9 +547,9 @@ edges:
to: dds_session to: dds_session
mechanism: airflow_dag mechanism: airflow_dag
streams: [events] streams: [events]
rhythm: пачкой, при каждом прогоне `dds_transform` rhythm: при каждом запуске `dds_transform`
actor: Задачи `session.rebuild` и `session.replace` дага `dds_transform`. actor: Задачи `session.rebuild` и `session.replace` дага `dds_transform`.
join: 'События одной `client_id` за `event_date` режутся по паузам; `session_id` - `cityHash64(client_id, min(event_time))`.' join: "События одного `client_id` за день `event_date` упорядочиваются по времени. Пауза дольше 30 минут начинает новую сессию. Ее `session_id` рассчитывается как `cityHash64(client_id, min(event_time))`."
links: links:
- label: SQL сборки - label: SQL сборки
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/session_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/session_rebuild.sql
@@ -565,9 +563,9 @@ edges:
to: dds_order to: dds_order
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, при каждом прогоне `dds_transform` rhythm: при каждом запуске `dds_transform`
actor: Задачи `order.rebuild` и `order.replace` дага `dds_transform`. actor: Задачи `order.rebuild` и `order.replace` дага `dds_transform`.
join: 'Соединения нет: из заказа берутся поля и позиции, `order_date` выводится из `created_at`.' join: "Поля заказа приводятся к типам DDS, а позиции из JSON разбираются в массивы. Дата `order_date` рассчитывается из `created_at`."
links: links:
- label: SQL сборки - label: SQL сборки
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/order_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/order_rebuild.sql
@@ -581,9 +579,9 @@ edges:
to: dds_identity to: dds_identity
mechanism: airflow_dag mechanism: airflow_dag
streams: [events] streams: [events]
rhythm: пачкой, при каждом прогоне `dds_transform` rhythm: при каждом запуске `dds_transform`
actor: Задача `identity_map` дага `dds_transform` соединяет покупки с заказами. actor: Задача `identity_map` дага `dds_transform` соединяет покупки с заказами.
join: 'Строки покупки и заказа соединяются по `purchase_id[1] = order_id`.' join: "Событие покупки соединяется с заказом по `purchase_id[1] = order_id`. В результате связываются посетитель сайта и пользователь магазина."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/identity_map_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/identity_map_rebuild.sql
@@ -595,9 +593,9 @@ edges:
to: dds_identity to: dds_identity
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, при каждом прогоне `dds_transform` rhythm: при каждом запуске `dds_transform`
actor: Задача `identity_map` дага `dds_transform` соединяет заказы с покупками. actor: Задача `identity_map` дага `dds_transform` соединяет заказы с покупками.
join: 'Строки заказа и покупки соединяются по `order_id = purchase_id[1]`; берется `user_id`.' join: "Заказ соединяется с событием покупки по `order_id = purchase_id[1]`. Из заказа берется `user_id` пользователя магазина."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/identity_map_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dds/identity_map_rebuild.sql
@@ -609,9 +607,9 @@ edges:
to: dm_daily_traffic to: dm_daily_traffic
mechanism: airflow_dag mechanism: airflow_dag
streams: [events] streams: [events]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Задача `daily_traffic` дага `dm_transform` считает посетителей по сессиям. actor: Задача `daily_traffic` дага `dm_transform` считает посетителей по сессиям.
join: 'Соединения нет: сессии группируются по `session_date`, который становится `report_date`.' join: "К сессиям присоединяется карта идентичностей по `client_id`, затем данные группируются по `session_date`. Эта дата записывается в `report_date`."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/daily_traffic_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/daily_traffic_rebuild.sql
@@ -623,9 +621,9 @@ edges:
to: dm_daily_traffic to: dm_daily_traffic
mechanism: airflow_dag mechanism: airflow_dag
streams: [events] streams: [events]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Задача `daily_traffic` дага `dm_transform` считает известных пользователей по `client_id`. actor: Задача `daily_traffic` дага `dm_transform` считает известных пользователей по `client_id`.
join: 'GLOBAL LEFT JOIN по `client_id`; сессии без пары остаются в витрине.' join: "`GLOBAL LEFT JOIN` присоединяет карту идентичностей к сессиям по `client_id`. Сессии без известного пользователя тоже участвуют в расчете посетителей."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/daily_traffic_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/daily_traffic_rebuild.sql
@@ -637,9 +635,9 @@ edges:
to: dm_revenue to: dm_revenue
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Задачи `revenue_daily.rebuild` и `revenue_daily.replace` дага `dm_transform`. actor: Задачи `revenue_daily.rebuild` и `revenue_daily.replace` дага `dm_transform`.
join: 'Соединения таблиц нет: ARRAY JOIN раскрывает `item_sku`, `item_quantity`, `item_price`; `order_date` становится `report_date`.' join: "`ARRAY JOIN` разворачивает массивы `item_sku`, `item_quantity`, `item_price` в строки позиций заказа. Выручка считается по оплаченным заказам; `order_date` записывается в `report_date`."
links: links:
- label: SQL сборки - label: SQL сборки
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/revenue_daily_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/revenue_daily_rebuild.sql
@@ -653,9 +651,9 @@ edges:
to: dm_revenue to: dm_revenue
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Даг `dm_transform` получает категорию через `dictGet` по `item_sku`; ключ словаря — `sku`. actor: "Задача `revenue_daily.rebuild` дага `dm_transform`."
join: 'Категория читается через `dictGet` по `item_sku`; ключ справочника - `sku`.' join: "Функция `dictGet` получает категорию товара по артикулу `item_sku` из заказа. В словаре этому артикулу соответствует ключ `sku`."
links: links:
- label: SQL - label: SQL
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/revenue_daily_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/revenue_daily_rebuild.sql
@@ -667,9 +665,9 @@ edges:
to: dm_purchase to: dm_purchase
mechanism: airflow_dag mechanism: airflow_dag
streams: [events] streams: [events]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают покупки. actor: Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают покупки.
join: 'Покупки группируются по `purchase_id[1]` как `purchase_order_id`; `event_date` становится `purchase_day`, затем GLOBAL FULL OUTER JOIN `purchase_order_id = backend_order_id`.' join: "События покупки группируются по номеру `purchase_id[1]`, который получает имя `purchase_order_id`. Дата `event_date` записывается в `purchase_day`. Затем `GLOBAL FULL OUTER JOIN` сопоставляет покупки с заказами по `purchase_order_id = backend_order_id`."
links: links:
- label: SQL сборки - label: SQL сборки
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/purchase_vs_orders_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/purchase_vs_orders_rebuild.sql
@@ -683,9 +681,9 @@ edges:
to: dm_purchase to: dm_purchase
mechanism: airflow_dag mechanism: airflow_dag
streams: [orders] streams: [orders]
rhythm: пачкой, при каждом прогоне `dm_transform` rhythm: при каждом запуске `dm_transform`
actor: Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают заказы. actor: Задачи `purchase_vs_orders.rebuild` и `purchase_vs_orders.replace` дага `dm_transform` читают заказы.
join: 'GLOBAL FULL OUTER JOIN: `purchase_order_id = backend_order_id` (`purchase_id[1]` и `order_id`); отсутствующая сторона получает NULL.' join: "`order_id` заказа получает имя `backend_order_id`, а `purchase_id[1]` покупки — `purchase_order_id`. `GLOBAL FULL OUTER JOIN` соединяет их по `purchase_order_id = backend_order_id`. Покупки без заказа и заказы без покупки сохраняются; поля отсутствующей стороны содержат `NULL`."
links: links:
- label: SQL сборки - label: SQL сборки
url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/purchase_vs_orders_rebuild.sql url: https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/sql/dm/purchase_vs_orders_rebuild.sql
+7 -7
View File
@@ -243,9 +243,9 @@
details.append(heading, meta); details.append(heading, meta);
addSection("Что это", node.what); addSection("Что это", node.what);
addSection("Как читать", node.read); addSection("Как читать", node.read);
addSection("Из чего состоит", node.parts); addSection("Связанные таблицы и представления", node.parts);
addSection("Ключи", node.keys); addSection("Как связать данные", node.keys);
addSection("Кто наполняет и как часто", node.fill); addSection("Как обновляются данные", node.fill);
addLinks(node.links); addLinks(node.links);
} }
function renderEdgeCard(edge) { function renderEdgeCard(edge) {
@@ -253,10 +253,10 @@
const heading = document.createElement("h2"); const heading = document.createElement("h2");
heading.textContent = `${nodeById.get(edge.from).name} → ${nodeById.get(edge.to).name}`; heading.textContent = `${nodeById.get(edge.from).name} → ${nodeById.get(edge.to).name}`;
details.append(heading); details.append(heading);
addSection("Механизм", mechanismById.get(edge.mechanism).label); addSection("Способ обработки", mechanismById.get(edge.mechanism).label);
addSection("Ритм", edge.rhythm); addSection("Когда выполняется", edge.rhythm);
addSection("Кто именно", edge.actor); addSection("Что выполняет обработку", edge.actor);
addSection("Как соединяет", edge.join); addSection("Что происходит с данными", edge.join);
addLinks(edge.links); addLinks(edge.links);
} }
function layoutMap() { function layoutMap() {