Files
clickstream-data-platform/sql/ddl/05-dic-catalog.sql
T
ddadminandClaude Opus 5 abc94ba406 feat(clickhouse): справочники вынесены в зону dic, словарь читает подложку
Зачем: место словаря в dds было унаследовано от первого объекта, а не решено.
Справочник читают несколько слоёв, а производит его в хранилище ни один —
прописка внутри одного из потребителей приписывала DDS владение, которого у
него нет.

Что: заведена база dic вне цепочки STG → ODS → DDS → DM, dds.products переехал
в dic.products. Под словарём появилась подложка dic.products_file на движке
File — намеренное усложнение ради урока: в бою источник словаря приезжает
процессом, а не лежит файлом у сервера. Источник объявлен формой query и
приводит цену из целых копеек каталога в Decimal(18, 2), как у денег бэкенда.
Обновление — окном LIFETIME(MIN 60 MAX 90) вместо ручной перезагрузки, ценой
заявленной неатомарности между нодами. У словаря свой беспарольный
пользователь dict с единственным правом на чтение dic. Суффикс _file добавлен
в конвенцию имён ADR 0006. Решение, отвергнутые варианты и условия пересмотра
— ADR 0012.

Проверка: make clean && make up на собранном заново стенде — зелено, make smoke
20 проверок и 0 ошибок, make lint чисто. Словарь LOADED со 180 строками, цена
Decimal(18, 2) и точна на копейках: 188990 → 1889.90. Пользователь bi читает
словарь dictGet-ом со второй ноды, analyst — подложку соединением, база dds
пуста. Минимальное право на движок замерено тремя пользователями: достаточно
GRANT FILE ON *.*, хотя отказ называет TABLE ENGINE ON File.

Closes #105

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 11:37:26 +03:00

67 lines
4.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Каталог товаров: подложка на файловом движке и словарь поверх неё.
--
-- Словарь читает не файл, а таблицу хранилища — намеренное усложнение
-- ([ADR 0012](../../docs/adr/0012-dictionary-home.md)). В бою справочник
-- приезжает процессом, и предложение SOURCE с запросом и учётной записью —
-- та форма, которую менти встретит; файловый источник работает, но редок.
--
-- Зона dic лежит вне цепочки STG → ODS → DDS → DM: справочник в хранилище
-- никто не производит, а читают его несколько слоёв.
-- Подложка ничего не хранит: движок File перечитывает CSV на каждом запросе,
-- поэтому правка каталога доезжает до словаря сама. Compose монтирует один и
-- тот же файл в user_files обеих нод только для чтения.
--
-- Путь считается ОТ user_files, а не от корня данных: форма
-- './user_files/catalog/products.csv' даёт FILE_DOESNT_EXIST. У файлового
-- источника словаря база пути была другой — отсюда разница с прежним DDL.
-- Типы здесь повторяют файл, а не модель: цена лежит целыми копейками, как её
-- пишет генератор. Приведение к деньгам делает словарь.
CREATE TABLE IF NOT EXISTS dic.products_file ON CLUSTER clickstream_cluster
(
sku String,
name String,
category String,
brand String,
price Int64,
demand String
)
ENGINE = File(CSVWithNames, './catalog/products.csv');
-- Пользователь dict объявлен файлом настройки и умеет одно — читать dic.
-- Назвать его обязательно: без user словарь идёт как default с пустым паролем
-- и падает с AUTHENTICATION_FAILED. Хост локальный, поэтому запрос к подложке
-- идёт без сети.
--
-- Окно обновления вместо LIFETIME(0): словарь перезагружается сам в случайный
-- момент внутри окна. Случайность разводит обращения разных серверов к
-- источнику, и цена у неё заявленная — ноды обновляются вразнобой, до 30
-- секунд одна видит правку каталога, а вторая ещё нет.
--
-- Ключ строковый, поэтому COMPLEX_KEY_HASHED: числовой FLAT здесь неприменим.
--
-- Цена приводится к деньгам прямо в источнике — оттого форма query, а не
-- table: словарь нормализует на входе, а не зеркалит подложку. В файле лежат
-- целые копейки, наружу словарь отдаёт Decimal(18, 2), как заказы бэкенда.
-- Единица в числе становится видна: 129000 против 1290.00.
--
-- Стык с событием на этом и стоит: в контракте события productPrice — целые
-- РУБЛИ, округление формата. Разрыв между ценой каталога и ценой в событии
-- намеренный, на нём держится урок про Float64.
CREATE DICTIONARY IF NOT EXISTS dic.products ON CLUSTER clickstream_cluster
(
sku String,
name String,
category String,
brand String,
price Decimal(18, 2),
demand String
)
PRIMARY KEY sku
SOURCE(CLICKHOUSE(
host 'localhost' port 9000 user 'dict'
query 'SELECT sku, name, category, brand, toDecimal64(price, 2) / 100 AS price, demand FROM dic.products_file'
))
LAYOUT(COMPLEX_KEY_HASHED())
LIFETIME(MIN 60 MAX 90);