feat(clickhouse): добавлен словарь товаров из каталога

- Зачем:
  - витринам нужен общий с генератором каталог, а менти — пример штатного обновления словаря.
- Что:
  - каталог смонтирован read-only в обе ноды и создан как dds.products ON CLUSTER.
  - роли получили dictGet, а check-clickhouse сверяет ответ под etl с исходным CSV.
  - источник, раскладка и явная политика обновления записаны в документации.
- Проверка:
  - make up с чистыми томами; make lint; make config-test; make smoke; make check-clickhouse.
  - в generator: make lint typecheck test — 427 тестов прошли.
This commit is contained in:
2026-08-19 00:50:14 +03:00
parent 62b275ef94
commit 13abc58d98
8 changed files with 106 additions and 22 deletions
+30 -2
View File
@@ -12,6 +12,8 @@ keeper, Kafka, каркас сервисов. Этап 2 идёт: в `sql/ddl/`
Этап 3 добавил вход второго источника и довёл его до ODS: топик `orders`, свой
чтец, своё сырьё, версии заказов с таблицей ошибок и поверхность текущего
состояния. Наполняет всю цепочку даг `orders_ingest` двумя шагами, а не матвью.
Тот же этап принёс первый объект DDS — словарь товаров из общего с генератором
CSV-файла.
Дальше по тексту устройство описано так, как оно проектируется; построенное от
заложенного отличает карта таблиц в конце.
@@ -414,6 +416,23 @@ kafka_offset)`: смотрят такую таблицу от класса, а
разрастается до имени отдельного поля. Точная граница приёма — в
[спецификации заказов](orders/ingestion.md).
## Словарь товаров
`dds.products` читает `data/catalog/products.csv` напрямую. Compose монтирует
каталог только для чтения в `user_files` обеих нод, а DDL создаёт словарь
`ON CLUSTER`: имя и форма одни, но каждая нода держит свою копию в памяти.
Источник `FILE` с форматом `CSVWithNames` читает заголовок файла. Строковый ключ
`sku` требует `COMPLEX_KEY_HASHED`; числовой `FLAT` здесь неприменим. Цена
остаётся целым числом копеек типа `Int64`, как в контракте события.
`LIFETIME(0)` отключает фоновое обновление. Каталог меняется только явной
правкой репозитория, а независимый опрос двух нод позволил бы им временно
отвечать разными версиями. Изменение применяют к обеим нодам штатной командой:
`SYSTEM RELOAD DICTIONARY ON CLUSTER clickstream_cluster dds.products`.
Это административная операция: её выполняют под `default`; роль `etl` права
перезагрузки словарей не получает.
## Раскладка SQL
Исполняемые дагами запросы лежат по правилу
@@ -439,6 +458,7 @@ Airflow читает и собирает эти файлы штатным шаб
| `00-databases.sql` | базы слоёв |
| `10-stg-tables.sql` | чтецы топиков `hits` и `orders`, локальные и распределённые таблицы сырья обоих источников |
| `20-ods-tables.sql` | типизированное событие, версии заказа и обе таблицы ошибок |
| `25-dds-dictionaries.sql` | словарь товаров из общего CSV-каталога |
| `30-ods-views.sql` | актуальные события, текущие заказы и матвью разбора в ODS |
| `40-stg-views.sql` | матвью приёма: чтец в сырьё |
@@ -501,13 +521,14 @@ ODS. Второе: матвью приёма создаётся последне
| ODS | `ods.order_snapshot_rep` / `_dist` | типизированные версии заказа |
| ODS | `ods.order_v` | текущая версия заказа на языке источника |
| ODS | `ods.order_snapshot_errors_rep` / `_dist` | строки слепка, не прошедшие строгий приём |
| DDS | `dds.products` | словарь товаров из общего с генератором CSV-каталога |
Матвью разбора у заказов нет: срез сырья раскладывают по этим двум целям два
`INSERT SELECT` шага `parse_batch` из файлов `sql/ods/order_snapshot_load.sql`
и `sql/ods/order_snapshot_errors_load.sql`.
Слои DDS и DM появляются на следующих этапах; их состав задан разделом 7
мастер-спеки и переносится сюда по мере постройки.
Таблицы DDS и слой DM появляются на следующих этапах; их состав задан разделом
7 мастер-спеки и переносится сюда по мере постройки.
## Что проверено
@@ -525,6 +546,13 @@ MCP Context7 подтвердила обычное представление с
`ods.event_v` остался равен `ods.event_dist FINAL`. Имена и типы всех колонок
представления совпали с распределённой таблицей.
**Проверка словаря товаров 19 августа 2026 года (#95).** Context7 подтвердил
DDL-словарь с файловым источником внутри `user_files`, хешированную раскладку
для строкового ключа и отключение фонового обновления через `LIFETIME(0)`.
На закреплённом ClickHouse 26.3 цена известного `sku` после правки CSV и
`SYSTEM RELOAD DICTIONARY ON CLUSTER`
изменилась на обеих нодах; после отката и повторной команды вернулась обратно.
**Проверка версий заказов 18 августа 2026 года (#94).** MCP Context7 подтвердил,
что `JSONType` возвращает имя типа значения JSON, — на нём стоит проверка типов
в предикате приёма заказов. Остальное снято на закреплённом ClickHouse 26.3.
+5 -1
View File
@@ -43,7 +43,7 @@
| `make config-test` | корень | Compose разбирается, файлы DAG синтаксически целы, в diff нет пробельных ошибок. О работоспособности не говорит ничего | не нужен | 1 с |
| `make lint` | корень | Код стенда — `dags/` и `infra/superset/` — отформатирован и проходит ruff | не нужен | 0,4 с |
| `make smoke` | корень | Стенд **собран**: службы живы, порты отвечают, подключения настроены друг на друга. Вширь и по касательной к каждой службе. Единственная цель, которая здесь правда смоук | нужен | 9 с |
| `make check-clickhouse` | корень | Всё, что спрашивают **у ClickHouse** и он отвечает сам: макросы, шарды, реплики, путь в keeper, ключ шардирования, очередь распределённых DDL, счёт событий стартового мира против описи | нужен | 8 с |
| `make check-clickhouse` | корень | Всё, что спрашивают **у ClickHouse** и он отвечает сам: макросы, шарды, реплики, путь в keeper, ключ шардирования, очередь распределённых DDL, ответ словаря товаров, счёт событий стартового мира против описи | нужен | 24 с |
| `make check-services` | корень | **Службы работают**: DAG запускается и доходит, топик создаётся и удаляется, Superset логинится и ходит в базу | нужен | 59 с |
| `make lint` | `generator/` | Код генератора отформатирован и проходит ruff | не нужен | 0,4 с |
| `make typecheck` | `generator/` | Типы генератора сходятся (ty) | не нужен | 0,5 с |
@@ -221,6 +221,10 @@ Kafka → STG → ODS, и живёт он в `make check-clickhouse`.
## Что проверено
**Перезамер 19 августа 2026 года при исполнении #95.** После добавления десятой
проверки словаря `make check-clickhouse` на чисто поднятом стенде прошёл за
24 секунды. Это цена всей цели, а не одной новой строки.
**Замер 9 августа 2026 года при появлении корневого `lint` (#65).** Три прогона
подряд — 0,39, 0,36 и 0,39 секунды на трёх файлах стенда; в таблице 0,4 с. На
машине с непрогретым кешем первый прогон дороже: `uvx` сначала скачивает ruff.