Files
clickstream-data-platform/docs/architecture/dds/event.md
T
ddadminandClaude Fable 5.1 59d8c83b17 docs(glossary): четыре термина переименованы, world.md и stand.md вычитаны
- Зачем:
  - справочники читает человек со стороны, а «пульт мира», «опись мира»,
    «работник» и «сырьё» звучали шуткой или калькой времён разработки
    (тикет #214, выбор владельца).
- Что:
  - CONTEXT.md: статьи «Паспорт мира», «Даги модельного времени»,
    «Шаговый даг», «Сырые данные», старые слова в строках «Избегать»;
    пометки в ADR 0005, 0008, 0009 без переписывания решений.
  - замены по README, справочникам, путеводителю, лабам, спекам,
    комментариям дагов и SQL, тегу дага и панели Grafana; имена в коде
    не тронуты.
  - world.md и stand.md: 35 находок вычитки внесены, регистр выровнен.
- Проверка:
  - make config-test; make lint в корне и в generator/; make test в
    generator/ (437 passed); скрипт ссылок из #212 пуст; grep старых
    слов вне ADR, research и CONTEXT.md пуст.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QBCtU38qSHg5DvgtnKXcW
2026-09-02 16:46:50 +03:00

11 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 тоже остаётся — это атрибут посетителя, а не линза времени.

purchase_revenue сохраняет смысл поля источника. Тип денег нормализуется в ODS; точный тип и проверка описаны в разделе «Актуальные события». DDS только переименовывает уже нормализованную колонку.

Расшифровки

Одна: 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 из STG. Это содержимое источника; отдельным атрибутом модели оно не становится. Разобранные массивы 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). Справочника целей нет; косметика без читателя.

Связанные решения