A B C D E F G H I K L M N O P R S T V W Y Z А Б В Е И К М О П Т Ц

Lazy Evaluation

Lazy Evaluation

 

 

Lazy Evaluation (Ленивые вычисления) — это стратегия выполнения программного кода, при которой запуск вычислений откладывается до тех пор, пока их результат не потребуется явно (например, для вывода на экран или сохранения на диск). В экосистеме Big Data (в частности, в Apache Spark) этот подход является фундаментальным: он позволяет системе сначала построить полный направленный ациклический граф задач (DAG), оптимизировать его целиком и только затем выделить ресурсы на обработку данных.

В отличие от классического программирования, где команды выполняются строка за строкой, «ленивый» подход позволяет избегать ненужных вычислений, экономить оперативную память и автоматически восстанавливать потерянные данные при сбоях.

Если вы еще не знакомы с тем, как именно строятся графы задач, рекомендую сначала изучить статью: DAG (Directed Acyclic Graph) в Big Data.

 

Eager vs. Lazy Evaluations: Битва подходов

 

Чтобы понять архитектурную необходимость ленивых вычислений в Big Data, нужно сравнить их с традиционной моделью.

 

Eager Evaluation (Энергичные вычисления)

 

Это стандартный подход (например, Python Pandas или Java List). Интерпретатор выполняет выражение сразу, как только встречает его в коде.

  • Пример: Вы загружаете CSV-файл на 1 ТБ в Pandas.
  • Результат: Библиотека немедленно попытается прочитать весь файл в RAM. Программа упадет с ошибкой Out Of Memory еще до того, как вы начнете фильтровать данные.

 

Lazy Evaluation (Ленивые вычисления)

 

В этой модели вызов функции не запускает обработку данных, а лишь добавляет запись в «план действий».

  • Пример: Вы пишете команду загрузки того же CSV в Apache Spark.
  • Результат: Spark не читает файл. Он лишь запоминает метаданные (путь к файлу). Чтение начнется только тогда, когда вы запросите конкретный результат.

Архитектура ленивости: Трансформации и Действия

 

В Apache Spark код делится на два типа операций. Понимание разницы между ними критично для управления DAG.

Transformations (Трансформации)

Это «ленивые» операции. Они создают новый RDD/DataFrame из существующего. При их вызове ничего не вычисляется. Spark просто обновляет свой внутренний граф задач в соответствии с Lazy Evaluations.

  • Примеры: map, filter, flatMap, reduceByKey, join.
  • Суть: Мы просто описываем логику преобразований («Взять колонку А», «Отфильтровать Б»).

Actions (Действия)

Это спусковой крючок. Действия заставляют Spark «материализовать» план, запустить вычисления на кластере и вернуть результат.

  • Примеры: collect, count, saveAsTextFile, take.
  • Суть: Мы требуем готовый результат здесь и сейчас.

От кода к DAG: Сквозной пример  использования Lazy Evaluations

 

Лучший способ понять, как текст превращается в граф — разобрать реальный пример из spark-shell для оценки механизма Lazy eveluations.

Допустим, мы анализируем биржевые данные, чтобы найти максимальный объем торгов (volume) по каждому тикеру (symbol).

Этап 0: Подготовим стенд для опытов без Hadoop и HDFS (Ubuntu/WSL)

 

# Необходима Java и сам Spark (через pip ставится обертка)
sudo apt install default-jdk python3-pip

# Скачиваем архив (проверьте актуальную версию на сайте, здесь пример для 3.5.0)
wget https://archive.apache.org/dist/spark/spark-3.5.0/spark-3.5.0-bin-hadoop3.tgz

# Распаковываем
tar xvf spark-3.5.0-bin-hadoop3.tgz

# Переходим в папку
cd spark-3.5.0-bin-hadoop3 

#--- готовим данные Dataset 

# Создаем папку для данных
mkdir -p data

# Создаем файл с тестовыми данными (без заголовка, чтобы код не упал на .toInt)
echo "2024-01-01,AAPL,150,155,149,152,152,5000" > data/stocks.csv
echo "2024-01-02,AAPL,152,158,151,157,157,6000" >> data/stocks.csv
echo "2024-01-01,GOOGL,100,105,99,102,102,3000" >> data/stocks.csv
echo "2024-01-02,GOOGL,102,104,101,103,103,3500" >> data/stocks.csv

# --Запуск Spark Shell в локальном режимe

./bin/spark-shell --master "local[*]"

Spark dataset and preset for run jobs

 

Этап 1: Написание кода Spark (Scala)

 

Анализ данных с помощью современного Apache Spark

Код курса
SPARK
Ближайшая дата курса
16 марта, 2026
Продолжительность
32 ак.часов
Стоимость обучения
102 400

 

// 1. Читаем локальный файл (обратите внимание на file:///)
val stocks = sc.textFile("file://" + System.getProperty("user.dir") + "/data/stocks.csv")

// 2. Парсим
val splits = stocks.map(record => record.split(","))

// 3. Выделяем Тикер и Объем
val symvol = splits.map(arr => (arr(1), arr(7).toInt))

// 4. Агрегируем (reduceByKey ищет максимум)
val maxvol = symvol.reduceByKey((vol1, vol2) => Math.max(vol1, vol2))

// 5. Выводим результат
maxvol.collect().foreach(println)

Spark Job execution with staging and lazy eveluations

 

Этап 2: Что происходит в Spark (Jobs и DAG)

 

Как только вы нажали Enter на строке с .collect(), Spark превращает этот код в Job, который состоит из стадий. В Spark UI вы увидите следующий DAG:

Stage 0 (Подготовка):

Stage 0 spark jobs with DAGs

  • Spark объединяет операции textFile, первый map (split) и второй map (выбор полей) в один конвейер.
  • Pipelining: Данные считываются с диска, парсятся и фильтруются за один проход, не сохраняясь промежуточно.
  • Эта стадия заканчивается подготовкой к отправке данных по сети (Shuffle Write).

Stage 1 (Агрегация):

Stage 1 Spark job with DAGs

  • Эта стадия начинается после перемешивания данных (Shuffle Read).
  • Здесь выполняется логика reduceByKey (поиск максимума).
  • Результат отправляется на драйвер (collect).

Важно: Обратите внимание, что граница между стадиями проходит именно по reduceByKey. Ленивые вычисления позволяют Spark «схлопнуть» все map операции в Stage 0, но Shuffle всегда разрывает цепочку.

Магия оптимизации: Catalyst Optimizer

 

Главное преимущество ленивости — возможность Spark увидеть весь алгоритм целиком до запуска. Это позволяет применить глобальные оптимизации через движок Catalyst:

  • Predicate Pushdown (Проталкивание фильтров): Если бы мы добавили .filter(arr(1) == «AAPL») перед reduceByKey, Spark не стал бы агрегировать все акции. Он переместил бы фильтр в самое начало, отбросив лишние данные сразу при чтении.
  • Column Pruning (Отсечение колонок): Хотя в CSV файле может быть 100 колонок, Spark видит, что нам нужны только индексы 1 и 7. Физически с диска будут прочитаны только они ( в случае хранения данных в columnar format — Parquet/ORC).

 

Анализ данных с помощью современного Apache Spark

Код курса
SPARK
Ближайшая дата курса
16 марта, 2026
Продолжительность
32 ак.часов
Стоимость обучения
102 400

 

 

Преимущества и подводные камни Lazy Evaluation

Плюсы:

  • Отказоустойчивость (Fault Tolerance): Если сервер упадет во время расчета maxvol, Spark знает по DAG (Lineage), что данные можно восстановить, перечитав файл и повторив map. Ему не нужно начинать всё приложение с нуля.
  • Эффективность: Минимизация операций ввода-вывода (I/O).

Минусы:

  • Сложность отладки: Если в вашем файле в 7-й колонке окажется буква вместо цифры, ошибка NumberFormatException вылетит не на строке val symvol = …, а на строке maxvol.collect(). Это часто сбивает новичков с толку: ошибка указывается там, где она «всплыла», а не там, где была запрограммирована.

Заключение

Ленивые вычисления превращают Spark из простого калькулятора в умного планировщика. Когда вы пишете код на Spark или PySpark, вы не двигаете данные руками — вы строите чертеж (DAG).

В следующий раз, запустив collect() или write(), обязательно откройте Spark UI (вкладка DAG Vizualization). Если вы увидите там свои стадии, соответствующие логике кода (как в примере с stocks), значит, вы начали мыслить как инженер Big Data.

Референсные ссылки

  1. Apache Spark Architecture Explained (Apache Documentation, 2024)
  2. RDD Programming Guide (Apache Documentation, 2024)
  3. Understanding Spark’s Logical and Physical Plans (Databricks Blog, 2024)
Изменение базового тарифа с 1 января 2026 года Подробнее