feat(orders): добавлен версионный ODS заказов
- Зачем: - менти должен различать версию заказа, наблюдение источника и запуск загрузки. - Что: - добавлены таблицы версий и брака заказов, а также представление ods.order_v. - даг orders_ingest дополнен строгим переходом одного среза STG в две цели ODS. - результаты опытов записаны в документации, дефект генератора вынесен в #102. - Проверка: - make lint config-test smoke check-clickhouse check-services.
This commit is contained in:
@@ -9,10 +9,11 @@
|
||||
keeper, Kafka, каркас сервисов. Этап 2 идёт: в `sql/ddl/` лежит вся цепочка
|
||||
`Kafka → STG → ODS` — чтец топика `hits`, таблицы сырья, типизированное
|
||||
событие с таблицей ошибок, поверхность актуального состояния и три матвью.
|
||||
Этап 3 добавил вход второго источника: топик `orders`, свой чтец и своё сырьё,
|
||||
которое наполняет даг `orders_ingest`, а не матвью. Дальше по тексту устройство
|
||||
описано так, как оно проектируется; построенное от заложенного отличает карта
|
||||
таблиц в конце.
|
||||
Этап 3 добавил вход второго источника и довёл его до ODS: топик `orders`, свой
|
||||
чтец, своё сырьё, версии заказов с таблицей ошибок и поверхность текущего
|
||||
состояния. Наполняет всю цепочку даг `orders_ingest` двумя шагами, а не матвью.
|
||||
Дальше по тексту устройство описано так, как оно проектируется; построенное от
|
||||
заложенного отличает карта таблиц в конце.
|
||||
|
||||
Зона ответственности у документа одна — хранилище. Генератор описан отдельно:
|
||||
его замысел — в [спеке генератора](../specs/2026-08-01-generator.md), формат
|
||||
@@ -422,8 +423,8 @@ kafka_offset)`: смотрят такую таблицу от класса, а
|
||||
|---|---|
|
||||
| `00-databases.sql` | базы слоёв |
|
||||
| `10-stg-tables.sql` | чтецы топиков `hits` и `orders`, локальные и распределённые таблицы сырья обоих источников |
|
||||
| `20-ods-tables.sql` | типизированное событие и таблица ошибок |
|
||||
| `30-ods-views.sql` | актуальные события и матвью разбора в ODS |
|
||||
| `20-ods-tables.sql` | типизированное событие, версии заказа и обе таблицы ошибок |
|
||||
| `30-ods-views.sql` | актуальные события, текущие заказы и матвью разбора в ODS |
|
||||
| `40-stg-views.sql` | матвью приёма: чтец в сырьё |
|
||||
|
||||
Порядок задают два правила. Первое: матвью принадлежит слою своей цели, а не
|
||||
@@ -482,6 +483,12 @@ ODS. Второе: матвью приёма создаётся последне
|
||||
| ODS | `ods.event_v` | актуальная версия события с полями источника |
|
||||
| ODS | `ods.event_errors_rep` / `_dist` | строки, не прошедшие строгий приём |
|
||||
| ODS | `ods.event_mv`, `ods.event_errors_mv` | разбор сырья в событие и в ошибки |
|
||||
| ODS | `ods.order_snapshot_rep` / `_dist` | типизированные версии заказа |
|
||||
| ODS | `ods.order_v` | текущая версия заказа на языке источника |
|
||||
| ODS | `ods.order_snapshot_errors_rep` / `_dist` | строки слепка, не прошедшие строгий приём |
|
||||
|
||||
Матвью разбора у заказов нет: срез сырья раскладывают по этим двум целям два
|
||||
`INSERT SELECT` шага `parse_batch` в даге `orders_ingest`.
|
||||
|
||||
Слои DDS и DM появляются на следующих этапах; их состав задан разделом 7
|
||||
мастер-спеки и переносится сюда по мере постройки.
|
||||
@@ -502,6 +509,48 @@ MCP Context7 подтвердила обычное представление с
|
||||
`ods.event_v` остался равен `ods.event_dist FINAL`. Имена и типы всех колонок
|
||||
представления совпали с распределённой таблицей.
|
||||
|
||||
**Проверка версий заказов 18 августа 2026 года (#94).** MCP Context7 подтвердил,
|
||||
что `JSONType` возвращает имя типа значения JSON, — на нём стоит проверка типов
|
||||
в предикате приёма заказов. Остальное снято на закреплённом ClickHouse 26.3.
|
||||
|
||||
Три находки касаются не заказов, а самого ClickHouse, и знать их стоит любому,
|
||||
кто пишет здесь строгий разбор:
|
||||
|
||||
- **`toDateOrNull` календарь не проверяет.** `'2026-02-30'` он молча превращает
|
||||
в `2026-03-02`, `'2026-13-01'` — в `1970-01-01`. Для строгого приёма он
|
||||
поэтому не годится: нужен `parseDateTimeInJodaSyntaxOrNull(…, 'yyyy-MM-dd',
|
||||
'UTC')`, который на обеих строках даёт `NULL`.
|
||||
- **Маска разбора формы не держит.** `parseDateTime64InJodaSyntaxOrNull` по
|
||||
маске `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` берёт и `2026-6-3T14:21:07.123Z` — без
|
||||
ведущих нулей. Форму приходится сверять отдельно, регулярным выражением;
|
||||
зато календарь маска проверяет честно (30 февраля, 13-й месяц, 25-й час
|
||||
дают `NULL`), как и лишние или недостающие знаки долей секунды и смещение
|
||||
`+00:00` вместо `Z`.
|
||||
- **У временных типов есть потолок, и он ниже, чем кажется.** `DateTime64(3)`
|
||||
заканчивается на `2299-12-31`, `DateTime` — на `2106-02-07`; строки за
|
||||
потолком разбор отдаёт как `NULL`. Это ловит опыт, который берёт «заведомо
|
||||
далёкий» год: 2999-й не разбирается вовсе.
|
||||
|
||||
Про сам приём заказов снято следующее. Предикат формы провода разложил все
|
||||
13 661 строку сырья, приехавшую при исполнении #93, без исключений и без
|
||||
`NULL`: 13 653 годных и 8 брака, сумма сошлась с общим счётом по каждому
|
||||
`_load_id`, пересечение ветвей — ноль. Все восемь строк брака — версии одного
|
||||
заказа с отрицательным `total`; это дефект генератора, разобранный в
|
||||
[спецификации приёма](orders/ingestion.md), «Что проверено». На управляемой
|
||||
порции из пяти строк (две версии
|
||||
одного заказа плюс по одной строке каждого класса брака) годные ушли в
|
||||
`ods.order_snapshot`, брак — в `ods.order_snapshot_errors` с ожидаемыми
|
||||
классами. Обе версии легли в одну партицию и на один шард; `FINAL` через
|
||||
распределённую таблицу вернул одну строку — ту, у которой `updated_at` позже, —
|
||||
тогда как физический счёт показывал две. Повтор задачи с тем же `_load_id`
|
||||
строку в `ods.order_v` и её `_load_ts` не изменил, а таблица ошибок записала
|
||||
тот же брак второй раз, как и обещано спецификацией приёма.
|
||||
|
||||
Отдельно измерено, что **сводка вставки не годится в счётчики строк**: у
|
||||
запроса с `WHERE` `read_rows` считает прочитанное с диска, а не подошедшее, —
|
||||
на одном и том же срезе из пяти строк две вставки дали 4 и 5. Сколько чего
|
||||
легло, спрашивают у самих таблиц по `_load_id`.
|
||||
|
||||
**Сверено с документацией.** Собственная колонка с именем виртуальной делает
|
||||
виртуальную недоступной. При вставке в `Distributed` шард выбирается по ключу
|
||||
шардирования; фоновый режим — умолчание, а `distributed_foreground_insert = 1`
|
||||
|
||||
Reference in New Issue
Block a user