Spark - repartition() vs coalesce()

Согласно Learning Spark

Имейте в виду, что перераспределение ваших данных - довольно дорогостоящая операция. Spark также имеет оптимизированную версию repartition(), называемую coalesce(), которая позволяет избежать перемещения данных, но только если вы уменьшаете количество разделов RDD.

Единственное различие, которое я получаю, заключается в том, что при перераспределении() число разделов может быть увеличено/уменьшено, но с coalesce() количество разделов может быть уменьшено только.

Если разделы распределены между несколькими машинами и запущен процесс coalesce(), как он может избежать перемещения данных?

Ответ 1

Это позволяет избежать полной перетасовки. Если известно, что число уменьшается, то исполнитель может безопасно хранить данные на минимальном количестве разделов, только перемещая данные с лишних узлов на узлы, которые мы сохранили.

Итак, это будет выглядеть примерно так:

Node 1 = 1,2,3
Node 2 = 4,5,6
Node 3 = 7,8,9
Node 4 = 10,11,12

Затем coalesce до двух разделов:

Node 1 = 1,2,3 + (10,11,12)
Node 3 = 7,8,9 + (4,5,6)

Обратите внимание, что Node 1 и Node 3 не требовали перемещения исходных данных.

Ответ 2

Ответ Джастина является удивительным, и этот ответ становится более глубоким.

Алгоритм repartition выполняет полную перетасовку и создает новые разделы с данными, которые распределяются равномерно. Позвольте создать DataFrame с номерами от 1 до 12.

val x = (1 to 12).toList
val numbersDf = x.toDF("number")

numbersDf содержит 4 раздела на моей машине.

numbersDf.rdd.partitions.size // => 4

Вот как данные разделяются на разделы:

Partition 00000: 1, 2, 3
Partition 00001: 4, 5, 6
Partition 00002: 7, 8, 9
Partition 00003: 10, 11, 12

Позвольте выполнить полный переход с помощью метода repartition и получить эти данные на двух узлах.

val numbersDfR = numbersDf.repartition(2)

Вот как данные numbersDfR разбиваются на мою машину:

Partition A: 1, 3, 4, 6, 7, 9, 10, 12
Partition B: 2, 5, 8, 11

Метод repartition создает новые разделы и равномерно распределяет данные в новых разделах (распределение данных более равномерно для больших наборов данных).

Разница между coalesce и repartition

coalesce использует существующие разделы, чтобы минимизировать количество перетасованных данных. repartition создает новые разделы и выполняет полную перетасовку. coalesce приводит к разделам с разным объемом данных (иногда разделов с разными размерами) и repartition приводит к примерно равным размерам разделов.

Является ли coalesce или repartition быстрее?

coalesce может работать быстрее, чем repartition, но разделы с неравным размером, как правило, работают медленнее, чем разделы с равным размером. Как правило, вам необходимо перераспределить наборы данных после фильтрации большого набора данных. Я нашел repartition быстрее, потому что Spark построен для работы с равными размерами разделов.

Прочитайте этот пост в блоге, если вы хотите получить более подробную информацию.

Ответ 3

Еще один момент, который следует отметить здесь, состоит в том, что, поскольку основным принципом Spark RDD является неизменяемость. Перераспределение или совместное создание нового RDD. Базовый RDD будет продолжать существовать с его первоначальным количеством разделов. В случае использования прецедента для сохранения RDD в кеше, то это же должно быть сделано для вновь созданного RDD.

scala> pairMrkt.repartition(10)
res16: org.apache.spark.rdd.RDD[(String, Array[String])] =MapPartitionsRDD[11] at repartition at <console>:26

scala> res16.partitions.length
res17: Int = 10

scala>  pairMrkt.partitions.length
res20: Int = 2

Ответ 4

Все ответы добавляют некоторые большие знания в этот очень часто задаваемый вопрос.

Итак, по традиции этого вопроса, вот мои 2 цента.

Я обнаружил, что перераспределение быстрее, чем слияние, в очень конкретном случае.

В моем приложении, когда количество файлов, которые мы оцениваем, ниже определенного порога, перераспределение работает быстрее.

Вот что я имею в виду

if(numFiles > 20)
    df.coalesce(numFiles).write.mode(SaveMode.Overwrite).parquet(dest)
else
    df.repartition(numFiles).write.mode(SaveMode.Overwrite).parquet(dest)

В вышеприведенном фрагменте, если мои файлы были меньше 20, coalesce продолжал заканчиваться, а перераспределение было намного быстрее, и поэтому приведенный выше код.

Конечно, это число (20) будет зависеть от количества рабочих и количества данных.

Надеюсь, что это поможет.

Ответ 5

repartition - рекомендуется использовать перераспределение, не увеличивая количество разделов, потому что оно предполагает перетасовку всех данных.

coalesce - рекомендуется использовать coalesce, уменьшая количество перегородок. Например, если у вас есть 3 раздела и вы хотите уменьшить его до 2 разделов, Coalesce переместит данные 3-го раздела в раздел 1 и 2. Раздел 1 и 2 останется в одном и том же контейнере. Но разделение будет перетасовывать данные во всех разделах, поэтому использование сети между исполнителем будет высоким, и это влияет на производительность.

Мудрая производительность coalesce производительность лучше, чем repartition, уменьшая количество разделов.

Ответ 6

Простым способом COALESCE: - только для уменьшения количества разделов, без перетасовки данных он просто сжимает разделы

REPARTITION: - для увеличения и уменьшения количества разделов, но происходит перетасовка

Пример: -

val rdd = sc.textFile("path",7)
rdd.repartition(10)
rdd.repartition(2)

Оба отлично работают

Но мы идем в общем за эти две вещи, когда нам нужно видеть вывод в одном кластере, идем с этим.

Ответ 7

Ко всем отличным ответам я хотел бы добавить, что повторное разбиение является одним из лучших вариантов использования распараллеливания данных, а объединение дает дешевый вариант сокращения раздела и очень полезно при записи данных в HDFS или какой-либо другой приемник, чтобы воспользоваться преимуществами большой пишет. Я нашел это полезным при записи данных в формате паркета, чтобы получить полное преимущество.

Ответ 8

Я хотел бы добавить к Джастину и Пауэр ответ, что -

"передел" будет игнорировать существующие разделы и создавать новые. Таким образом, вы можете использовать его для исправления перекоса данных. Вы можете упомянуть ключи разделов, чтобы определить распределение. Перекос данных - одна из самых больших проблем в пространстве больших данных.

"coalesce" будет работать с существующими разделами и перетасовывать их подмножество. Он не может исправить перекос данных так же, как "перераспределение". так что даже если это дешевле, это может быть не то, что вам нужно.

Ответ 9

Из кода и документов документа следует, что coalesce(n) - это то же самое, что coalesce(n, shuffle = false) а repartition(n) - это как coalesce(n, shuffle = true)

Таким образом, coalesce и repartition могут быть использованы для увеличения числа разделов

С shuffle = true вы можете объединить большее количество разделов. Это полезно, если у вас есть небольшое количество разделов, скажем, 100, потенциально с несколькими разделами, которые являются необычно большими.

Еще одно важное замечание, которое необходимо подчеркнуть, заключается в том, что если вы резко уменьшите количество разделов, вам следует рассмотреть возможность использования смешанной версии coalesce (то же самое, что и repartition в этом случае). Это позволит выполнять ваши вычисления параллельно на родительских разделах (несколько задач).

Однако, если вы делаете резкое объединение, например, с numPartitions = 1, это может привести к тому, что ваши вычисления будут выполняться на меньшем количестве узлов, чем вам нравится (например, один узел в случае numPartitions = 1). Чтобы избежать этого, вы можете передать shuffle = true. Это добавит случайный шаг, но означает, что текущие разделы восходящего потока будут выполняться параллельно (независимо от текущего разделения).

Пожалуйста, также обратитесь к соответствующему ответу здесь

Ответ 10

Но также вы должны убедиться, что данные, которые поступают на объединенные узлы, должны быть хорошо сконфигурированы, если вы имеете дело с огромными данными. Поскольку все данные будут загружены в эти узлы, может возникнуть исключение памяти. Хотя возмещение затратно, я предпочитаю им пользоваться. Так как он перемешивает и распределяет данные одинаково.

Будь мудрым, чтобы выбрать между объединением и переделом.

Ответ 11

Для кого-то, у кого были проблемы с генерацией одного CSV файла из PySpark (AWS EMR) в качестве вывода и сохранением его на s3, помогло перераспределение. Причина в том, что объединение не может сделать полную перестановку, но перераспределение может. По сути, вы можете увеличить или уменьшить количество разделов, используя перераспределение, но можете только уменьшить количество разделов (но не 1), используя объединение. Вот код для тех, кто пытается записать CSV из AWS EMR в s3:

df.repartition(1).write.format('csv')\
.option("path", "s3a://my.bucket.name/location")\
.save(header = 'true')

Ответ 12

Передел: - перетасовать данные в новое количество разделов

Например. наш начальный фрейм данных разделен на 200 разделов.

df.repartition(500): данные будут перетасовываться с 200 разделов на новые 500 разделов

Объединить: перемешать данные в число разделов

df.coalesce(5): данные будут перетасованы из оставшихся 15 разделов