docs(course): каркас курса и переобвязка уроков 0–6 на путь import (#21)
Зачем: после редизайна пути менти курс ссылался на старый путь generated-history-analytics/backfill и не проходился по новому стенду. Что: в README курса — единый блок подготовки и канонического сброса (make clean -> make up + ddl_init/world_init -> make superset-init), таблица уроков дополнена лабами 07–08 («в работе»); LESSON_STANDARD и уроки 0–6 ссылаются на канонический блок; урок 1 переведён на дозаливку через world_next_day (кнопкой-анонсом, цена в минутах названа); урок 4 — лесенка DAG-ов; урок 5 — словарь «база import / живой поток»; урок 6 обязателен; цифры старого мира помечены маркером «сверить-на-стенде». Проверка: grep по generated-history-analytics/backfill в docs/course/ пуст; правки только в docs/course/; git diff --check чистый. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,15 +49,9 @@
|
||||
|
||||
## 2. Руки: убедись, что данные текут
|
||||
|
||||
Поднимаем стенд и создаём стартовую историю. Это штатный путь курса: готовый источник
|
||||
данных стенда пишет события в Kafka, ClickHouse читает их в STG, затем batch строит
|
||||
ODS, DDS и DM. Файлы `data/*.jsonl` в этом пути не источник аналитики; пока это только
|
||||
кладовка значений для источника данных стенда.
|
||||
|
||||
```bash
|
||||
make generated-history-analytics
|
||||
make up
|
||||
```
|
||||
Подготовь стенд по
|
||||
[канонической инструкции курса](../README.md#подготовка-и-канонический-сброс).
|
||||
После успешного `world_init` эталонный мир уже прошёл путь Kafka → STG → ODS → DDS → DM.
|
||||
|
||||
Теперь смотрим, что доехало до ClickHouse. Открой SQL-консоль:
|
||||
`http://localhost:9123/play` (или Kafka UI на `http://localhost:8082`, чтобы тем же
|
||||
@@ -189,27 +183,23 @@ SELECT
|
||||
FROM stg.kafka_browser_raw;
|
||||
```
|
||||
|
||||
**Перезаливаем срез, чтобы новая колонка заполнилась.** Сначала чистим только таблицу
|
||||
приёмника — иначе рядом останутся строки из секции 2, вставленные ещё *до*
|
||||
`ADD COLUMN`, и в них `kafka_msg_ts` будет пустой (`1970-01-01`):
|
||||
**Дозаливаем следующий день, чтобы новая колонка заполнилась.** Не очищай
|
||||
`stg.browser_raw`: `world_next_day` растит уже импортированный мир, а его финальная
|
||||
проверка сверяет весь накопленный результат. В старых строках, вставленных до
|
||||
`ADD COLUMN`, `kafka_msg_ts` останется пустым (`1970-01-01`) — ниже мы их отфильтруем.
|
||||
|
||||
```sql
|
||||
TRUNCATE TABLE stg.browser_raw;
|
||||
```
|
||||
|
||||
Затем повторно создаём стартовую историю **без очистки volumes**. Это важно:
|
||||
`CLEAN_START=0` сохраняет твою новую колонку и пересозданное MV, но добавляет свежие
|
||||
сообщения в Kafka, чтобы ClickHouse прочитал их уже с новой схемой.
|
||||
|
||||
```bash
|
||||
CLEAN_START=0 make generated-history-analytics
|
||||
```
|
||||
Открой Airflow и кнопкой **Trigger DAG** запусти `world_next_day` с пустой формой.
|
||||
Он дозальёт в Kafka следующий день, а ClickHouse прочитает новые сообщения уже с
|
||||
изменённой схемой. Такой прогон занимает несколько минут — дождись состояния
|
||||
`success`. Здесь мы только нажимаем готовую кнопку; подробно `world_next_day`
|
||||
разберём в лабе 07.
|
||||
|
||||
**Смотрим результат:**
|
||||
|
||||
```sql
|
||||
SELECT kafka_ts, kafka_msg_ts
|
||||
FROM stg.browser_raw
|
||||
WHERE kafka_msg_ts > toDateTime(0)
|
||||
ORDER BY kafka_offset
|
||||
LIMIT 5;
|
||||
```
|
||||
@@ -224,19 +214,8 @@ LIMIT 5;
|
||||
> теряется. Обратный случай — колонку добавил, а в MV не указал — тоже не упадёт: поле
|
||||
> заполнится дефолтом. Вывод: за синхронность схемы и MV отвечаешь ты, а не движок.
|
||||
|
||||
**Верни как было** (откат — тоже две операции, и порядок важен):
|
||||
|
||||
```sql
|
||||
DROP VIEW stg.mv_kafka_browser_to_stg; -- сначала MV, что ссылается на колонку
|
||||
ALTER TABLE stg.browser_raw DROP COLUMN kafka_msg_ts;
|
||||
```
|
||||
|
||||
```bash
|
||||
make ddl # пересоздаёт эталонное MV из 10_stg.sql, схема снова как в репозитории
|
||||
```
|
||||
|
||||
Если запутался в состоянии — всегда есть полный чистый прогон:
|
||||
`make generated-history-analytics && make up`.
|
||||
**Верни как было.** После дозаливки мир уже вырос, поэтому верни схему и данные
|
||||
[каноническим сбросом](../README.md#подготовка-и-канонический-сброс).
|
||||
|
||||
---
|
||||
|
||||
@@ -244,10 +223,10 @@ make ddl # пересоздаёт эталонное MV из 10_stg.sql, с
|
||||
|
||||
| Действие | Где смотреть | Что ожидать |
|
||||
|----------|--------------|-------------|
|
||||
| `make generated-history-analytics && make up` | `SELECT count() FROM stg.browser_raw` | счётчик > 0 |
|
||||
| каноническая подготовка | `SELECT count() FROM stg.browser_raw` | счётчик > 0 |
|
||||
| глянуть строку | `SELECT raw FROM stg.browser_raw LIMIT 1` | валидный JSON целиком, неразобранный |
|
||||
| глянуть offset'ы | `SELECT kafka_offset FROM stg.browser_raw ORDER BY kafka_offset` | идут по возрастанию, без дублей |
|
||||
| правка из секции 4 | `SELECT kafka_msg_ts FROM stg.browser_raw LIMIT 5` | колонка заполнена временем сообщения |
|
||||
| `world_next_day` после правки из секции 4 | `SELECT kafka_msg_ts FROM stg.browser_raw WHERE kafka_msg_ts > toDateTime(0) LIMIT 5` | новые строки заполнены временем сообщения |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user