Spark - répartition () vs coalesce ()


254

Selon Learning Spark

Gardez à l'esprit que la répartition de vos données est une opération assez coûteuse. Spark a également une version optimisée de repartition()appelée coalesce()qui permet d'éviter le mouvement des données, mais uniquement si vous diminuez le nombre de partitions RDD.

Une différence que j'obtiens est qu'avec repartition()le nombre de partitions peut être augmenté / diminué, mais avec coalesce()le nombre de partitions peut seulement être diminué.

Si les partitions sont réparties sur plusieurs machines et coalesce()exécutées, comment éviter le mouvement des données?

Réponses:


354

Cela évite un shuffle complet . S'il est connu que le nombre diminue, l'exécuteur peut conserver en toute sécurité les données sur le nombre minimum de partitions, en déplaçant uniquement les données des nœuds supplémentaires vers les nœuds que nous avons conservés.

Donc, ça irait quelque chose comme ceci:

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

Ensuite coalesce, jusqu'à 2 partitions:

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

Notez que le nœud 1 et le nœud 3 n'ont pas eu besoin de déplacer leurs données d'origine.


115
Merci pour la réponse. La documentation aurait dû mieux dire minimize data movementau lieu de avoiding data movement.
Praveen Sripati

12
Y a-t-il un cas où repartitiondevrait être utilisé à la place de coalesce?
Niemand

21
@Niemand Je pense que la documentation actuelle couvre assez bien cela: github.com/apache/spark/blob/… Gardez à l'esprit que tout repartitionest appelé coalesceavec le shuffleparamètre défini sur true. Faites-moi savoir si cela vous a été utile.
Justin Pihony

2
Est-il possible de réduire le nombre de fichiers de partition existants? Je n'ai pas de hdfs, mais problème avec de nombreux fichiers.

2
la répartition sera statistiquement plus lente car elle ne sait pas qu'elle diminue ... bien qu'ils pourraient peut-être optimiser cela. En interne, il appelle juste coalesce avec un shuffle = truedrapeau
Justin Pihony

172

La réponse de Justin est impressionnante et cette réponse va plus en profondeur.

L' repartitionalgorithme effectue un shuffle complet et crée de nouvelles partitions avec des données réparties uniformément. Créons un DataFrame avec les nombres de 1 à 12.

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

numbersDf contient 4 partitions sur ma machine.

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

Voici comment les données sont réparties sur les partitions:

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

Faisons un shuffle complet avec la repartitionméthode et obtenons ces données sur deux nœuds.

val numbersDfR = numbersDf.repartition(2)

Voici comment les numbersDfRdonnées sont partitionnées sur ma machine:

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

La repartitionméthode crée de nouvelles partitions et distribue uniformément les données dans les nouvelles partitions (la distribution des données est plus uniforme pour les ensembles de données plus volumineux).

Différence entre coalesceetrepartition

coalesceutilise les partitions existantes pour minimiser la quantité de données mélangées. repartitioncrée de nouvelles partitions et fait un shuffle complet. coalesceentraîne des partitions avec différentes quantités de données (parfois des partitions de tailles très différentes) et repartitiondes partitions de taille à peu près égale.

Est coalesceou repartitionplus rapide?

coalescepeut s'exécuter plus rapidement que repartition, mais les partitions de taille inégale sont généralement plus lentes à travailler que les partitions de taille égale. Vous devrez généralement répartir les ensembles de données après avoir filtré un grand ensemble de données. J'ai trouvé repartitionplus rapide dans l'ensemble parce que Spark est conçu pour fonctionner avec des partitions de taille égale.

NB J'ai curieusement observé que la répartition peut augmenter la taille des données sur le disque . Assurez-vous d'exécuter des tests lorsque vous utilisez la répartition / fusion sur de grands ensembles de données.

Lisez cet article de blog si vous souhaitez encore plus de détails.

Quand vous utiliserez coalesce & repartition dans la pratique


8
Excellente réponse @Powers, mais les données de la partition A et B ne sont-elles pas biaisées? Comment est-il réparti uniformément?
anwartheravian

En outre, quelle est la meilleure façon d'obtenir la taille de la partition sans obtenir d'erreur OOM. J'utilise rdd.glom().map(len).collect()mais cela donne beaucoup d'erreurs OOM.
anwartheravian

8
@anwartheravian - La partition A et la partition B sont de tailles différentes car l' repartitionalgorithme ne distribue pas les données de la même manière pour les très petits ensembles de données. J'avais l'habitude repartitiond'organiser 5 millions d'enregistrements en 13 partitions et chaque fichier mesurait entre 89,3 Mo et 89,6 Mo - c'est assez égal!
Pouvoirs

1
@Powers cela semble mieux répondre avec des détails.
Vert

1
Cela explique beaucoup mieux la différence. Merci!
Abhi

22

Un point supplémentaire à noter ici est que, comme le principe de base de Spark RDD est l'immuabilité. La répartition ou la fusion créera un nouveau RDD. Le RDD de base continuera d'exister avec son nombre d'origine de partitions. Dans le cas où le cas d'utilisation demande de conserver le RDD dans le cache, la même chose doit être faite pour le RDD nouvellement créé.

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

joli! ce qui est essentiel et au moins à ce dev scala expérimenté, pas évident - à savoir, ni la répartition ni soudent tentative de modifier les données, à quel point il est réparti entre les nœuds
doug

1
@Harikrishnan donc si j'ai bien compris les autres réponses, alors selon elles en cas de fusion, Spark utilise des partitions existantes mais comme RDD est immuable, pouvez-vous décrire comment Coalesce utilise les partitions existantes? Selon ma compréhension, je pensais que Spark ajoute de nouvelles partitions aux partitions existantes en fusion.
Explorer

Mais si le "vieux" RDD n'est plus utilisé comme le sait le graphe d'exécution, il sera effacé de la mémoire s'il n'est pas persisté, n'est-ce pas?
Markus

15

repartition - il est recommandé de l'utiliser tout en augmentant le nombre de partitions, car cela implique de mélanger toutes les données.

coalesce- il est recommandé de l'utiliser tout en réduisant le nombre de partitions. Par exemple, si vous disposez de 3 partitions et que vous souhaitez la réduire à 2, coalesceles données de la 3e partition seront déplacées vers les partitions 1 et 2. Les partitions 1 et 2 resteront dans le même conteneur. D'autre part, repartitionmélangera les données dans toutes les partitions, donc l'utilisation du réseau entre les exécuteurs sera élevée et cela aura un impact sur les performances.

coalescefonctionne mieux que repartitiontout en réduisant le nombre de partitions.


Explication utile.
Narendra Maru

11

Ce qui découle du code et des documents de code, c'est que coalesce(n)c'est la même chose coalesce(n, shuffle = false)et repartition(n)c'est la même chose quecoalesce(n, shuffle = true)

Ainsi, les deux coalesceet repartitionpeuvent être utilisés pour augmenter le nombre de partitions

Avec shuffle = true, vous pouvez réellement fusionner avec un plus grand nombre de partitions. Ceci est utile si vous avez un petit nombre de partitions, disons 100, potentiellement avec quelques partitions anormalement grandes.

Une autre note importante à souligner est que si vous diminuez considérablement le nombre de partitions, vous devriez envisager d'utiliser une version mélangée de coalesce(comme repartitiondans ce cas). Cela permettra à vos calculs d'être effectués en parallèle sur les partitions parentes (tâche multiple).

Cependant, si vous effectuez une fusion drastique, par exemple pour numPartitions = 1, cela peut entraîner votre calcul sur moins de nœuds que vous le souhaitez (par exemple, un nœud dans le cas de numPartitions = 1). Pour éviter cela, vous pouvez passer shuffle = true. Cela ajoutera une étape de lecture aléatoire, mais signifie que les partitions en amont actuelles seront exécutées en parallèle (quelle que soit la partition actuelle).

Veuillez également vous référer à la réponse correspondante ici


10

Toutes les réponses ajoutent une grande connaissance à cette question très souvent posée.

Donc, selon la tradition de la chronologie de cette question, voici mes 2 cents.

J'ai trouvé la répartition plus rapide que la fusion , dans des cas très spécifiques.

Dans mon application, lorsque le nombre de fichiers que nous estimons est inférieur au certain seuil, la répartition fonctionne plus rapidement.

Voici ce que je veux dire

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

Dans l'extrait ci-dessus, si mes fichiers étaient inférieurs à 20, la fusion prendrait une éternité pour se terminer tandis que la répartition était beaucoup plus rapide et donc le code ci-dessus.

Bien sûr, ce nombre (20) dépendra du nombre de travailleurs et de la quantité de données.

J'espère que cela pourra aider.


6

Répartition : mélangez les données dans un NOUVEAU nombre de partitions.

Par exemple. La trame de données initiale est partitionnée en 200 partitions.

df.repartition(500): Les données seront transférées de 200 partitions à 500 nouvelles partitions.

Coalesce : mélangez les données dans le nombre de partitions existant.

df.coalesce(5): Les données seront mélangées des 195 partitions restantes à 5 partitions existantes.


4

J'aimerais ajouter à la réponse de Justin et Power que -

repartitionignorera les partitions existantes et en créera de nouvelles. Vous pouvez donc l'utiliser pour corriger le biais de données. Vous pouvez mentionner des clés de partition pour définir la distribution. L'asymétrie des données est l'un des plus gros problèmes dans l'espace des problèmes de «big data».

coalescefonctionnera avec les partitions existantes et mélangera un sous-ensemble d'entre elles. Il ne peut pas corriger le biais de données autant que le repartitionfait. Par conséquent, même s'il est moins cher, ce n'est peut-être pas la chose dont vous avez besoin.


3

À toutes les bonnes réponses, je voudrais ajouter que repartitionc'est l'une des meilleures options pour tirer parti de la parallélisation des données. Bien que coalescedonne une option bon marché pour réduire les partitions et il est très utile lors de l'écriture de données sur HDFS ou un autre récepteur pour tirer parti des grandes écritures.

J'ai trouvé cela utile lors de l'écriture de données au format parquet pour en tirer le meilleur parti.


2

Pour quelqu'un qui a eu des problèmes pour générer un seul fichier csv à partir de PySpark (AWS EMR) en tant que sortie et l'enregistrer sur s3, l'utilisation de la répartition a aidé. La raison en est que la fusion ne peut pas faire un remaniement complet, mais la répartition peut. Essentiellement, vous pouvez augmenter ou diminuer le nombre de partitions en utilisant la répartition, mais vous ne pouvez diminuer le nombre de partitions (mais pas 1) en utilisant la fusion. Voici le code pour quiconque essaie d'écrire un csv depuis AWS EMR vers s3:

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

0

D'une manière simple COALESCE: - est seulement pour diminue le nombre de partitions, pas de brassage des données, il suffit de compresser les partitions

RÉPARTITION: - est à la fois pour augmenter et diminuer le nombre de partitions, mais le brassage a lieu

Exemple:-

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

Les deux fonctionnent bien

Mais nous optons généralement pour ces deux choses lorsque nous devons voir la sortie dans un cluster, nous allons avec cela.


9
Il y aura également des mouvements de données avec le hongrois.
sun_dare

0

Mais vous devez également vous assurer que les données qui arrivent, les nœuds de fusion doivent avoir une configuration élevée, si vous avez affaire à des données énormes. Parce que toutes les données seront chargées sur ces nœuds, peut entraîner une exception de mémoire. Bien que la réparation soit coûteuse, je préfère l'utiliser. Puisqu'il mélange et distribue les données également.

Soyez sage de choisir entre la fusion et la répartition.


0

L' repartitionalgorithme effectue un brassage complet des données et crée des partitions de données de taille égale. coalescecombine les partitions existantes pour éviter un shuffle complet.

Coalesce fonctionne bien pour prendre un RDD avec beaucoup de partitions et combiner des partitions sur un seul nœud de travail pour produire un RDD final avec moins de partitions.

Repartitionva remanier les données dans votre RDD pour produire le nombre final de partitions que vous demandez. Le partitionnement des DataFrames semble être un détail d'implémentation de bas niveau qui devrait être géré par le framework, mais ce n'est pas le cas. Lorsque vous filtrez de gros DataFrames en plus petits, vous devez presque toujours repartitionner les données. Vous filtrerez probablement de gros DataFrames en plus petits fréquemment, alors habituez-vous au repartitionnement.

Lisez cet article de blog si vous souhaitez encore plus de détails.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.