Spark - repartition () vs coalesce ()


254

Secondo Learning Spark

Tieni presente che il ripartizionamento dei dati è un'operazione abbastanza costosa. Spark ha anche una versione ottimizzata di repartition()chiamato coalesce()che consente di evitare lo spostamento dei dati, ma solo se si sta diminuendo il numero di partizioni RDD.

Una differenza che ottengo è che con repartition()il numero di partizioni può essere aumentato / diminuito, ma con coalesce()il numero di partizioni può essere solo ridotto.

Se le partizioni sono distribuite su più macchine e coalesce()vengono eseguite, come può evitare lo spostamento dei dati?

Risposte:


354

Evita uno shuffle completo . Se è noto che il numero sta diminuendo, l'esecutore può conservare in modo sicuro i dati sul numero minimo di partizioni, spostando i dati solo dai nodi extra, sui nodi che abbiamo mantenuto.

Quindi, andrebbe qualcosa del genere:

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

Quindi coalescefino a 2 partizioni:

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

Si noti che il nodo 1 e il nodo 3 non richiedono lo spostamento dei dati originali.


115
Grazie per la risposta. La documentazione avrebbe dovuto dire meglio minimize data movementinvece di avoiding data movement.
Praveen Sripati,

12
C'è un caso in cui repartitiondovrebbe essere usato invece di coalesce?
Niemand,

21
@Niemand Penso che la documentazione attuale copra abbastanza bene: github.com/apache/spark/blob/… Tieni presente che tutto repartitionciò che fa è chiamare coalescecon il shuffleparametro impostato su true. Fammi sapere se questo aiuta.
Justin Pihony,

2
È possibile ridurre il numero di file di partizione esistenti? Non ho hdf, ma ho problemi con molti file.

2
la ripartizione sarà statisticamente più lenta poiché non sa che si sta riducendo ... anche se forse potrebbero ottimizzarla. Internamente chiama solo coalescenza con una shuffle = truebandiera
Justin Pihony,

171

La risposta di Justin è fantastica e questa risposta è più approfondita.

L' repartitionalgoritmo esegue un shuffle completo e crea nuove partizioni con dati distribuiti uniformemente. Creiamo un DataFrame con i numeri da 1 a 12.

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

numbersDf contiene 4 partizioni sulla mia macchina.

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

Ecco come vengono suddivisi i dati sulle partizioni:

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

Facciamo un shuffle completo con il repartitionmetodo e otteniamo questi dati su due nodi.

val numbersDfR = numbersDf.repartition(2)

Ecco come numbersDfRvengono partizionati i dati sulla mia macchina:

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

Il repartitionmetodo crea nuove partizioni e distribuisce uniformemente i dati nelle nuove partizioni (la distribuzione dei dati è più uniforme anche per set di dati più grandi).

Differenza tra coalesceerepartition

coalesceutilizza le partizioni esistenti per ridurre al minimo la quantità di dati che vengono mescolati. repartitioncrea nuove partizioni e fa un riordino completo. coalescerisulta in partizioni con diverse quantità di dati (a volte partizioni con dimensioni molto diverse) e repartitiongenera partizioni di dimensioni approssimativamente uguali.

È coalesceo repartitionpiù veloce?

coalescepuò essere eseguito più velocemente di repartition, ma le partizioni di dimensioni diverse sono generalmente più lente da lavorare rispetto alle partizioni di dimensioni uguali. In genere è necessario ripartizionare i set di dati dopo aver filtrato un set di dati di grandi dimensioni. Ho trovato repartitioncomplessivamente più veloce perché Spark è progettato per funzionare con partizioni di uguali dimensioni.

NB Ho curiosamente osservato che la ripartizione può aumentare la dimensione dei dati sul disco . Assicurati di eseguire i test quando utilizzi la ripartizione / coalescenza su set di dati di grandi dimensioni.

Leggi questo post sul blog se desideri ulteriori dettagli.

Quando in pratica utilizzerai la coalizione e la ripartizione


8
Ottima risposta @Powers, ma i dati nelle partizioni A e B non sono distorti? Come viene distribuito uniformemente?
Anwartheravian il

Inoltre, qual è il modo migliore per ottenere la dimensione della partizione senza ottenere errori OOM. Uso rdd.glom().map(len).collect()ma dà molti errori OOM.
Anwartheravian

8
@anwartheravian - La partizione A e la partizione B hanno dimensioni diverse perché l' repartitionalgoritmo non distribuisce i dati allo stesso modo per set di dati molto piccoli. Ho usato repartitionper organizzare 5 milioni di dischi in 13 partizioni e ogni file è stato tra i 89,3 MB e 89,6 MB - che è abbastanza uguali!
Poteri

1
@Per questo aspetto, rispondi meglio con i dettagli.
Verde

1
Questo spiega la differenza molto meglio. Grazie!
Abhi

22

Un altro punto da notare qui è che, poiché il principio di base di Spark RDD è l'immutabilità. La ripartizione o la coalizione creerà un nuovo RDD. Il RDD di base continuerà a esistere con il suo numero originale di partizioni. Nel caso in cui il caso d'uso richieda di mantenere RDD nella cache, lo stesso deve essere fatto per il nuovo RDD creato.

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

Ben fatto! questo è fondamentale e almeno per questo esperto scala dev, non ovvio - cioè, né la ripartizione né il tentativo di coalizione di modificare i dati, proprio come sono distribuiti tra i nodi
doug

1
@Harikrishnan, quindi se ho capito bene le altre risposte, allora per loro in caso di coalescenza Spark utilizza partizioni esistenti, tuttavia, poiché RDD è immutabile, puoi descrivere come Coalesce utilizza le partizioni esistenti? Secondo la mia comprensione, ho pensato che Spark aggiungesse nuove partizioni alle partizioni esistenti in coalizione.
Explorer

Ma se il "vecchio" RDD non viene più utilizzato come è noto dal grafico di esecuzione, verrà cancellato dalla memoria se non persisterà, non è vero?
Markus,

15

repartition - si consiglia di usarlo aumentando il numero di partizioni, poiché comporta la mescolanza di tutti i dati.

coalesce- si consiglia di utilizzarlo riducendo il numero di partizioni. Ad esempio, se si dispone di 3 partizioni e si desidera ridurla a 2, coalescei dati della terza partizione verranno spostati sulla partizione 1 e 2. Le partizioni 1 e 2 rimarranno nello stesso contenitore. D'altra parte, repartitionmescolerà i dati in tutte le partizioni, pertanto l'utilizzo della rete tra gli esecutori sarà elevato e influirà sulle prestazioni.

coalesceoffre prestazioni migliori rispetto alla repartitionriduzione del numero di partizioni.


Spiegazione utile.
Narendra Maru,

11

Ciò che segue dal codice e dai documenti del codice coalesce(n)è lo stesso di coalesce(n, shuffle = false)ed repartition(n)è lo stesso dicoalesce(n, shuffle = true)

Pertanto, entrambi coalescee repartitionpossono essere utilizzati per aumentare il numero di partizioni

Con shuffle = true, puoi effettivamente fondere un numero maggiore di partizioni. Ciò è utile se si dispone di un numero limitato di partizioni, ad esempio 100, potenzialmente con alcune partizioni di dimensioni anomale.

Un'altra nota importante da sottolineare è che se si riduce drasticamente il numero di partizioni si dovrebbe considerare di utilizzare la versione shufflecoalesce (uguale repartitiona quella in quel caso). Ciò consentirà che i tuoi calcoli vengano eseguiti in parallelo su partizioni padre (attività multiple).

Tuttavia, se si esegue una drastica coalescenza, ad esempio numPartitions = 1, ciò può comportare che il calcolo avvenga su un numero di nodi inferiore a quello desiderato (ad esempio un nodo nel caso di numPartitions = 1). Per evitarlo, puoi passare shuffle = true. Ciò aggiungerà un passaggio casuale, ma significa che le attuali partizioni a monte verranno eseguite in parallelo (per qualunque sia l'attuale partizionamento).

Fare riferimento anche alla relativa risposta qui


10

Tutte le risposte aggiungono una grande conoscenza a questa domanda molto frequente.

Quindi, secondo la tradizione della sequenza temporale di questa domanda, ecco i miei 2 centesimi.

Ho trovato la ripartizione più veloce della coalizione , in casi molto specifici.

Nella mia applicazione quando il numero di file che stimiamo è inferiore alla determinata soglia, la ripartizione funziona più velocemente.

Ecco cosa intendo

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

Nello snippet sopra, se i miei file erano meno di 20, il coalesce impiegava un'eternità per finire mentre la ripartizione era molto più veloce e quindi il codice sopra.

Naturalmente, questo numero (20) dipenderà dal numero di lavoratori e dalla quantità di dati.

Spero che aiuti.


6

Ripartizione : mescola i dati in un NUOVO numero di partizioni.

Per esempio. Il frame di dati iniziale è partizionato in 200 partizioni.

df.repartition(500): I dati verranno trasferiti da 200 partizioni a nuove 500 partizioni.

Coalesce : mescola i dati in un numero esistente di partizioni.

df.coalesce(5): I dati verranno trasferiti dalle restanti 195 partizioni a 5 partizioni esistenti.


3

Vorrei aggiungere alla risposta di Justin e Power che:

repartitionignorerà le partizioni esistenti e ne creerà di nuove. Quindi puoi usarlo per correggere l'inclinazione dei dati. È possibile menzionare le chiavi di partizione per definire la distribuzione. L'inclinazione dei dati è uno dei maggiori problemi nello spazio problematico dei "big data".

coalescefunzionerà con le partizioni esistenti e mescolerà un sottoinsieme di esse. Non può correggere l'inclinazione dei dati tanto quanto repartitionfa. Pertanto, anche se è meno costoso, potrebbe non essere la cosa di cui hai bisogno.


3

A tutte le grandi risposte che vorrei aggiungere, questa repartitionè una delle migliori opzioni per trarre vantaggio dalla parallelizzazione dei dati. Mentre coalesceoffre un'opzione economica per ridurre le partizioni ed è molto utile quando si scrivono dati su HDFS o su qualche altro sink per sfruttare grandi scritture.

Ho trovato questo utile quando si scrivono dati in formato parquet per ottenere il massimo vantaggio.


2

Per qualcuno che ha avuto problemi a generare un singolo file CSV da PySpark (AWS EMR) come output e salvarlo su s3, l'utilizzo della ripartizione ha aiutato. Il motivo è che la coalizione non può fare un shuffle completo, ma la ripartizione può. In sostanza, puoi aumentare o diminuire il numero di partizioni usando la ripartizione, ma puoi solo diminuire il numero di partizioni (ma non 1) usando la coalizione. Ecco il codice per chiunque stia cercando di scrivere un csv da AWS EMR a s3:

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

0

In modo semplice COALESCE: - serve solo per ridurre il no delle partizioni, nessun mescolamento dei dati comprime solo le partizioni

REPARTITION: - serve sia per aumentare che per diminuire il no delle partizioni, ma avviene lo shuffle

Esempio:-

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

Entrambi funzionano bene

Ma andiamo generalmente per queste due cose quando abbiamo bisogno di vedere l'output in un cluster, andiamo con questo.


9
Ci saranno anche spostamenti di dati con Coalese.
sun_dare,

0

Ma dovresti anche assicurarti che i dati provenienti dai nodi di coalescenza dovrebbero essere altamente configurati, se hai a che fare con dati enormi. Poiché tutti i dati verranno caricati su tali nodi, è possibile che si verifichino eccezioni di memoria. Sebbene la riparazione sia costosa, preferisco usarla. Dal momento che mescola e distribuisce i dati allo stesso modo.

Sii saggio scegliere tra coalescenza e ripartizione.


0

L' repartitionalgoritmo esegue un shuffle completo dei dati e crea partizioni di dimensioni uguali. coalescecombina le partizioni esistenti per evitare un riordino completo.

Coalesce funziona bene per prendere un RDD con molte partizioni e combinare le partizioni su un singolo nodo di lavoro per produrre un RDD finale con meno partizioni.

Repartitionrimescolerà i dati nel tuo RDD per produrre il numero finale di partizioni richieste. Il partizionamento di DataFrames sembra un dettaglio di implementazione di basso livello che dovrebbe essere gestito dal framework, ma non lo è. Quando si filtrano grandi DataFrame in file più piccoli, è necessario ripartizionare quasi sempre i dati. Probabilmente filtrerai frequentemente DataFrame grandi in file più piccoli, quindi abituati al ripartizionamento.

Leggi questo post sul blog se desideri ulteriori dettagli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.