Какие типы операций существуют в Apache Spark?

Ответ

В Apache Spark операции делятся на два основных типа: трансформации (transformations) и действия (actions).

Трансформации — ленивые операции, которые создают новую RDD, DataFrame или Dataset из существующей. Они не выполняются немедленно, а лишь строят граф вычислений (DAG).

  • Поэлементные преобразования: map(), flatMap(), filter().
  • Агрегации и соединения: groupBy(), reduceByKey(), join(), union().
  • Изменение партиционирования: repartition(), coalesce().

Действия — операции, которые запускают вычисления, возвращают результат в драйвер-программу или сохраняют данные. Они заставляют выполниться все накопленные трансформации.

  • Сбор данных: count(), collect(), take(), first().
  • Сохранение: saveAsTextFile(), write().parquet(), write().csv().
  • Агрегация: reduce(), aggregate(), foreach().

Пример на Scala с RDD:

// Трансформации (ленивые)
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val transformedRdd = rdd.filter(_ % 2 == 0).map(_ * 10) // Фильтр и умножение

// Действие (запускает вычисления)
val result = transformedRdd.collect() // Array(20, 40)
println(result.mkString(", "))

Ключевое отличие: Трансформации определяют что вычислять, а действия — когда начинать вычисления и что с результатом делать.

Ответ 18+ 🔞

Давай разберём эту тему, а то некоторые до сих пор путаются, как будто на дворе 2002-й год. В Apache Spark, ёпта, есть всего два типа операций, и это надо запомнить, как своё имя.

Первые — это трансформации (transformations). Это такие ленивые твари, которые нихуя не делают сразу. Они просто строят план, типа "эй, чувак, вот когда-нибудь потом мы возьмём эти данные и сделаем вот так". Создают они новый RDD, DataFrame или Dataset, но реальных вычислений пока ноль. Просто рисуют граф в воздухе, доверия ебать ноль к их исполнительности на этом этапе.

Что к ним относится? Ну, например:

  • Поэлементные преобразования: map(), flatMap(), filter() — каждый элемент по отдельности трогают.
  • Агрегации и соединения: groupBy(), reduceByKey(), join() — тут уже данные начинают общаться между собой.
  • Изменение партиционирования: repartition(), coalesce() — это когда ты решаешь, по сколько строк в каждой пачке таскать.

А вторые — это действия (actions). Вот это уже серьёзные пацаны. Это команда "пиздуй делать!". Они-то и запускают весь этот цирк, заставляя все накопленные ленивые трансформации наконец-то отработать. Результат либо возвращается к тебе в программу, либо пишется куда-то на диск.

Примеры действий:

  • Сбор данных: count(), collect(), take() — выгребают всё из кластера к драйверу. С collect() осторожно, а то можно такую овердохуища данных притащить, что драйвер накроется медным тазом.
  • Сохранение: saveAsTextFile(), write().parquet() — тут всё понятно, сохраняем и идём пить чай.
  • Агрегация: reduce(), aggregate() — сводят всё к какому-то одному значению.

Ключевое отличие, блядь, вот в чём: Трансформации — это как составить список покупок. Действия — это как пойти в магазин, отстоять очередь и всё это купить. Пока не скажешь "collect()" — никакого реального движения данных не будет, терпения ноль ебать у этой системы.

Смотри на примере, чтобы вообще ни у кого сомнений не осталось:

// Трансформации (ленивые, нихуя не происходит)
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val transformedRdd = rdd.filter(_ % 2 == 0).map(_ * 10) // Пока только планы, блядь!

// Действие (ВЖУХ! и понеслась!)
val result = transformedRdd.collect() // Вот тут Spark просыпается и начинает работать
println(result.mkString(", "))

Вот и вся магия. Запомни: пока не вызвал действие — можешь строить хоть хуй в пальто из трансформаций, вычисляться ничего не будет. Как только вызвал — ёперный театр, поехали.