docs(dds): зафиксирована физическая модель карты идентичностей
- Зачем: - согласованная модель нужна для пакетной реализации DDS и понятного публичного интерфейса слоя. - Что: - описаны физическая карта идентичностей, полный пересчёт и отказ от first_matched_at. - унифицирован публичный контракт _v для событий, заказов, сессий и карты. - синхронизированы мастер-спека, имена объектов и граница доступа. - Проверка: - git diff --cached --check.
This commit is contained in:
1 parent
256d51840b
commit
f0c4b4c627
7 files changed
+234
-59
No files matched your search
@@ -224,14 +224,15 @@ Ecommerce (заполнены только у торговых событий):
|
||||
неизменного `created_at`, шардирование по `cityHash64(order_id)`.
|
||||
`snapshot_date` остаётся датой наблюдения источника, но не задаёт публикацию
|
||||
или идемпотентность. Физическое чтение может видеть несколько версий;
|
||||
`ods.order_v` возвращает точное текущее состояние. Устройство модели DDS и
|
||||
способ её материализации решаются отдельно.
|
||||
`ods.order_v` возвращает точное текущее состояние. В DDS одна строка хранит
|
||||
один заказ с позициями в типизированных массивах; физическая модель и
|
||||
пакетное наполнение описаны в [доке заказа](../architecture/dds/order.md).
|
||||
|
||||
Пропущенный день ничего не ломает, следующий слепок самовосстанавливает.
|
||||
- `items` остаётся сырой строкой JSON в ODS. Разбирать позиции следует на
|
||||
границе ODS → DDS, но их представление определяется вместе с будущей моделью
|
||||
заказов. Это остаётся носителем навыка «вложенный JSON в ClickHouse», не
|
||||
превращая приём в преждевременную модель данных.
|
||||
- `items` остаётся сырой строкой JSON в ODS. Позиции разбираются на границе
|
||||
ODS → DDS в типизированные массивы строки заказа. Это остаётся носителем
|
||||
навыка «вложенный JSON в ClickHouse», не превращая приём в преждевременную
|
||||
модель данных.
|
||||
- Статусы держим все три: смена `created` → `paid` и есть причина «дыхания»
|
||||
выручки внутри окна; сужение до двух — резервный срез 1. На выходе из окна
|
||||
заказ либо `paid`, либо `cancelled`: неоплаченного отменяют, «навсегда
|
||||
@@ -292,12 +293,19 @@ CSV в репозитории (`data/catalog/products.csv`: `sku`, `name`, `cate
|
||||
- **Карта соответствий кука↔пользователь** строится трансформацией из уже
|
||||
существующего моста: `purchase`-событие (`ClientID`, `purchaseID`) ↔ заказ
|
||||
(`order_id`, `user_id`). Ни новых полей, ни нового транспорта.
|
||||
- Форма и место карты: таблица `dds.identity_map`
|
||||
(`client_id` UInt64, `user_id` UInt64, `first_matched_at` DateTime),
|
||||
ReplacingMergeTree, `ORDER BY (client_id, user_id)`, шардирование по
|
||||
`cityHash64(client_id)` — тем же выражением, что события (иначе ко-локации
|
||||
нет); ко-локация делает обогащение витрин локальным;
|
||||
заказы при сборке карты подтягиваются через GLOBAL JOIN.
|
||||
- Форма и место карты: `dds.identity_map_rep` хранит пару `client_id` UInt64,
|
||||
`user_id` UInt64 и координаты собственной загрузки `_load_id`, `_load_ts` в
|
||||
`ReplicatedReplacingMergeTree(_load_ts)` с `ORDER BY (client_id, user_id)`.
|
||||
`dds.identity_map_dist` шардирует по `cityHash64(client_id)` — тем же
|
||||
выражением, что события; ко-локация позволяет обогащать витрины локально.
|
||||
Публичный интерфейс `dds.identity_map_v` перечисляет колонки явно и прячет
|
||||
`FINAL`. `first_matched_at` в стенде нет: у него нет читателя; история
|
||||
склейки оставлена самостоятельной работе в issue #145.
|
||||
- Карта пересобирается пакетно после модели заказов: все `purchase` из
|
||||
`dds.event_v` соединяются с текущими заказами `dds.order_v` через
|
||||
`GLOBAL JOIN`, статус заказа связь покупателя с кукой не отменяет. Каждый
|
||||
запуск пишет полный текущий набор различных пар; предыдущий результат не
|
||||
служит источником следующего.
|
||||
- **N:1**: часть покупателей покупает с двух кук («телефон и ноутбук») —
|
||||
параметр мира; значение фиксирует эта спека: 15%, детерминировано
|
||||
от seed. Ядро лабы:
|
||||
@@ -422,16 +430,20 @@ README.
|
||||
| STG | `stg.orders_raw_kafka`, `stg.orders_raw`, без MV | сырые строки слепка; чтец на ноде 1, забирает пакетный шаг |
|
||||
| ODS | `ods.event` (+`_errors`), `ods.event_v` | типизированные версии событий, брак и точное актуальное состояние |
|
||||
| ODS | `ods.order` (+`_errors`), `ods.order_v` | типизированные версии заказов, брак и точное текущее состояние |
|
||||
| DDS | `dds.session` | сборка сессий из событий (наследник `dds.click`) |
|
||||
| DDS | `dds.session_rep` / `_dist`, `dds.session_v` | физическая сборка сессий и её публичный интерфейс |
|
||||
| DDS | `dds.event_v` | представление над `ods.event`: snake_case-имена, расшифровка кодов `DeviceCategory`; витрины DM читают его, а не ODS напрямую |
|
||||
| DDS | модель заказов | зерно, связи и материализация проектируются на этапе DDS |
|
||||
| DDS | `dds.identity_map` | карта кука↔пользователь |
|
||||
| DDS | `dds.order_rep` / `_dist`, `dds.order_v` | текущая модель заказа и её публичный интерфейс |
|
||||
| DDS | `dds.identity_map_rep` / `_dist`, `dds.identity_map_v` | физическая карта кука↔пользователь и её точный публичный интерфейс |
|
||||
| DIC | подложка `products_file` и словарь `products` | каталог из CSV, вне цепочки слоёв ([ADR 0012](../adr/0012-dictionary-home.md)) |
|
||||
| DM | витрины `dm.*_v`, `dm.dq_summary` | см. ниже |
|
||||
|
||||
У каждой таблицы слоя — пара из локальной и распределённой, имена по конвенции
|
||||
суффиксов; она же задаёт служебные колонки, нарезку и срок хранения сырья —
|
||||
см. [доку хранилища](../architecture/storage.md).
|
||||
Потребительские роли и витрины читают сущности DDS через `_v` с явным списком
|
||||
колонок; прав на `_rep` и `_dist` у них нет. Физические объекты остаются ролям
|
||||
загрузки, диагностики и обслуживания. Механизм и проверяемая граница доступа —
|
||||
в [доке хранилища](../architecture/storage.md), «Имена объектов».
|
||||
|
||||
Заказы принимаются **пакетным забором** ([ADR
|
||||
0008](../adr/0008-order-ingestion.md), [ADR
|
||||
@@ -494,7 +506,7 @@ Kafka день переигрывается генератором заново:
|
||||
счётчики `purchases`/`add_to_carts` оживают из таксономии, добавляется
|
||||
`declared_revenue` по UTM.
|
||||
- **`daily_traffic_v`** — расширяется парой «посетители» / «известные
|
||||
пользователи» (обогащение через `dds.identity_map`, локальное соединение
|
||||
пользователи» (обогащение через `dds.identity_map_v`, локальное соединение
|
||||
по ключу ко-локации).
|
||||
- `events_enriched_v`, `top_pages_daily_v`, `session_overview_v`,
|
||||
`dq_errors_daily_v` — переезжают на новую модель без смены роли: источник —
|
||||
@@ -670,8 +682,10 @@ Kafka Engine на двух нодах снят с этого списка при
|
||||
`ReplacingMergeTree`. Проверять то, что заведомо случается и заведомо
|
||||
обезврежено, — работа без ответа на конце.
|
||||
|
||||
- Поведение соединения двух Distributed-таблиц и `distributed_product_mode` —
|
||||
эмпирически на стенде (хвост #14).
|
||||
- Точную форму локального обогащения `daily_traffic_v` через публичные `_v` —
|
||||
эмпирически при проектировании витрин #135. Общее поведение соединения двух
|
||||
Distributed-таблиц уже проверено в
|
||||
[исследовании](../research/2026-08-22-distributed-join.md).
|
||||
- Размер артефакта эталонного мира после пересборки.
|
||||
- Спорные API (Airflow Datasets/сенсоры, ClickHouse DDL) — перед кодом
|
||||
сверять через MCP Context7 (правило AGENTS.md).
|
||||
|
||||
Reference in new issue
Block a user