# Задание 1: `dm.events_enriched_v` **Чему учит:** слой — это контракт, а не копия данных. Витрина, которая не меняет зерно источника, остается представлением, и копии событий ради других имен колонок не заводит ни один боевой склад. Это разминка. Строк она не хранит, в конвейер не встает, ключа шардирования у нее нет. Задача одна: собрать плоское событие для BI и не поддаться соблазну разложить его на диск. ## Роль витрины Договор события в DDS широкий — 44 колонки, почти весь формат выгрузки: часть из них технические координаты источника, часть — параллельные массивы товаров. Аналитику в Superset нужен плоский набор деловых полей и пара производных, которые иначе каждый пишет заново в каждом запросе. Витрина отвечает на вопрос «что вообще происходило»: с нее начинают, когда надо посмотреть на события глазами человека, а не разбирать широкую строку источника. Источником для витрин следующих заданий она не служит. Витрина слоя DM читает публичный договор DDS — так устроены и стендовые витрины, и потому задания независимы: соседнюю домашку можно делать первой, а можно не делать вовсе. ## Зерно и форма Зерно — **событие**: одна строка витрины равна одной строке `dds.event_v`. Зерно источника сохранено, значит форма — обычное представление `CREATE VIEW dm.events_enriched_v`, без физической таблицы, без донора и без задачи в `dm_transform`. Пересобирать нечего. Источник — `dds.event_v`, и только он. ## Состав колонок Явный список обязателен: договор не должен расширяться сам, когда в источник добавят колонку. **Время и посетитель:** `event_date`, `event_time`, `event_hour`, `client_id`, `event_id`. **Действие:** `event_type` (`pageview`, `add_to_cart`, `purchase`), `url`, `page_path`, `referer`, `referer_host`, `title`. **Атрибуция:** `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`. **Паспорт визита:** `device_category`, `browser`, `operating_system`, `region_country`, `region_city`. **Торговый блок, массивами как в источнике:** `product_id`, `product_name`, `product_category`, `product_price`, `product_quantity`, `product_event_type`, `purchase_id`, `purchase_revenue`, `purchase_coupon`. Три колонки в источнике не лежат и считаются здесь: | Колонка | Как считается | Зачем | |---|---|---| | `event_hour` | `toHour(event_time)` | суточный профиль спрашивают в каждом отчете | | `page_path` | путь `url` без домена и параметров | группировка по странице без разбора строки в каждом запросе | | `referer_host` | домен `referer` | «откуда пришли» одним значением, а не полным адресом | Служебных `_load_id` и `_load_ts` у витрины нет, и это не забывчивость. Их нет и у `dds.event_v`: событие в DDS не грузят, а читают из ODS, поэтому координат собственной загрузки у него не бывает. Служебная колонка называет запуск, который положил строку на диск, — здесь на диск никто ничего не кладет. ## Ловушка задания Массивы `product_*` тянет развернуть через `ARRAY JOIN` — так плоская таблица становится по-настоящему плоской. Разворачивать нельзя, и вреда здесь два. Очевидный: у события с тремя позициями получилось бы три строки, зерно витрины перестало бы совпадать с зерном источника, а вместе с ним развалилось бы и правило формы — такую витрину уже пришлось бы материализовать. Неочевидный и куда более разрушительный: `ARRAY JOIN` — соединение внутреннее, и строку с пустым массивом он выбрасывает. Торговый блок пуст у всех событий, кроме корзин и покупок, то есть у подавляющего большинства. Так «плоская таблица событий» превращается в таблицу товарных позиций и теряет девятнадцать строк из двадцати — а по имени и по составу колонок она по-прежнему выглядит таблицей событий. Ошибка не падает и ничего не подсвечивает. Массивы едут в договор как есть; разворачивает их тот, кому нужна позиция заказа, — и делает это уже в своей витрине, с другим зерном и другим именем. ## Как проверить себя Деловой ключ — `event_id` внутри дня. Собери прямой ответ из `dds.event_v` за тот же день, соедини с витриной полным внешним соединением и посчитай строки, где ключа нет с одной из сторон или где различаются значения деловых колонок. Ноль — зеленый. Отдельно проверяются три производные колонки: `event_hour`, `page_path` и `referer_host` должны совпасть с тем же выражением, посчитанным по `dds.event_v` на лету. Если строк в витрине оказалось в разы меньше, чем в источнике, а остались в ней одни корзины и покупки — это развернутые массивы: `ARRAY JOIN` выбросил все события с пустым торговым блоком. ## Приемка - [ ] `dm.events_enriched_v` создано, физических таблиц под ним нет; - [ ] список колонок в представлении явный; - [ ] число строк и набор `event_id` совпадают с `dds.event_v` за каждый прожитый день; - [ ] задача `events_enriched` в `homework_check` зеленая; - [ ] задачи в `dm_transform` **нет** — и не должно быть.