Según Learning Spark
Ten en cuenta que reparticionar tus datos es una operación bastante cara. Spark también tiene una versión optimizada de repartition() llamada coalesce() que permite evitar el movimiento de datos, pero sólo si estás disminuyendo el número de particiones del RDD.
Una diferencia que obtengo es que con repartition() se puede aumentar/disminuir el número de particiones, pero con coalesce() sólo se puede disminuir el número de particiones.
Si las particiones están repartidas en varias máquinas y se ejecuta coalesce(), ¿cómo puede evitar el movimiento de datos?
Evita una barajada completa. Si se sabe que el número es decreciente, entonces el ejecutor puede mantener con seguridad los datos en el número mínimo de particiones, sólo moviendo los datos fuera de los nodos extra, en los nodos que mantuvimos.
Entonces, sería algo así:
Node 1 = 1,2,3
Node 2 = 4,5,6
Node 3 = 7,8,9
Node 4 = 10,11,12
Entonces "coalesce" hasta 2 particiones:
Node 1 = 1,2,3 + (10,11,12)
Node 3 = 7,8,9 + (4,5,6)
Obsérvese que el Nodo 1 y el Nodo 3 no necesitaron sus datos originales para moverse.
La respuesta de Justin's es impresionante y esta respuesta profundiza en ella.
El algoritmo de repartición
hace una barajada completa y crea nuevas particiones con datos distribuidos uniformemente. Vamos a crear un DataFrame con los números del 1 al 12.
val x = (1 to 12).toList
val numbersDf = x.toDF("number")
numbersDf
contiene 4 particiones en mi máquina.
numbersDf.rdd.partitions.size // => 4
Así es como se dividen los datos en las particiones:
Partition 00000: 1, 2, 3
Partition 00001: 4, 5, 6
Partition 00002: 7, 8, 9
Partition 00003: 10, 11, 12
Hagamos un barrido completo con el método repartition
y obtengamos estos datos en dos nodos.
val numbersDfR = numbersDf.repartition(2)
Así es como se particionan los datos de numbersDfR
en mi máquina:
Partition A: 1, 3, 4, 6, 7, 9, 10, 12
Partition B: 2, 5, 8, 11
El método repartition
hace nuevas particiones y distribuye uniformemente los datos en las nuevas particiones (la distribución de los datos es más uniforme para conjuntos de datos más grandes).
Diferencia entre coalesce
y repartition
El coalesce
utiliza las particiones existentes para minimizar la cantidad de datos que se barajan. La función repartition
crea nuevas particiones y baraja todos los datos. El resultado de coalesce
son particiones con diferentes cantidades de datos (a veces particiones con tamaños muy diferentes) y el resultado de repartition
son particiones con tamaños más o menos iguales.
**¿Es más rápido el coalesce
o el repartition
?
coalesce
puede ser más rápido que repartition
, pero las particiones de tamaño desigual son generalmente más lentas de trabajar que las de tamaño igual. Normalmente tendrá que reparticionar los conjuntos de datos después de filtrar un gran conjunto de datos. He encontrado que repartition
es más rápido en general porque Spark está construido para trabajar con particiones de igual tamaño.
Lee esta entrada del blog si quieres más detalles.
Un punto adicional a tener en cuenta aquí es que, como el principio básico de Spark RDD es la inmutabilidad. La repartición o coalescencia creará un nuevo RDD. El RDD base seguirá existiendo con su número original de particiones. En caso de que el caso de uso exija persistir el RDD en la caché, entonces lo mismo tiene que hacerse para el RDD recién creado.
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