Files
ddadminandClaude Opus 4.8 cbf8b2d770 fix(course): правки по итогам слепого ревью лаб 07/08 (#22)
Зачем: два слепых ревью (Codex CODE-1..9, Claude TASK-1..2) и
перепроверки нашли дефекты в лабах и метадоках; финал лабы 08
переделан по решению пользователя.

Что:
- канонический сброс в README курса теперь снимает DAG'и с паузы
  (все создаются на паузе);
- имя дашборда исправлено на «E-commerce Analytics Dashboard»;
- финал лабы 08: вместо мифа «users == sessions на статике» —
  вернувшийся пользователь через границу заморозки и измеренное
  обещание свежести; §2 велит записать границы и время (§6 их требует);
- CONTEXT.md: эталонный мир — замороженный живой,
  4 056 пользователей / 26 083 визита, возвраты уже есть;
- уроки 5–6 ведут в обязательный маршрут, живое упражнение
  урока 5 требует канонический сброс;
- контрактные тесты: убран якорь на удалённую команду; добавленные
  на триаже тесты-цитаты срезаны до устойчивых инвариантов
  (прозаический легаси-жанр — issue #24);
- handoff обновлён до текущего состояния.

Проверка: make test (219 generator + 31 contract) и make lint зелёные;
SQL вернувшегося пользователя проверен на эфемерном ClickHouse 25.1
(на полном наборе — в #23).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 14:48:02 +03:00

23 KiB
Raw Permalink Blame History

Урок 6. BI-витрина в Superset

Формат: практика — будешь запускать Superset поверх готовых витрин ClickHouse, смотреть дашборд и делать маленькую обратимую правку в конфигурации чарта. Пререквизит: пройдены уроки 4–5 (ты уже запускал etl_pipeline, видел DM-слой в конце пайплайна и понимаешь разницу между мониторингом стенда и данными для анализа). Эталонные пути: sql/ddl/dm/40_dm.sql, sql/dm/40_dds_to_dm.sql, superset/init_superset.py, superset/create_dashboard.py.

Поток данных одной строкой: DDS → DM views / dm.dq_summary → Superset datasets → charts → dashboard → native filters

О чём урок простыми словами: ClickHouse уже подготовил таблицы и представления для потребления. Superset превращает их в экран для аналитика: датасеты, графики, фильтры и один общий дашборд.


1. Зачем и где в проде

После уроков 1–4 у нас есть данные: поток приземлился в STG, разобрался в ODS, собрался в DDS, а в конце появился DM-слой. После урока 5 у нас есть мониторинг: он отвечает, жив ли стенд и не сломался ли пайплайн.

Теперь нужен другой взгляд — BI (Business Intelligence, «аналитический интерфейс для бизнес-вопросов»). BI отвечает не «жив ли ClickHouse», а:

  • сколько событий пришло;
  • какие устройства чаще встречаются;
  • из каких стран пришёл трафик;
  • какие UTM-каналы дают больше кликов;
  • какие страницы самые популярные;
  • доходят ли строки до витрины без потерь по слоям конвейера.

Superset — BI-инструмент. Он не заменяет ClickHouse, Airflow или Grafana. Он сидит поверх готовых данных и даёт интерфейс для просмотра, фильтрации и сборки графиков.

В нашем стенде роли такие:

Слой Что делает
dds.click, dds.event хранит собранные сущности после ODS
dm.v_*, dm.dq_summary готовит поверхность потребления для аналитики
Superset dataset регистрирует таблицу или VIEW из ClickHouse в Superset
Superset chart сохраняет один график или KPI на базе dataset
Superset dashboard собирает charts в один экран
Native filters фильтруют dashboard по дате, стране, устройству, браузеру

Граница урока: витрина DM и BI-экран — не одно и то же.

DM-витрина — это SQL-объект в ClickHouse. Она задаёт форму данных: какие поля есть, на какой гранулярности лежит агрегат, какие joins уже сделаны. BI-экран — это способ показать эту витрину человеку: график, таблица, фильтр, порядок блоков на странице.

В проде иначе. Superset обычно подключают к нескольким хранилищам, заводят роли и права, разделяют черновые и опубликованные дашборды, а тяжёлые витрины материализуют. Но базовая схема та же: хранилище готовит данные, BI даёт удобную точку потребления.


2. Руки: запускаем Superset и смотрим дашборд

Подготовь стенд по канонической инструкции курса. После успешного world_init эталонный мир уже прошёл путь Kafka → STG → ODS → DDS → DM, а make superset-init создал метаданные Superset:

  • подключение clickhouse_dwh;
  • 6 datasets поверх dm.*.
  • 10 charts;
  • dashboard E-commerce Analytics Dashboard.

Для этого урока нам нужен готовый DM-слой и уже созданный dashboard, а не разбор DAG. Если Superset metadata нужно пересоздать отдельно, используй make superset-init. Если нужно обновить только charts и dashboard после правки в superset/create_dashboard.py, используй make superset-dashboard.

Открой Superset: http://localhost:8088 (логин admin, пароль admin).

Если Superset предлагает сменить пароль после первого входа, для учебного стенда можно нажать Skip. В проде так не делают, но локальный курс держит одинаковые инструкции для всех.

Открываем dashboard

Открой готовый dashboard:

http://localhost:8088/superset/dashboard/ecommerce-analytics/

Если URL не открылся, зайди через меню Dashboards и найди E-commerce Analytics Dashboard.

На экране должны быть блоки:

  • KPI сверху: Total Events, Unique Users, Avg Events/Visit, Conversion to /confirmation;
  • динамика: Events over Time, Traffic by Device;
  • география: Top Countries by Events;
  • маркетинг: UTM Effectiveness Table, Page Funnel;
  • прохождение строк по слоям: Rows by Layer (event).

Conversion to /confirmation считается как просмотры /confirmation / просмотры /home. Это page-funnel метрика, а не доля визитов: она совпадает с тем, как ниже устроен chart Page Funnel.

Rows by Layer (event) показывает, сколько строк доходит до каждого слоя конвейера STG → ODS → DDS → DM. Прежде чем читать чарт, договоримся про одно слово.

Зерно (grain), он же уровень гранулярности — это что считается одной строкой таблицы. У события зерно «одно событие = одна строка» (ключ event_id), у визита — «один визит = одна строка» (ключ click_id). Это разные зёрна: событий обычно больше, чем визитов, потому что в одном визите много событий. Складывать строки разного зерна в одно число бессмысленно — это всё равно что сложить «штуки яблок» и «корзины яблок».

Поэтому чарт держит одно зерно — event: берёт по одной канонической таблице событий на слой (browser_raw → browser_event → event → v_events_enriched), а не сумму по слою. Если просуммировать все таблицы слоя, в один столбец попадут таблицы разного зерна: события, визиты и технические таблицы ошибок. Получится «воронка потерь», которой на самом деле нет.

Если на первом переходе число уменьшается, это не обязательно потеря данных. В ODS работает дедупликация at-least-once потока по event_id (ReplacingMergeTree): в STG могут приехать повторы, а дальше остаётся каноническое число уникальных событий. Настоящие проблемы качества (ошибки парсинга, осиротевшие события) на чистой стартовой истории равны нулю и лежат в dm.dq_summary отдельными check_name — их разбирали уроки 3–4.

Фильтр даты

В стартовой истории события идут по модельному времени стенда. В текущей конфигурации dashboard фильтр даты открывается как No filter. Если у тебя осталась старая metadata Superset и native filter Date Range стоит в значении Last week, часть графиков может быть пустой, хотя данные есть.

Для этого урока поставь в фильтре даты одно из двух:

  • No filter;
  • или ручной диапазон вокруг дат, которые видны в event_timestamp.

После этого нажми Apply filters. Теперь смотри на dashboard как аналитик: какие графики отвечают на бизнес-вопросы, а какие только показывают техническое устройство конвейера.

Проверяем данные напрямую в ClickHouse

Открой ClickHouse play-консоль: http://localhost:9123/play.

Проверь, что основной dataset Superset не пустой:

SELECT count() AS events
FROM dm.v_events_enriched;

И посмотри, откуда берётся график Page Funnel:

SELECT page_url_path, sum(pageviews) AS pageviews
FROM dm.v_top_pages_daily
GROUP BY page_url_path
ORDER BY pageviews DESC
LIMIT 20;

Запомни эту связку: Superset показывает график, но данные и логика агрегации живут в ClickHouse.


3. Загляни внутрь

Разберём три места: DM-витрины в ClickHouse, регистрацию datasets в Superset и сборку charts / dashboard.

DM: поверхность потребления

Открой sql/ddl/dm/40_dm.sql.

В начале файла написано, почему DM сейчас сделан через VIEW:

  • логику можно менять без пересоздания таблиц;
  • нет копии данных поверх DDS;
  • для демо производительности достаточно.

Основная витрина для dashboard — dm.v_events_enriched. Она соединяет dds.event и dds.click через click_id:

FROM dds.event AS e
LEFT JOIN dds.click AS c ON c.click_id = e.click_id;

LEFT JOIN здесь осознанный: событие может существовать без части контекста из клика. Для BI это значит: график событий не исчезает только потому, что у части строк нет устройства или географии.

Другие VIEW дают более узкие поверхности:

VIEW / таблица Для чего нужна в Superset
dm.v_events_enriched KPI, динамика, устройства, география, фильтры
dm.v_daily_traffic готовая дневная агрегация трафика
dm.v_utm_effectiveness таблица по UTM-каналам
dm.v_top_pages_daily популярные страницы
dm.v_session_overview обзор сессий
dm.dq_summary метрики по слоям: строки (total_rows), ошибки, сироты

Открой sql/dm/40_dds_to_dm.sql. Этот файл не пересчитывает все dm.v_*: VIEW создаются в DDL. Здесь batch-часть наполняет dm.dq_summary метриками по слоям (включая строку для слоя dm), чтобы dashboard мог показать прохождение строк по конвейеру после каждого прогона.

init_superset.py: подключение и datasets

Открой superset/init_superset.py.

Сначала скрипт собирает URI ClickHouse:

return f"clickhousedb://{user}:{password}@{host}:{port}/{database}"

Внутри Docker-сети Superset ходит в ClickHouse по HTTP-порту 8123, поэтому URI использует clickhousedb://...@clickhouse:8123/default.

Потом скрипт создаёт подключение clickhouse_dwh и регистрирует datasets:

datasets = [
    {
        "table_name": "v_events_enriched",
        "schema": "dm",
        "database_name": "clickhouse_dwh",
        "description": "Полная обогащённая витрина событий (event + click)"
    },
    ...
]

Dataset в Superset — это не копия данных. Это запись в metadata Superset: какая таблица или VIEW есть в ClickHouse, какие у неё колонки и как её можно использовать в графиках.

Metadata Superset живёт в PostgreSQL, а сами данные остаются в ClickHouse. Поэтому после полного сброса volumes нужно заново создать metadata Superset, а после пересчёта данных — сами charts обычно остаются теми же.

create_dashboard.py: charts, dashboard, filters

Открой superset/create_dashboard.py.

В CHARTS_CONFIG лежит список charts. Один элемент списка — один график. Ниже показаны ключевые поля Page Funnel; в реальном файле после них есть ещё визуальные параметры funnel — схема цветов, легенда, подписи и формат чисел:

{
    "slice_name": "🪜 Page Funnel",
    "viz_type": "funnel",
    "dataset_name": "v_top_pages_daily",
    "params": {
        "groupby": ["page_url_path"],
        "metric": {
            "expressionType": "SQL",
            "sqlExpression": "SUM(pageviews)",
            "label": "Pageviews"
        },
        "row_limit": 20,
        "time_range": "No filter",
        "sort_by_metric": True,
        "percent_calculation_type": "first_step",
        # Дальше в файле идут визуальные параметры funnel.
    }
}

Здесь видно четыре идеи:

  • slice_name — имя chart в Superset;
  • viz_type — тип визуализации;
  • dataset_name — на каком dataset строится chart;
  • params — настройка запроса и отображения.

Ниже DASHBOARD_CONFIG задаёт сам dashboard:

DASHBOARD_CONFIG = {
    "dashboard_title": "🛒 E-commerce Analytics Dashboard",
    "description": "...",
    "published": True,
    "slug": "ecommerce-analytics",
}

Dashboard находится по slug, а charts добавляются в layout. Если dashboard уже существует, скрипт обновляет metadata, layout и список charts. На этом держится управляемая правка: можно поменять параметр chart, запустить make superset-dashboard и увидеть результат в UI.

Native filters создаются в build_dashboard_metadata. Там есть фильтры:

  • Date Range по event_date;
  • Country по geo_country;
  • Device Type по device_type;
  • Browser по browser_name.

Эти фильтры задаются в левой панели dashboard. Click-to-filter между виджетами не включен: клик по сектору pie chart, столбцу Top Countries, строке таблицы или funnel не меняет остальные charts.

Фильтр применяется только к charts, где есть нужное поле. Country, Device Type и Browser работают с charts на dm.v_events_enriched; агрегированные витрины для UTM, page funnel и DQ не содержат все эти измерения.

Что проверили по API. Перед уроком Superset сверили через MCP Context7 (/apache/superset): в Superset есть отдельные сущности charts и dashboards, metadata хранится отдельно от подключаемых источников данных. Для funnel Context7 не дал точную строку viz_type, поэтому дополнительно проверили установленный Superset 4.1.2: bundled example Featured Charts/Funnel.yaml использует viz_type: funnel. Поэтому в уроке не лезем в REST API Superset, а работаем через уже существующий скрипт стенда.


4. Управляемая правка: уменьшаем Page Funnel

Сейчас chart Page Funnel показывает до 20 страниц:

"row_limit": 20,

Сделай маленькую видимую правку: временно покажи только топ-3 страницы.

Открой superset/create_dashboard.py, найди chart Page Funnel и поменяй:

"row_limit": 20,

на:

"row_limit": 3,

Запусти обновление dashboard:

make superset-dashboard

Вернись в Superset и обнови страницу dashboard. В chart Page Funnel должно остаться не больше трёх страниц. Если фильтр даты снова скрыл данные, поставь Date Range → No filter и нажми Apply filters.

Почему это хорошая маленькая правка:

  • мы не меняем SQL-витрину в ClickHouse;
  • не создаём новый dataset;
  • не трогаем подключение к ClickHouse;
  • меняем только BI-представление уже готовых данных.

Верни как было

Верни в superset/create_dashboard.py:

"row_limit": 20,

И снова запусти:

make superset-dashboard

После обновления страницы chart Page Funnel снова может показывать до 20 страниц.

Если после экспериментов Superset выглядит странно, самый простой учебный возврат dashboard metadata к конфигурации из репозитория:

make superset-dashboard

Данные в ClickHouse эта команда не удаляет. Она повторно применяет charts и dashboard metadata Superset.


5. Проверь себя

Действие Где смотреть Что ожидать
make transform ClickHouse dm.v_events_enriched count() > 0
make superset-init Superset → Settings → Database Connections есть подключение clickhouse_dwh
открыть Datasets Superset UI есть datasets v_events_enriched, v_top_pages_daily, dq_summary
открыть dashboard Superset UI видны KPI, маркетинг, география и прохождение строк по слоям
поставить Date Range → No filter dashboard filters графики не скрываются из-за даты модельного времени
поменять row_limit у Page Funnel на 3 и запустить make superset-dashboard chart Page Funnel не больше трёх страниц
вернуть row_limit на 20 и запустить make superset-dashboard chart Page Funnel ограничение снова до 20 страниц

Вопросы для созвона:

  • чем DM-витрина отличается от Superset dataset;
  • почему Superset не должен ходить напрямую в сырые STG-таблицы;
  • зачем dashboard нужен Date Range, если SQL-витрина уже агрегирована;
  • почему изменение row_limit — это BI-правка, а не изменение модели данных;
  • где хранятся данные, а где metadata Superset.

6. Что должно получиться

К концу урока у тебя должен быть открытый dashboard E-commerce Analytics Dashboard в Superset. Сделай скриншот после временной правки Page Funnel: на нём должно быть видно, что chart показывает не больше трёх страниц.

Второй артефакт — короткий абзац своими словами:

DM-слой в ClickHouse готовит данные для потребления, dataset в Superset регистрирует эту витрину, chart задаёт один график, dashboard собирает charts в экран, а native filters дают аналитику быстрый способ менять срез данных.

После этого обязательно верни row_limit на 20, чтобы следующий урок или следующий прогон стенда начинался с исходной конфигурации.


Мост к следующему шагу

Теперь у тебя есть сквозная цепочка от Kafka до дашборда в Superset. В лабе 07 ты добавишь в этот мир следующий модельный день и проверишь границу двух суточных порций.