Зачем: - Показать два ритма пересборки агрегатов на готовых витринах DM. Что: - Добавлены физические модели и публичные договоры revenue_daily и daily_traffic. - Добавлен dm_transform с оконной заменой выручки и полным пересчетом трафика. - Отрицательный опыт локального соединения через публичные _v зафиксирован; выбран явный GLOBAL LEFT JOIN. - Замены партиций сериализованы после подтвержденного OOM при трех одновременных задачах. - Обновлены архитектурные документы и мастер-спека. Проверка: - make lint, make config-test, make smoke, make check-clickhouse, make check-services. - Чистая сборка world_recreate, dds_transform и dm_transform; меры сверены с прямыми агрегатами.
10 KiB
Контракт события в DDS
Учебный результат: менти видит первый на стенде пример правила «слой — это
контракт, а не обязательно копия данных». Заказ и сессия — физические
таблицы, а событие в DDS не хранится вовсе: dds.event_v — представление,
которое переводит событие на язык бизнес-модели, не копируя ни строки.
Витрины DM читают его, а не ODS напрямую.
Форма
Обычное представление над ods.event_v — вторым уровнем, так что FINAL
остаётся спрятанным в один слой, внутри контракта ODS. Единственное
сомнение против такой формы — «представление материализуется до фильтра» —
снято исследованием проталкивания
условий: условия
внешних запросов доезжают до партиций и первичного ключа сквозь два уровня
представлений и переименование колонок.
Две оговорки исследования соблюдены контрактом. Ключевая для срезов колонка
event_date отдаётся переименованием EventDate, не пересчётом — иначе
индекс перестал бы её анализировать. Цена FINAL — отключённый
автоматический PREWHERE — свойство ODS, представление её не усугубляет.
Как публичный договор DDS, представление перечисляет колонки явно и следует общей конвенции чтения, «Имена объектов».
Язык модели
Имена атрибутов — имена модели, а не нормализованные имена источника (CONTEXT.md, «Нормализованное имя»). Для большинства колонок они совпадают: атрибут переезжает под нормализованным именем из описания выгрузки. Расхождения два, и каждое — решение модели:
WatchID→event_id: модель зовёт сущность событием, «watch» — жаргон выгрузки Метрики.UTCEventTime→event_timeв поясе счётчика (Europe/Samara): DDS обслуживает человека с дашбордом, время лежит местным (дока хранилища, «Часовые пояса»). Пересчёт — смена линзы, байты те же, проталкиванию не мешает. Второй метки времени контракт не отдаёт: выбор линзы слой сделал за читателя, UTC остаётся языком ODS.
ClientID остаётся client_id: это устоявшееся имя куки во всей
экосистеме Метрики, по нему шардирование и мост к dds.identity_map_v;
своё имя здесь создало бы третий синоним. client_timezone тоже остаётся —
это атрибут посетителя, а не линза времени.
Расшифровки
Одна: device_category — коды 1–4 в строки desktop / mobile /
tablet / tv. У настоящей Метрики этот атрибут и есть строка (выгрузка
стенда несёт число — принятое отступление: спека, раздел 1.1), контракт возвращает
ему боевой вид.
Значения device_category 1–4 получают имена, остальные сохраняются
десятичной строкой. Новый код остаётся видимым, пока у него не появится имя в
договоре.
Остальные кодированные атрибуты не расшифровываются. Для goals_reached
справочника целей на стенде нет, id и есть язык. Регионы в расшифровке не
нуждаются: выгрузка несёт названия рядом с id (region_city,
region_country), словарь ничего бы не раскрыл. Идея дать менти собрать
справочник регионов самому ушла в лабы — issue #143.
Что скрыто
VisitID— чужой суррогат сессии: свою сессию модель чеканит сама (session_id, модель сессии), а эталон — инструмент проверки, не атрибут модели. DQ-сверка нарезки идёт за эталоном вods.event_v: она по построению сопоставляет наш слой с чужим чеканом — честно, что за чужим она и идёт в его слой.Sign— колонка формата без механики: генератор исправлений не шлёт, и в модели события колонке ответить нечего. Честный рассказ о ней живёт в DDL ODS и лекции.ecommerce— сырой JSON: сырьё, а не атрибут. Разобранные массивыpurchase_*иproduct_*в контракте есть; лаба про разбор JSON внутри колонки читает ODS._load_ts— у представления нет собственной загрузки, а чужие координаты слой не переносит (правило слоя — модель заказа, «Служебные колонки»); расследование спрашивает ODS по ключу события.
Остальные колонки отдаются целиком, включая ip_address и оба
region_*_id: контракт — не цензор, он прячет только то, чему в модели
нечего сказать.
Читатели
- Сборка сессий: ключи нарезки (
client_id,event_time,event_date), тип события, страница, UTM, паспорт куки — категория устройства приходит уже расшифрованной. - Витрины
dm.events_enriched_v,dm.top_pages_daily_vиdm.utm_effectiveness_v(declared_revenueберется изpurchase_revenue). - Событийная сторона сверки
dm.purchase_vs_orders_v:purchase_id,purchase_revenue,event_date. - DQ-сверка сессий с эталоном читает не его, а
ods.event_v— см. «Что скрыто».
Не входит
- Форма витрин DM — #135.
- Лаба со справочником регионов — issue #143, проектирование лаб.
Отклонённые варианты
- Материализация вместо представления. Дублировала бы широкий ODS ради переименований, и урок «слой — контракт, а не копия» пропал бы; единственный довод за — сомнение в проталкивании условий — снят исследованием #128.
utc_event_timeвторой меткой рядом сevent_time. Контракт вернул бы читателю выбор линзы, который слой обязан делать сам; расхождение двух часов — урок ODS, не DDS.visit_idв контракте. Сверка и лаба читали бы одну поверхность, но чужой чекан встал бы атрибутом модели — тем же доводом модель сессии не пустила его в свою строку. Решение владельца: DQ-опыт показательнее, когда эталон приходит из другого слоя.cookie_idвместоclient_id. Честное имя модели, но третий синоним куки на ровном месте: проза говорит «кука», экосистема —ClientID.- Словарь регионов на стенде. Повторил бы урок
dictGetкаталога вторым разом, а раскрывать нечего — названия уже в строке. Идея «сделать руками» ушла в лабы (issue #143). - Прочие расшифровки (
goals_reachedв имена целей,has_gclidв Bool). Справочника целей нет; косметика без читателя.
Связанные решения
- Проталкивание условий сквозь представления — резолюция #128: форма контракта и обе её оговорки.
- Модель сессии —
session_idи довод против чужого чекана; сюда же передан вопрос о судьбеVisitID. - Модель заказа — правило служебных колонок слоя.
- Мастер-спека, раздел 7 — два контракта:
ods.event_vхранит язык источника,dds.event_vговорит языком модели. - CONTEXT.md — «Нормализованное имя», «Хранилище».