feat(course): add SparkSession setup practice to module 3

This commit is contained in:
ddadmin committed 2026-09-15 09:01:41 -04:00
1 parent 00942c255f
commit 7c5e976405
10 files changed
+523 -22

No files matched your search

+34 -8
View File
@@ -1,7 +1,11 @@
# Модуль 3. Raw-данные и первое чтение в Spark
**Статус:** `Ready for validation`
**Последнее обновление:** `2026-03-07`
**Статус:** `Ready for review` — код проверен на стенде, время самостоятельного прохождения студентом пока не измерено
**Последнее обновление:** `2026-09-15`
Дополнение: [#2 — практика настройки SparkSession](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/2), после закрытой [#1](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/1). Новая практика входит в модуль 3; структура курса остаётся из восьми модулей.
Результаты прогона и ограничения: [проверка #2](issue-2-spark-session-validation.md).
## Цель
@@ -11,6 +15,9 @@
После прохождения модуля студент:
- создаёт Spark-сессию для кластера, различает настройки из кода, параметров запуска и общего файла;
- проверяет фактический master, имя приложения, настройки каталога и чтение собственной временной Iceberg-таблицы;
- объясняет повторное использование контекста, остановку сессии и перезапуск ядра; меняет часовой пояс с восстановлением исходного значения;
- понимает, как локальный data bundle попадает в raw-зону MinIO;
- умеет загружать PARQUET-файлы в MinIO программно через `boto3`;
- умеет читать raw-данные из MinIO через Spark (`spark.read.parquet` по `s3a://` пути);
@@ -84,6 +91,20 @@ volumes:
### Секция 0: Введение
- **[md]** Заголовок, цели модуля, prerequisite (data bundle из `START_HERE.md`). Таблица-сравнение: «Классический DWH: данные уже внутри СУБД» vs «Lakehouse: данные нужно явно доставить в storage».
### Секция 0.1: Как настроен Spark в нашем стенде
- **Объяснение:** SparkSession, SparkContext, driver в Jupyter, executors на worker-ах; master, appName, getOrCreate; local и кластер. Источники настроек и подготовленный доступ к Iceberg/MinIO.
- **Демонстрация:** сессия с master из общего файла, вычисление суммы 0…9, вывод выбранных несекретных настроек. Изменение `spark.sql.session.timeZone` и восстановление в `finally`.
- **Новый запуск:** повторный builder с другим appName сохраняет фактическое имя контекста; после `stop()` новый контекст получает новое имя.
- **Самостоятельное повторение:** заполнить адрес кластера, имя приложения и builder; контрольное решение в раскрывающемся блоке. Повторить ячейку и проверить неизменный applicationId.
- **Проверка каталога:** создать собственную Iceberg-таблицу с уникальным именем, прочитать `[0, 1]`, удалить только её через `DROP TABLE … PURGE` в `finally`. Учебные таблицы других модулей не используются.
- **Checkpoint:** проверить master и appName, объяснить источники настроек и место вычислений. После удаления временной таблицы перезапустить ядро, повторить заполненный шаблон и проверку Iceberg, затем продолжить raw-ingest.
- **Длительность:** ориентир 20–30 минут; на модуль целиком около 2 часов. Замер машинного выполнения и ограничения проверки фиксируются отдельно от оценки времени студента.
### Секция 0.2: Подготовка к raw-ingest
- Импорты, MinIO-клиент, пути и вспомогательные функции исходного урока. Сессия продолжает работать после checkpoint настройки.
### Секция 1: Проверка data bundle
- **[md]** Зачем проверяем; почему не скачиваем из интернета в ноутбуке (воспроизводимость, сетевые ограничения, разделение ответственности onboarding vs практика).
- **[code]** `os.listdir("/opt/data/nyc_taxi")`, вывод файлов с размерами, assert на наличие PARQUET-файлов и `taxi_zone_lookup.csv` — оба нужны для полного прохождения модуля (включая самостоятельное задание в Секции 6). Понятное сообщение с отсылкой к `START_HERE.md` при отсутствии любого из компонентов.
@@ -96,7 +117,7 @@ volumes:
### Секция 3: Первое чтение в Spark
- **[md]** Разница `spark.read.parquet("s3a://...")` (raw-файлы) vs `spark.table(...)` (управляемая Iceberg-таблица). Мы пока на этапе raw, Iceberg-таблица появится в Модуле 4.
- **[code]** Создание SparkSession (паттерн из Module 2 — адрес кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`).
- **[code]** Чтение через сессию, созданную в секции 0.1; повторная инициализация не нужна.
- **[code]** Чтение одного файла: `spark.read.parquet("s3a://lakehouse/raw/nyc_taxi/yellow_tripdata_2024-01.parquet")`.
- **[code]** Чтение всех файлов wildcard: `yellow_tripdata_*.parquet` (без привязки к конкретному году в wildcard, чтобы код работал с любыми скачанными файлами).
@@ -130,12 +151,15 @@ volumes:
### Дизайн-решения по ноутбуку
- **Helper-код:** весь код inline в ноутбуке. Отдельный модуль в `src/` не создаётся — студент должен видеть каждый шаг явно (`boto3.upload_file()`, `spark.read.parquet()`, `.printSchema()`).
- **Cleanup:** ноутбук НЕ удаляет raw-данные из MinIO — они нужны Модулю 4 (bronze). Spark-сессия останавливается. Явное пояснение в конце ноутбука.
- **Cleanup:** практика настройки удаляет только свою временную таблицу. Ноутбук НЕ удаляет raw-данные из MinIO — они нужны Модулю 4 (bronze). Spark-сессия останавливается в конце.
## Checkpoint
Студент должен уметь:
- создать сессию по заполненному шаблону, подтвердить master `spark://spark-master:7077` и заданное appName;
- прочитать `[0, 1]` из собственной Iceberg-таблицы и подтвердить её удаление;
- объяснить, какие настройки предоставил стенд, где выполняются задания и что повторить после перезапуска ядра;
- показать файлы в raw-зоне MinIO (через MinIO Console или через код);
- прочитать raw PARQUET через Spark и вывести несколько строк;
- назвать схему Yellow Taxi (количество колонок, основные типы);
@@ -148,10 +172,11 @@ volumes:
- `docker-compose.yml` содержит volume mount `./data:/opt/data:ro` для контейнера `jupyter`, и `docker compose config` проходит без ошибок.
- `START_HERE.md` содержит воспроизводимую инструкцию по скачиванию NYC Taxi PARQUET (минимум 3 файла + taxi zone lookup) до запуска Модуля 3.
- `.gitignore` содержит `/data/` для исключения датасета из git.
- `notebooks/03_raw_ingest_and_first_read.ipynb` можно выполнить сверху вниз в поднятом Jupyter-окружении при наличии скачанного data bundle.
- `notebooks/03_raw_ingest_and_first_read.ipynb` можно пройти по порядку в поднятом Jupyter-окружении при наличии data bundle, заполнив шаблон и выполнив указанный перезапуск ядра.
- Ноутбук следует методике курса: `объяснение -> демонстрация -> самостоятельное повторение -> checkpoint`.
- Ноутбук использует паттерны из Модулей 1-2: `boto3` для MinIO, SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`.
- Raw-данные остаются в MinIO после выполнения ноутбука (cleanup отсутствует намеренно).
- Демонстрация берёт master из `spark-defaults.conf`; самостоятельное задание явно задаёт тот же адрес, сохраняя подготовленную конфигурацию каталога. Шаблон и контрольное решение проверяются в новых ядрах на Spark 3.5.1.
- Проверены повторные ячейки, перезапуск ядра, изменение и восстановление часового пояса, новое имя приложения после остановки контекста.
- Raw-данные остаются в MinIO после выполнения ноутбука; удаляется только временная таблица настройки.
- При отсутствии data bundle — понятный assert с отсылкой к `START_HERE.md`.
- `docs/stack_reference.md` обновлён: секция JupyterLab содержит `./data` mount.
- `plans/README.md` содержит строку Модуля 3 в оглавлении.
@@ -166,7 +191,8 @@ volumes:
## Out of Scope
- Создание Iceberg-таблиц — отложено до Модуля 4.
- Создание рабочих Iceberg-таблиц из raw — в Модуле 4. В Модуле 3 есть только маленькая временная таблица для проверки подключения.
- Подбор памяти, числа executors, shuffle, GC и эксперимент с числом партиций.
- Трансформации и очистка данных — отложено до Модулей 4-5.
- Чтение raw-данных через Trino (Trino не умеет читать произвольные файлы без таблицы) — отложено до Модуля 6.
- Партиционирование, MERGE, streaming, gold-слой.