Compare commits
4
Commits
a085b2fc55
...
00942c255f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00942c255f | ||
|
|
2cdecd82f8 | ||
|
|
a5244f8a0b | ||
|
|
91a5c85469 |
No files matched your search
@@ -56,6 +56,9 @@ graph TB
|
|||||||
| `Trino` | Compute — ad hoc SQL, чтение тех же таблиц |
|
| `Trino` | Compute — ad hoc SQL, чтение тех же таблиц |
|
||||||
| `JupyterLab` | Точка входа — практические ноутбуки курса |
|
| `JupyterLab` | Точка входа — практические ноутбуки курса |
|
||||||
|
|
||||||
|
Ноутбуки подключаются к Spark-кластеру с
|
||||||
|
[готовыми настройками стенда](./docs/stack_reference.md#spark).
|
||||||
|
|
||||||
## С чего начать
|
## С чего начать
|
||||||
|
|
||||||
1. Открой [START_HERE.md](./START_HERE.md) — запуск стенда, диагностика, первый ноутбук.
|
1. Открой [START_HERE.md](./START_HERE.md) — запуск стенда, диагностика, первый ноутбук.
|
||||||
|
|||||||
@@ -111,6 +111,12 @@ notebooks/01_environment_and_smoke_test.ipynb
|
|||||||
- первый ноутбук курса: `01_environment_and_smoke_test.ipynb`;
|
- первый ноутбук курса: `01_environment_and_smoke_test.ipynb`;
|
||||||
- локальный учебный data bundle для Модуля 3 должен быть доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
- локальный учебный data bundle для Модуля 3 должен быть доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
||||||
|
|
||||||
|
Ноутбуки берут адрес кластера из
|
||||||
|
[`spark/spark-defaults.conf`](./spark/spark-defaults.conf). Если изменил его,
|
||||||
|
перезапусти ядро и заново создай Spark-сессию. Повторный запуск ячейки с
|
||||||
|
`getOrCreate()` использует текущую сессию. При перезапуске ядра переменные Python
|
||||||
|
сбрасываются, а учебные таблицы и файлы сохраняются.
|
||||||
|
|
||||||
## Базовая диагностика
|
## Базовая диагностика
|
||||||
|
|
||||||
### Посмотреть список контейнеров
|
### Посмотреть список контейнеров
|
||||||
|
|||||||
+11
-2
@@ -53,7 +53,16 @@ docker compose down -v
|
|||||||
|
|
||||||
- Master UI: `http://localhost:8080`
|
- Master UI: `http://localhost:8080`
|
||||||
- Worker UI: `http://localhost:8081` и `http://localhost:8082`
|
- Worker UI: `http://localhost:8081` и `http://localhost:8082`
|
||||||
- Spark master endpoint внутри сети compose: `spark://spark-master:7077`
|
- Адрес Spark master внутри сети Docker Compose: `spark://spark-master:7077`
|
||||||
|
|
||||||
|
Адрес кластера (`spark.master`) и настройки доступа к Iceberg и MinIO заданы в
|
||||||
|
[`spark/spark-defaults.conf`](../spark/spark-defaults.conf). Docker подключает этот
|
||||||
|
файл к контейнеру Jupyter как `/opt/spark/conf/spark-defaults.conf`.
|
||||||
|
|
||||||
|
При первом вызове `getOrCreate()` Spark читает настройки и создает сессию.
|
||||||
|
Повторный вызов использует уже работающую сессию. Если изменил адрес кластера
|
||||||
|
или настройки в файле, перезапусти ядро ноутбука и снова выполни ячейки
|
||||||
|
с импортами и созданием сессии.
|
||||||
|
|
||||||
Пример запуска smoke-скрипта:
|
Пример запуска smoke-скрипта:
|
||||||
|
|
||||||
@@ -141,7 +150,7 @@ docker compose run --rm iceberg-catalog-init
|
|||||||
| Файл | Что задаёт |
|
| Файл | Что задаёт |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `docker-compose.yml` | состав сервисов, порты, volumes, init-контейнеры |
|
| `docker-compose.yml` | состав сервисов, порты, volumes, init-контейнеры |
|
||||||
| `spark/spark-defaults.conf` | Spark catalog `lakehouse`, `s3a`, Iceberg extensions |
|
| `spark/spark-defaults.conf` | Spark master, catalog `lakehouse`, `s3a`, Iceberg extensions |
|
||||||
| `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ |
|
| `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ |
|
||||||
| `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями |
|
| `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями |
|
||||||
| `jupyter/Dockerfile` | образ JupyterLab на базе Spark |
|
| `jupyter/Dockerfile` | образ JupyterLab на базе Spark |
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# Мы не указываем .master() явно, так как он и другие настройки Iceberg\n",
|
"# Адрес Spark-кластера и настройки Iceberg берутся из spark-defaults.conf.\n",
|
||||||
"# подтягиваются из конфигурации spark-defaults.conf при старте сессии.\n",
|
"# Поэтому в ноутбуке достаточно задать имя приложения.\n",
|
||||||
"from pyspark.sql import SparkSession\n",
|
"from pyspark.sql import SparkSession\n",
|
||||||
"\n",
|
"\n",
|
||||||
"spark = SparkSession.builder \\\n",
|
"spark = SparkSession.builder \\\n",
|
||||||
|
|||||||
+12
-10
@@ -1,11 +1,11 @@
|
|||||||
# План развития курса «Lakehouse без магии»
|
# План развития курса «Lakehouse без магии»
|
||||||
|
|
||||||
Статус: ближайшие доработки определены, реализация впереди.
|
Статус: подключение Spark исправлено; следующая работа — практика настройки сессии.
|
||||||
Последнее обновление: 2026-09-15.
|
Последнее обновление: 2026-09-15.
|
||||||
|
|
||||||
Здесь собираем отзывы студентов, выбираем следующие улучшения и объясняем их порядок. Подробные задания, критерии приёмки и актуальный статус исполнения хранятся в [Gitea Issues](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues).
|
Здесь собираем отзывы студентов, выбираем следующие улучшения и объясняем их порядок. Подробные задания, критерии приёмки и актуальный статус исполнения хранятся в [Gitea Issues](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues).
|
||||||
|
|
||||||
Текущие рамки курса задаёт [PRD](../docs/course_prd.md), а состав уроков — [программа](../docs/course_program.md). Запись в этом плане означает будущую работу. При реализации изменения сначала обновляем соответствующий канонический документ, затем учебные материалы и ссылки на них.
|
Текущие рамки курса задаёт [PRD](../docs/course_prd.md), а состав уроков — [программа](../docs/course_program.md). Статус каждой работы указан ниже. При реализации изменения сначала обновляем соответствующий канонический документ, затем учебные материалы и ссылки на них.
|
||||||
|
|
||||||
## Обратная связь
|
## Обратная связь
|
||||||
|
|
||||||
@@ -22,21 +22,23 @@
|
|||||||
|
|
||||||
### 1. Проверить и исправить создание Spark-сессий
|
### 1. Проверить и исправить создание Spark-сессий
|
||||||
|
|
||||||
**Статус:** запланировано; выполняется первым.
|
**Статус:** выполнено, [MR #3](https://git.dementev.space/ddmitry/mini-lakehouse-lab/pulls/3).
|
||||||
|
|
||||||
**Задача:** [#1 — подключение Spark-сессий в новом ядре](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/1).
|
**Задача:** [#1 — подключение Spark-сессий в новом ядре](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/1).
|
||||||
|
|
||||||
В `src/spark/cluster_smoke.py` адрес master задаётся явно. В модуле 2 комментарий говорит, что master берётся из `spark-defaults.conf`, однако в этом файле нет `spark.master`. В модулях 2–8 сессия создаётся без явного `.master(...)`. Это подтверждённое расхождение исходников; фактический режим работы этих ноутбуков в новом ядре ещё не проверен.
|
В новых процессах модуль 1 подключался к кластеру, а модули 2–8 запускали Spark
|
||||||
|
локально (`local[*]`). В исправлении все восемь ноутбуков берут адрес кластера
|
||||||
|
из `spark/spark-defaults.conf`.
|
||||||
|
|
||||||
Нужно проверить создание сессии каждого ноутбука в отдельном новом ядре, зафиксировать фактический master и привести код и пояснения к воспроизводимому способу подключения. Повторное прохождение сохраняет учебные данные из предыдущих модулей: независимость от состояния ядра не означает независимость от этих данных.
|
**Проверено:** инициализация каждого ноутбука в отдельном процессе,
|
||||||
|
вычисление на кластере, повторный `getOrCreate()`, запись и чтение тестовой
|
||||||
**Результат:** каждый ноутбук подключается к ожидаемому Spark-кластеру после перезапуска ядра; документация правильно объясняет источник настроек. Проверки и необходимые исправления описываются в задаче.
|
Iceberg-таблицы. Результаты проверок и их ограничения приведены в комментарии к #1.
|
||||||
|
|
||||||
### 2. Добавить практику «Как настроен Spark в нашем стенде»
|
### 2. Добавить практику «Как настроен Spark в нашем стенде»
|
||||||
|
|
||||||
**Статус:** запланировано; зависит от результата работы 1.
|
**Статус:** запланировано; можно приступать после завершения #1.
|
||||||
|
|
||||||
**Задача:** [#2 — практика базовой настройки SparkSession](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/2), заблокирована задачей #1.
|
**Задача:** [#2 — практика базовой настройки SparkSession](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/2).
|
||||||
|
|
||||||
Практику разместить в начале модуля 3. Ориентир — 20–30 минут; фактическую длительность проверить при прохождении.
|
Практику разместить в начале модуля 3. Ориентир — 20–30 минут; фактическую длительность проверить при прохождении.
|
||||||
|
|
||||||
@@ -78,4 +80,4 @@
|
|||||||
|
|
||||||
## Выпущенные улучшения
|
## Выпущенные улучшения
|
||||||
|
|
||||||
Доработки из этого плана ещё не выпущены.
|
- [#1](https://git.dementev.space/ddmitry/mini-lakehouse-lab/issues/1): все восемь ноутбуков подключаются к Spark-кластеру при создании сессии в новом процессе; настройки собраны в `spark/spark-defaults.conf`.
|
||||||
@@ -96,7 +96,7 @@ volumes:
|
|||||||
|
|
||||||
### Секция 3: Первое чтение в Spark
|
### Секция 3: Первое чтение в Spark
|
||||||
- **[md]** Разница `spark.read.parquet("s3a://...")` (raw-файлы) vs `spark.table(...)` (управляемая Iceberg-таблица). Мы пока на этапе raw, Iceberg-таблица появится в Модуле 4.
|
- **[md]** Разница `spark.read.parquet("s3a://...")` (raw-файлы) vs `spark.table(...)` (управляемая Iceberg-таблица). Мы пока на этапе raw, Iceberg-таблица появится в Модуле 4.
|
||||||
- **[code]** Создание SparkSession (паттерн из Module 2 — без `.master()`, `setLogLevel("ERROR")`).
|
- **[code]** Создание SparkSession (паттерн из Module 2 — адрес кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`).
|
||||||
- **[code]** Чтение одного файла: `spark.read.parquet("s3a://lakehouse/raw/nyc_taxi/yellow_tripdata_2024-01.parquet")`.
|
- **[code]** Чтение одного файла: `spark.read.parquet("s3a://lakehouse/raw/nyc_taxi/yellow_tripdata_2024-01.parquet")`.
|
||||||
- **[code]** Чтение всех файлов wildcard: `yellow_tripdata_*.parquet` (без привязки к конкретному году в wildcard, чтобы код работал с любыми скачанными файлами).
|
- **[code]** Чтение всех файлов wildcard: `yellow_tripdata_*.parquet` (без привязки к конкретному году в wildcard, чтобы код работал с любыми скачанными файлами).
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ volumes:
|
|||||||
- `.gitignore` содержит `/data/` для исключения датасета из git.
|
- `.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`.
|
- Ноутбук следует методике курса: `объяснение -> демонстрация -> самостоятельное повторение -> checkpoint`.
|
||||||
- Ноутбук использует паттерны из Модулей 1-2: `boto3` для MinIO, SparkSession без `.master()`, `setLogLevel("ERROR")`.
|
- Ноутбук использует паттерны из Модулей 1-2: `boto3` для MinIO, SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`.
|
||||||
- Raw-данные остаются в MinIO после выполнения ноутбука (cleanup отсутствует намеренно).
|
- Raw-данные остаются в MinIO после выполнения ноутбука (cleanup отсутствует намеренно).
|
||||||
- При отсутствии data bundle — понятный assert с отсылкой к `START_HERE.md`.
|
- При отсутствии data bundle — понятный assert с отсылкой к `START_HERE.md`.
|
||||||
- `docs/stack_reference.md` обновлён: секция JupyterLab содержит `./data` mount.
|
- `docs/stack_reference.md` обновлён: секция JupyterLab содержит `./data` mount.
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ Bronze нужен Модулю 5. Spark-сессия останавливает
|
|||||||
| История изменений | Нет (или WAL на уровне СУБД) | Snapshots и manifests (встроены в формат) |
|
| История изменений | Нет (или WAL на уровне СУБД) | Snapshots и manifests (встроены в формат) |
|
||||||
|
|
||||||
### Секция 1: Spark-сессия и проверка raw
|
### Секция 1: Spark-сессия и проверка raw
|
||||||
- **[code]** SparkSession (паттерн Модулей 2-3: без `.master()`, `setLogLevel("ERROR")`).
|
- **[code]** SparkSession (паттерн Модулей 2-3: адрес кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`).
|
||||||
- **[code]** Быстрая проверка: `spark.read.parquet("s3a://lakehouse/raw/nyc_taxi/yellow_tripdata_*.parquet").count()` + `.printSchema()`. Assert на ненулевой count с отсылкой к Модулю 3.
|
- **[code]** Быстрая проверка: `spark.read.parquet("s3a://lakehouse/raw/nyc_taxi/yellow_tripdata_*.parquet").count()` + `.printSchema()`. Assert на ненулевой count с отсылкой к Модулю 3.
|
||||||
- **[md]** Сейчас читаем как набор файлов — нет истории, каталогизации, контроля схемы. Дальше создадим управляемую таблицу.
|
- **[md]** Сейчас читаем как набор файлов — нет истории, каталогизации, контроля схемы. Дальше создадим управляемую таблицу.
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ Bronze нужен Модулю 5. Spark-сессия останавливает
|
|||||||
|
|
||||||
- `notebooks/04_bronze_with_iceberg.ipynb` можно выполнить сверху вниз в поднятом Jupyter-окружении после прохождения Модуля 3 (raw-данные в MinIO).
|
- `notebooks/04_bronze_with_iceberg.ipynb` можно выполнить сверху вниз в поднятом Jupyter-окружении после прохождения Модуля 3 (raw-данные в MinIO).
|
||||||
- Ноутбук следует методике курса: `объяснение → демонстрация → самостоятельное повторение → checkpoint`.
|
- Ноутбук следует методике курса: `объяснение → демонстрация → самостоятельное повторение → checkpoint`.
|
||||||
- Ноутбук использует паттерны из Модулей 1-3: SparkSession без `.master()`, `setLogLevel("ERROR")`, `boto3` для MinIO.
|
- Ноутбук использует паттерны из Модулей 1-3: SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`, `boto3` для MinIO.
|
||||||
- Ноутбук идемпотентен: повторное выполнение (`CREATE OR REPLACE`) не дублирует данные и не роняет ячейки.
|
- Ноутбук идемпотентен: повторное выполнение (`CREATE OR REPLACE`) не дублирует данные и не роняет ячейки.
|
||||||
- CTAS использует явный список колонок, а не `SELECT *`.
|
- CTAS использует явный список колонок, а не `SELECT *`.
|
||||||
- Bronze-таблица `lakehouse.bronze.nyc_taxi_yellow` остаётся после выполнения ноутбука для использования в Модуле 5.
|
- Bronze-таблица `lakehouse.bronze.nyc_taxi_yellow` остаётся после выполнения ноутбука для использования в Модуле 5.
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ Silver нужен Модулям 6 и 8. Spark-сессия останавлив
|
|||||||
- **[md]** Ключевая идея: silver = bronze + явные правила трансформации + проверки качества.
|
- **[md]** Ключевая идея: silver = bronze + явные правила трансформации + проверки качества.
|
||||||
|
|
||||||
### Секция 1: Spark-сессия и проверка bronze
|
### Секция 1: Spark-сессия и проверка bronze
|
||||||
- **[code]** SparkSession (паттерн Модулей 2-4: без `.master()`, `setLogLevel("ERROR")`). Константы, вспомогательные функции (`format_bytes`, `list_objects` — переиспользование паттерна из Модуля 4).
|
- **[code]** SparkSession (паттерн Модулей 2-4: адрес кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`). Константы, вспомогательные функции (`format_bytes`, `list_objects` — переиспользование паттерна из Модуля 4).
|
||||||
- **[code]** Assert: `spark.table(BRONZE_TABLE).count() > 0` с отсылкой к Модулю 4. Assert: `spark.table(BRONZE_LOOKUP_TABLE)` существует — при отсутствии жёсткая ошибка с отсылкой к Секции 8 Модуля 4.
|
- **[code]** Assert: `spark.table(BRONZE_TABLE).count() > 0` с отсылкой к Модулю 4. Assert: `spark.table(BRONZE_LOOKUP_TABLE)` существует — при отсутствии жёсткая ошибка с отсылкой к Секции 8 Модуля 4.
|
||||||
- **[md]** Обе bronze-таблицы на месте. Теперь строим silver.
|
- **[md]** Обе bronze-таблицы на месте. Теперь строим silver.
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ speed_mph DOUBLE (E4: новая, trip_distance / (tr
|
|||||||
|
|
||||||
- `notebooks/05_silver_layer.ipynb` можно выполнить сверху вниз в поднятом Jupyter-окружении после прохождения Модуля 4 (bronze-таблицы в каталоге).
|
- `notebooks/05_silver_layer.ipynb` можно выполнить сверху вниз в поднятом Jupyter-окружении после прохождения Модуля 4 (bronze-таблицы в каталоге).
|
||||||
- Ноутбук следует методике курса: `объяснение -> демонстрация -> самостоятельное повторение -> checkpoint`.
|
- Ноутбук следует методике курса: `объяснение -> демонстрация -> самостоятельное повторение -> checkpoint`.
|
||||||
- Ноутбук использует паттерны из Модулей 1-4: SparkSession без `.master()`, `setLogLevel("ERROR")`.
|
- Ноутбук использует паттерны из Модулей 1-4: SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`.
|
||||||
- Ноутбук идемпотентен: повторное выполнение (`CREATE OR REPLACE`) не дублирует данные и не роняет ячейки.
|
- Ноутбук идемпотентен: повторное выполнение (`CREATE OR REPLACE`) не дублирует данные и не роняет ячейки.
|
||||||
- CTAS использует явный список колонок, а не `SELECT *`.
|
- CTAS использует явный список колонок, а не `SELECT *`.
|
||||||
- Правила трансформации зафиксированы в markdown-таблице перед кодом, а не только в коде.
|
- Правила трансформации зафиксированы в markdown-таблице перед кодом, а не только в коде.
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ RUN pip3 install --no-cache-dir \
|
|||||||
- `notebooks/06_spark_and_trino_on_same_table.ipynb` выполняется сверху вниз после прохождения Модуля 5 без внешних зависимостей (DBeaver не обязателен).
|
- `notebooks/06_spark_and_trino_on_same_table.ipynb` выполняется сверху вниз после прохождения Модуля 5 без внешних зависимостей (DBeaver не обязателен).
|
||||||
- Ноутбук содержит живой цикл write → read: Spark создаёт таблицу, Trino читает.
|
- Ноутбук содержит живой цикл write → read: Spark создаёт таблицу, Trino читает.
|
||||||
- Методика курса: объяснение -> демонстрация -> самостоятельное повторение -> checkpoint.
|
- Методика курса: объяснение -> демонстрация -> самостоятельное повторение -> checkpoint.
|
||||||
- Паттерны Модулей 1-5: SparkSession без `.master()`, `setLogLevel("ERROR")`.
|
- Паттерны Модулей 1-5: SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`.
|
||||||
- Trino-запросы — в исполняемых code cells через Python `trino` клиент. DBeaver-подсказки — в markdown.
|
- Trino-запросы — в исполняемых code cells через Python `trino` клиент. DBeaver-подсказки — в markdown.
|
||||||
- При отсутствии silver — assert с отсылкой к Модулю 5. Схема silver: не менее 24 колонок (допускается расширенная схема после Модуля 5).
|
- При отсутствии silver — assert с отсылкой к Модулю 5. Схема silver: не менее 24 колонок (допускается расширенная схема после Модуля 5).
|
||||||
- Текст на русском с параллелями к PostgreSQL/Greenplum.
|
- Текст на русском с параллелями к PostgreSQL/Greenplum.
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ print(f"Демо-таблица пересоздана: {spark.table(DEMO_TABLE)
|
|||||||
- `notebooks/07_safe_table_changes.ipynb` выполняется сверху вниз после прохождения Модуля 6 без внешних зависимостей (DBeaver не обязателен).
|
- `notebooks/07_safe_table_changes.ipynb` выполняется сверху вниз после прохождения Модуля 6 без внешних зависимостей (DBeaver не обязателен).
|
||||||
- Ноутбук содержит: демонстрацию schema evolution (`ADD COLUMN` на silver), time travel (`VERSION AS OF`), recovery (`rollback_to_snapshot`), демонстрацию влияния `RENAME COLUMN` на downstream.
|
- Ноутбук содержит: демонстрацию schema evolution (`ADD COLUMN` на silver), time travel (`VERSION AS OF`), recovery (`rollback_to_snapshot`), демонстрацию влияния `RENAME COLUMN` на downstream.
|
||||||
- Методика курса: объяснение -> демонстрация -> самостоятельное повторение -> checkpoint.
|
- Методика курса: объяснение -> демонстрация -> самостоятельное повторение -> checkpoint.
|
||||||
- Паттерны Модулей 1-6: SparkSession без `.master()`, `setLogLevel("ERROR")`, `trino_query()`.
|
- Паттерны Модулей 1-6: SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`, `trino_query()`.
|
||||||
- Schema evolution на silver: только `ADD COLUMN` (безопасная операция). Опасные операции — на демо-таблице.
|
- Schema evolution на silver: только `ADD COLUMN` (безопасная операция). Опасные операции — на демо-таблице.
|
||||||
- При отсутствии silver — assert с отсылкой к Модулю 5.
|
- При отсутствии silver — assert с отсылкой к Модулю 5.
|
||||||
- Текст на русском с параллелями к PostgreSQL/Greenplum.
|
- Текст на русском с параллелями к PostgreSQL/Greenplum.
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ except Exception as e:
|
|||||||
- `notebooks/08_maintenance_and_final_lab.ipynb` выполняется сверху вниз после прохождения Модуля 6 без внешних зависимостей (DBeaver не обязателен, Модуль 7 рекомендуется, но не обязателен).
|
- `notebooks/08_maintenance_and_final_lab.ipynb` выполняется сверху вниз после прохождения Модуля 6 без внешних зависимостей (DBeaver не обязателен, Модуль 7 рекомендуется, но не обязателен).
|
||||||
- Ноутбук содержит: демонстрацию проблемы мелких файлов, compaction (`rewrite_data_files`), expire_snapshots, финальную сквозную практику.
|
- Ноутбук содержит: демонстрацию проблемы мелких файлов, compaction (`rewrite_data_files`), expire_snapshots, финальную сквозную практику.
|
||||||
- Методика курса: объяснение → демонстрация → самостоятельное повторение → checkpoint.
|
- Методика курса: объяснение → демонстрация → самостоятельное повторение → checkpoint.
|
||||||
- Паттерны Модулей 1–7: SparkSession без `.master()`, `setLogLevel("ERROR")`, `trino_query()`.
|
- Паттерны Модулей 1–7: SparkSession с адресом кластера из `spark-defaults.conf`, `setLogLevel("ERROR")`, `trino_query()`.
|
||||||
- Демо-таблица `taxi_maintenance_demo` создаётся и удаляется внутри ноутбука.
|
- Демо-таблица `taxi_maintenance_demo` создаётся и удаляется внутри ноутбука.
|
||||||
- Финальная практика в отдельном namespace `lakehouse.final` с полным cleanup в конце.
|
- Финальная практика в отдельном namespace `lakehouse.final` с полным cleanup в конце.
|
||||||
- При отсутствии silver — assert с отсылкой к Модулю 5. При отсутствии raw-данных в MinIO — assert с отсылкой к Модулю 3.
|
- При отсутствии silver — assert с отсылкой к Модулю 5. При отсутствии raw-данных в MinIO — assert с отсылкой к Модулю 3.
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# spark/spark-defaults.conf
|
# spark/spark-defaults.conf
|
||||||
|
|
||||||
|
# Адрес Spark-кластера для новых сессий
|
||||||
|
spark.master spark://spark-master:7077
|
||||||
|
|
||||||
# Включаем Iceberg extensions
|
# Включаем Iceberg extensions
|
||||||
spark.sql.extensions org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
|
spark.sql.extensions org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
|
||||||
|
|
||||||
|
|||||||
@@ -2,30 +2,29 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from pyspark.sql import SparkSession
|
from pyspark.sql import SparkSession
|
||||||
|
|
||||||
DEFAULT_MASTER_URL = "spark://spark-master:7077"
|
EXPECTED_MASTER_URL = "spark://spark-master:7077"
|
||||||
DEFAULT_APP_NAME = "cluster-smoke"
|
DEFAULT_APP_NAME = "cluster-smoke"
|
||||||
DEFAULT_ROW_COUNT = 1_000_000
|
DEFAULT_ROW_COUNT = 1_000_000
|
||||||
|
|
||||||
|
|
||||||
def create_spark_session(
|
def create_spark_session(
|
||||||
app_name: str = DEFAULT_APP_NAME,
|
app_name: str = DEFAULT_APP_NAME,
|
||||||
master_url: str = DEFAULT_MASTER_URL,
|
|
||||||
) -> SparkSession:
|
) -> SparkSession:
|
||||||
"""Создать SparkSession для проверок окружения в Модуле 1.
|
"""Создать SparkSession для проверок окружения в Модуле 1.
|
||||||
|
|
||||||
Функция специально остаётся минимальной и опирается на смонтированный
|
Адрес кластера и настройки Iceberg и MinIO заданы в spark-defaults.conf.
|
||||||
в контейнер `spark-defaults.conf` для остальной Spark/Iceberg-конфигурации.
|
|
||||||
"""
|
"""
|
||||||
return SparkSession.builder.appName(app_name).master(master_url).getOrCreate()
|
return SparkSession.builder.appName(app_name).getOrCreate()
|
||||||
|
|
||||||
|
|
||||||
def run_cluster_smoke(spark: SparkSession, row_count: int = DEFAULT_ROW_COUNT) -> dict:
|
def run_cluster_smoke(spark: SparkSession, row_count: int = DEFAULT_ROW_COUNT) -> dict:
|
||||||
spark_context = spark.sparkContext
|
spark_context = spark.sparkContext
|
||||||
master_url = spark_context.master
|
master_url = spark_context.master
|
||||||
|
|
||||||
if master_url.startswith("local"):
|
if master_url != EXPECTED_MASTER_URL:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Smoke test must run against the Spark cluster, not local mode."
|
"Smoke test must run against "
|
||||||
|
f"{EXPECTED_MASTER_URL}, got {master_url}."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Берём больше партиций, чем даёт defaultParallelism, чтобы задача точно
|
# Берём больше партиций, чем даёт defaultParallelism, чтобы задача точно
|
||||||
|
|||||||
Reference in new issue
Block a user