feat(stand): переведён аналитический путь на стартовую историю
- Зачем: - чистый стенд должен строить аналитику из генерации, а не из архивного JSONL-сида. - Что: - добавлены команды generated-history-analytics и generated-history-check. - обновлены README, operations и Superset-документы под путь generator backfill -> DM -> Superset. - создан follow-up на миграцию учебных материалов с архивного сида. - Проверка: - make generated-history-analytics. - make generated-history-check. - reviewer gate issue 06 пройден без блокирующих находок.
This commit is contained in:
+62
-36
@@ -9,8 +9,12 @@
|
||||
- `make up` (или `docker compose up -d`)
|
||||
- `make down` (остановить и удалить контейнеры/сети проекта)
|
||||
- `make clean` (полная очистка: `down -v --remove-orphans`)
|
||||
- `make generated-history-analytics` (штатный чистый прогон: стартовая история
|
||||
генератора -> Kafka/STG -> ODS -> DDS -> DM -> Superset)
|
||||
- `make generated-history-check` (повторяемая проверка ClickHouse и Superset
|
||||
после прогона стартовой истории)
|
||||
- `make ddl` (применяет SQL из `sql/ddl/00_databases.sql` и `sql/ddl/*/*.sql` в ClickHouse)
|
||||
- `make data` (пересоздаёт топики и заливает данные в Kafka; по умолчанию полный объём, срез — `LIMIT=50 make data`)
|
||||
- `make data` (архивный путь: заливает `data/*.jsonl` в Kafka; не основной источник аналитики)
|
||||
- `make transform` (запускает batch-процесс ODS -> DDS -> DM)
|
||||
- `make superset-init` (повторная инициализация Superset: подключение к ClickHouse, датасеты, дашборд)
|
||||
- `docker compose ps`
|
||||
@@ -33,6 +37,10 @@
|
||||
|
||||
## Airflow DAGs
|
||||
|
||||
Штатный аналитический путь больше не начинается с `kafka_load`: чистый стенд
|
||||
получает данные из стартовой истории генератора. DAG-и ниже остаются для
|
||||
ручных экспериментов, отладки и совместимости учебного стенда.
|
||||
|
||||
### `ddl_init`
|
||||
|
||||
- Запуск: ручной (`Trigger DAG`)
|
||||
@@ -41,6 +49,7 @@
|
||||
|
||||
### `kafka_load`
|
||||
|
||||
- Архивный путь, не основной источник аналитики.
|
||||
- Запуск: ручной (`Trigger DAG with config`)
|
||||
- Параметры:
|
||||
- `limit` (`int`, default `0`) — количество строк (`0` = все)
|
||||
@@ -62,6 +71,8 @@
|
||||
- `full_refresh` (`bool`, default `true`) — очистить DDS перед загрузкой
|
||||
- `wait_stg_timeout_sec` (`int`, default `600`, minimum `30`) — сколько секунд задача `wait_for_stg_data` ждёт появления данных в STG, прежде чем упасть по таймауту
|
||||
- Зависимость: требует наличия данных в STG (от `kafka_load` или `make data`)
|
||||
- В штатном сценарии STG наполняет `make generated-history-analytics` через
|
||||
backfill генератора.
|
||||
- Гейт целостности DDS: `check_dds_integrity` считает события без клика, а
|
||||
`assert_dds_integrity` роняет DAG при `orphan_events > 0`. Проверка идёт после
|
||||
`load_dds` и до `load_dm_summary`, чтобы DM не собирался поверх нарушенной связи
|
||||
@@ -122,6 +133,29 @@ GEN_STATE_RESET=true GEN_LAMBDA_BASE_PER_MIN=60 docker compose up -d generator
|
||||
|
||||
### Стартовая история через backfill
|
||||
|
||||
Штатная команда чистого прогона:
|
||||
|
||||
```bash
|
||||
make generated-history-analytics
|
||||
```
|
||||
|
||||
Она выполняет полный сброс volumes, поднимает ClickHouse и Kafka, применяет DDL,
|
||||
запускает `GEN_RUN_MODE=backfill`, прогоняет batch STG -> ODS -> DDS -> DM,
|
||||
инициализирует Superset и запускает техническую проверку. Для координатора или CI
|
||||
короткая повторная проверка после уже готового стенда:
|
||||
|
||||
```bash
|
||||
make generated-history-check
|
||||
```
|
||||
|
||||
По умолчанию команда использует быстрый проверочный профиль: 6 часов модельного
|
||||
времени (`GEN_MODEL_T_END=2026-01-01T06:00:00+00:00`). Суточную историю можно
|
||||
прогнать отдельно, явно задав правую границу:
|
||||
|
||||
```bash
|
||||
GEN_MODEL_T_END=2026-01-02T00:00:00+00:00 make generated-history-analytics
|
||||
```
|
||||
|
||||
`GEN_RUN_MODE=backfill` быстро проматывает модельное прошлое от `GEN_MODEL_T0`
|
||||
до `GEN_MODEL_T_END` без сна. В Kafka попадают события только за полуоткрытый
|
||||
отрезок `[T0, T_end)`. В compact-topic `generator_state` сохраняется state на
|
||||
@@ -129,8 +163,9 @@ GEN_STATE_RESET=true GEN_LAMBDA_BASE_PER_MIN=60 docker compose up -d generator
|
||||
контрольными числами. При live-запуске с теми же настройками генератор видит,
|
||||
что state совпадает с manifest, и стартует ровно с `T_end` без настенной дельты.
|
||||
|
||||
Для чистого повтора проще всего пересоздать volumes. Это сбрасывает ClickHouse,
|
||||
Kafka-топики данных и compact-topic state.
|
||||
Для чистого повтора пересоздавайте volumes. Это сбрасывает ClickHouse,
|
||||
Kafka-топики данных, state и manifest генератора. `make generated-history-analytics`
|
||||
делает это по умолчанию (`CLEAN_START=1`).
|
||||
|
||||
```bash
|
||||
make clean
|
||||
@@ -141,7 +176,7 @@ GEN_RUN_MODE=backfill \
|
||||
GEN_STATE_RESET=true \
|
||||
GEN_SEED=4242 \
|
||||
GEN_MODEL_T0=2026-01-01T00:00:00+00:00 \
|
||||
GEN_MODEL_T_END=2026-01-02T00:00:00+00:00 \
|
||||
GEN_MODEL_T_END=2026-01-01T06:00:00+00:00 \
|
||||
GEN_MODEL_TIMEZONE=UTC \
|
||||
GEN_MODEL_TIME_SPEED=1 \
|
||||
GEN_TICK_SECONDS=60 \
|
||||
@@ -154,6 +189,9 @@ sleep 10
|
||||
bash scripts/run_batch.sh
|
||||
```
|
||||
|
||||
Ручной сценарий выше нужен для отладки. В обычной проверке используйте
|
||||
`make generated-history-analytics`, чтобы не забыть Superset и итоговый check.
|
||||
|
||||
Manifest можно посмотреть так:
|
||||
|
||||
```bash
|
||||
@@ -175,7 +213,7 @@ docker compose run -d --name startup-history-live --no-deps \
|
||||
-e GEN_STATE_RESET=false \
|
||||
-e GEN_SEED=4242 \
|
||||
-e GEN_MODEL_T0=2026-01-01T00:00:00+00:00 \
|
||||
-e GEN_MODEL_T_END=2026-01-02T00:00:00+00:00 \
|
||||
-e GEN_MODEL_T_END=2026-01-01T06:00:00+00:00 \
|
||||
-e GEN_MODEL_TIMEZONE=UTC \
|
||||
-e GEN_MODEL_TIME_SPEED=1 \
|
||||
-e GEN_TICK_SECONDS=60 \
|
||||
@@ -195,7 +233,7 @@ bash scripts/run_batch.sh
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end
|
||||
SELECT
|
||||
uniqExact(user_domain_id) AS users,
|
||||
uniqExact(click_id) AS visits,
|
||||
@@ -219,7 +257,7 @@ docker compose exec -T clickhouse clickhouse-client \
|
||||
--query "
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end
|
||||
SELECT hex(sipHash128(groupArray(tuple(
|
||||
event_id,
|
||||
click_id,
|
||||
@@ -245,7 +283,7 @@ FROM (
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
users AS (
|
||||
SELECT user_domain_id, uniqExact(click_id) AS visits
|
||||
FROM dm.v_events_enriched
|
||||
@@ -266,7 +304,7 @@ FROM users;
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
30 AS max_session_events,
|
||||
sessions AS (
|
||||
SELECT
|
||||
@@ -296,7 +334,7 @@ FROM sessions;
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
sessions AS (
|
||||
SELECT
|
||||
click_id,
|
||||
@@ -327,7 +365,7 @@ FROM sessions;
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
sessions AS (
|
||||
SELECT
|
||||
click_id,
|
||||
@@ -356,8 +394,8 @@ FROM sessions;
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-01 00:00:00', 6) AS t0,
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-02 00:10:00', 6) AS t_live_end
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:10:00', 6) AS t_live_end
|
||||
SELECT
|
||||
count() AS events,
|
||||
uniqExact(event_id) AS unique_events,
|
||||
@@ -373,7 +411,7 @@ WHERE event_ts >= t0 AND event_ts < t_live_end;
|
||||
|
||||
```sql
|
||||
WITH
|
||||
toDateTime64('2026-01-02 00:00:00', 6) AS t_end,
|
||||
toDateTime64('2026-01-01 06:00:00', 6) AS t_end,
|
||||
crossing AS (
|
||||
SELECT
|
||||
click_id,
|
||||
@@ -518,32 +556,19 @@ curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/dash
|
||||
docker compose restart grafana
|
||||
```
|
||||
|
||||
## Рекомендуемый сценарий (фаза 2)
|
||||
## Рекомендуемый сценарий
|
||||
|
||||
```bash
|
||||
# 1. Запуск инфраструктуры
|
||||
make up
|
||||
# Полный чистый путь: генерация -> STG -> ODS -> DDS -> DM -> Superset
|
||||
make generated-history-analytics
|
||||
|
||||
# 2. Инициализация схемы (один раз)
|
||||
# Airflow UI -> DAGs -> ddl_init -> Trigger DAG
|
||||
|
||||
# 3. Загрузка данных через Airflow
|
||||
# Airflow UI -> DAGs -> kafka_load -> Trigger DAG with config
|
||||
# Параметры по умолчанию: limit=0, reset_topics=true
|
||||
|
||||
# 4. Запуск ETL
|
||||
# Airflow UI -> DAGs -> etl_pipeline -> Trigger DAG with config
|
||||
# {"full_refresh": true}
|
||||
|
||||
# 5. Проверка результатов
|
||||
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT count() FROM ods.browser_event"
|
||||
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT count() FROM dds.event"
|
||||
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT * FROM dm.dq_summary"
|
||||
# Повторная техническая проверка без пересоздания данных
|
||||
make generated-history-check
|
||||
```
|
||||
|
||||
## Быстрые проверки
|
||||
|
||||
- Kafka ingest: наличие данных в `stg.*` и типизированных строк в `ods.*`.
|
||||
- Kafka ingest: наличие данных генератора в `stg.*` и типизированных строк в `ods.*`.
|
||||
- Airflow UI: `http://localhost:8080` показывает DAG `ddl_init`, `kafka_load`, `etl_pipeline`.
|
||||
- BI: витрина `dm.v_events_enriched` отвечает за разумное время при фильтре по дате.
|
||||
|
||||
@@ -760,6 +785,7 @@ curl -s -X POST -u admin:admin http://localhost:3000/api/admin/provisioning/aler
|
||||
docker compose up -d clickhouse
|
||||
docker compose up -d --force-recreate superset-init superset
|
||||
```
|
||||
- После `docker compose down -v` нужно повторно прогнать: `ddl_init` -> `kafka_load` -> `etl_pipeline`.
|
||||
- После `make clean`/`down -v` Superset стартует, но витрины `dm.*` ещё пустые или отсутствуют до прогона ETL; после `ddl_init` -> `kafka_load` -> `etl_pipeline` выполнить `make superset-init`.
|
||||
- Для демо по умолчанию использовать малый срез данных; полный прогон делать осознанно.
|
||||
- После `docker compose down -v` нужно повторно прогнать `make generated-history-analytics`.
|
||||
- После `make clean`/`down -v` Superset стартует, но витрины `dm.*` ещё пустые или
|
||||
отсутствуют до прогона стартовой истории; используйте `make generated-history-analytics`.
|
||||
- Архивную загрузку `make data` использовать только для ручных экспериментов.
|
||||
|
||||
+9
-6
@@ -4,10 +4,10 @@
|
||||
|
||||
## Исполняемые файлы
|
||||
|
||||
### Airflow (основной путь запуска)
|
||||
### Airflow (ручной и учебный путь запуска)
|
||||
|
||||
- `airflow/dags/ddl_init_dag.py` — инициализация схемы ClickHouse
|
||||
- `airflow/dags/kafka_load_dag.py` — загрузка в Kafka из JSONL
|
||||
- `airflow/dags/kafka_load_dag.py` — архивная загрузка в Kafka из JSONL; не основной источник аналитики
|
||||
- `airflow/dags/etl_pipeline_dag.py` — ETL процесс STG -> ODS -> DDS -> DM
|
||||
- `airflow/dags/utils/kafka_helpers.py` — helper-функции для Kafka
|
||||
- `airflow/dags/utils/sql_helpers.py` — чтение и подготовка SQL-файлов для DAG
|
||||
@@ -35,17 +35,20 @@ DDL (форма таблиц):
|
||||
- `superset/init_superset.py` — подключение к ClickHouse + создание датасетов
|
||||
- `superset/create_dashboard.py` — сборка дашборда с чартами
|
||||
|
||||
### Скрипты (запасной путь, не основной)
|
||||
### Скрипты
|
||||
|
||||
Shell-скрипты `scripts/*` (и обёртки `make ddl`/`make data`/`make transform`) — это локальный fallback в обход Airflow. Основной путь запуска — DAG-и Airflow (см. выше).
|
||||
Shell-скрипты `scripts/*` и Makefile-обёртки дают повторяемый локальный запуск.
|
||||
Основной чистый путь аналитики — `make generated-history-analytics`.
|
||||
|
||||
- `scripts/apply_clickhouse_ddl.sh` — применение DDL
|
||||
- `scripts/load_kafka_data.sh` — загрузка в Kafka
|
||||
- `scripts/load_kafka_data.sh` — архивная загрузка `data/*.jsonl` в Kafka
|
||||
- `scripts/run_batch.sh` — batch-процесс
|
||||
- `scripts/run_generated_history_analytics.sh` — чистый прогон стартовой истории до DM и Superset
|
||||
- `scripts/check_generated_analytics.sh` — проверка DM-витрин и Superset metadata на данных генерации
|
||||
|
||||
## Данные и конфиги
|
||||
|
||||
- `data/*.jsonl` — исходные данные (могут быть грязными)
|
||||
- `data/*.jsonl` — архивная фактура для генератора; не основной источник аналитики
|
||||
- `configs/` — конфиги ClickHouse, Prometheus, Grafana
|
||||
- `configs/prometheus.yml` — конфигурация Prometheus (scrape targets для ClickHouse, Kafka, Airflow)
|
||||
- `configs/statsd_mapping.yml` — маппинг StatsD → Prometheus метрик для Airflow
|
||||
|
||||
+19
-30
@@ -9,20 +9,13 @@
|
||||
### 1. Запуск инфраструктуры
|
||||
|
||||
```bash
|
||||
# Запуск всех сервисов
|
||||
make up
|
||||
|
||||
# Применение DDL в ClickHouse
|
||||
make ddl
|
||||
|
||||
# Загрузка данных в Kafka
|
||||
make data
|
||||
|
||||
# Запуск ETL-пайплайна (ODS → DDS → DM)
|
||||
make transform
|
||||
# Чистый прогон: стартовая история генератора -> DM -> Superset
|
||||
make generated-history-analytics
|
||||
```
|
||||
|
||||
### 2. Инициализация Superset
|
||||
Команда очищает volumes, генерирует стартовую историю, прогоняет batch
|
||||
STG -> ODS -> DDS -> DM и создаёт metadata Superset. Если данные уже
|
||||
подготовлены и нужно только пересобрать Superset:
|
||||
|
||||
```bash
|
||||
# Автоматическая инициализация (создание подключения и датасетов)
|
||||
@@ -32,7 +25,7 @@ make superset-init
|
||||
make superset-dashboard
|
||||
```
|
||||
|
||||
### 3. Доступ к UI
|
||||
### 2. Доступ к UI
|
||||
|
||||
Откройте в браузере: http://localhost:8088
|
||||
|
||||
@@ -63,13 +56,14 @@ make superset-dashboard
|
||||
- **🎯 Conversion to /confirmation** — доля просмотров `/confirmation` от просмотров `/home`
|
||||
|
||||
KPI разложены в одну строку по 12-колоночной сетке Superset: четыре блока по 3 колонки.
|
||||
`Unique Sessions` не вынесен отдельной KPI-плиткой, потому что в демо-данных
|
||||
`user_domain_id` и `click_id` идут 1:1 и дают то же число, что `Unique Users`.
|
||||
`Unique Sessions` не вынесен отдельной KPI-плиткой: в текущем дашборде важнее
|
||||
развести события, пользователей и среднюю глубину визита. Генератор создаёт
|
||||
повторные визиты, поэтому `user_domain_id` и `click_id` уже не идут 1:1.
|
||||
|
||||
#### Динамика трафика
|
||||
- **📅 Events over Time** — линейный график событий с 5-минутными бакетами
|
||||
(все события стенда укладываются в ~50 минут, поэтому часовая гранулярность
|
||||
давала бы всего 2 точки и прямую линию)
|
||||
(быстрый проверочный профиль покрывает 6 часов модельного времени, поэтому
|
||||
5-минутные бакеты дают видимую динамику без лишнего шума)
|
||||
- **📱 Traffic by Device** — pie chart распределения по устройствам
|
||||
|
||||
#### География
|
||||
@@ -92,11 +86,9 @@ KPI разложены в одну строку по 12-колоночной с
|
||||
> **Почему именно одно зерно, а не сумма по слою.** Чарт берёт по одной
|
||||
> канонической таблице на слой (`browser_raw → browser_event → event →
|
||||
> v_events_enriched`). Если суммировать `total_rows` по всем таблицам слоя,
|
||||
> в один столбец складываются таблицы разного зерна (события `1000` + визиты `99`
|
||||
> + пустые error-таблицы) и получается **ложная «воронка потерь»**, которой нет.
|
||||
> На одном зерне убывание становится настоящим: видимый шаг **1050 → 1000** —
|
||||
> это дедупликация at-least-once потока по `event_id` в ODS
|
||||
> (`ReplacingMergeTree`), а дальше число стабильно до витрины.
|
||||
> в один столбец складываются таблицы разного зерна: события, визиты и
|
||||
> error-таблицы. Получается **ложная «воронка потерь»**, которой нет. На одном
|
||||
> зерне видно прохождение event-строк по слоям, а не сумму несравнимых таблиц.
|
||||
>
|
||||
> Настоящие сигналы качества (`rows_with_errors` в ODS, `orphan_events` в DDS)
|
||||
> на чистых демо-данных равны нулю и живут в `dm.dq_summary` отдельными
|
||||
@@ -110,7 +102,7 @@ KPI разложены в одну строку по 12-колоночной с
|
||||
|
||||
| Фильтр | Поле | Тип | Применение |
|
||||
|--------|------|-----|------------|
|
||||
| 📅 Date Range | `event_date` | Time Range | Charts с `event_date`; по умолчанию `No filter`, чтобы демо-данные 2022 года не скрывались |
|
||||
| 📅 Date Range | `event_date` | Time Range | Charts с `event_date`; по умолчанию `No filter`, чтобы стартовая история не скрывалась фильтром даты |
|
||||
| 🌍 Country | `geo_country` | Multi-select | Charts на `dm.v_events_enriched` |
|
||||
| 📱 Device Type | `device_type` | Multi-select | Charts на `dm.v_events_enriched` |
|
||||
| 🌐 Browser | `browser_name` | Multi-select | Charts на `dm.v_events_enriched` |
|
||||
@@ -135,8 +127,10 @@ make clean # Остановка с удалением volumes
|
||||
make logs service=superset # Логи сервиса
|
||||
|
||||
# ETL
|
||||
make generated-history-analytics # Чистый прогон генерации до Superset
|
||||
make generated-history-check # Проверка DM и Superset metadata
|
||||
make ddl # Применение DDL в ClickHouse
|
||||
make data # Загрузка данных в Kafka
|
||||
make data # Архивная загрузка data/*.jsonl в Kafka
|
||||
make transform # Запуск batch-процесса
|
||||
|
||||
# Superset
|
||||
@@ -247,12 +241,7 @@ make superset-restart
|
||||
|
||||
# Полная переинициализация
|
||||
docker compose down -v
|
||||
docker compose up -d
|
||||
make ddl
|
||||
make data
|
||||
make transform
|
||||
make superset-init
|
||||
make superset-dashboard
|
||||
make generated-history-analytics
|
||||
```
|
||||
|
||||
### Нет данных в чартах
|
||||
|
||||
Reference in New Issue
Block a user