Kıvılcım - repartition () vs coalesce ()


254

Kıvılcım Öğrenmeye Göre

Verilerinizi yeniden bölümlendirmenin oldukça pahalı bir işlem olduğunu unutmayın. Kıvılcım da optimize edilmiş bir sürümü var repartition()denilen coalesce()ama RDD bölüm sayısını azaltarak yalnızca eğer, veri hareketini üstesinden gelinebileceğini.

Aldığım bir fark repartition(), bölüm sayısı ile artırılabilir / azaltılabilir, ancak coalesce()bölüm sayısı ile sadece azaltılabilir.

Bölümler birden çok makineye yayılmışsa ve coalesce()çalıştırılıyorsa, veri hareketini nasıl önleyebilir?

Yanıtlar:


354

Tam bir karıştırmayı önler . Sayının azalmakta olduğu biliniyorsa, yürütücü verileri minimum bölüm sayısı üzerinde güvenli bir şekilde tutabilir, yalnızca verileri ekstra düğümlerden, tuttuğumuz düğümlere taşıyabilir.

Yani, şöyle bir şey olurdu:

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

Sonra coalesce2 bölüme kadar:

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

Düğüm 1 ve Düğüm 3'ün orijinal verilerinin taşınmasını gerektirmediğine dikkat edin.


115
Yanıt için teşekkürler. Bunun minimize data movementyerine belgelerin daha iyi söylenmesi gerekirdi avoiding data movement.
Praveen Sripati

12
Ne zaman repartitionkullanılmalı coalesce?
Niemand

21
: @Niemand Geçerli dokümantasyon kapakları oldukça iyi bu düşünüyorum github.com/apache/spark/blob/... tüm unutmayın repartitionçağrıdır yapar coalesceile shuffletrue parametre seti. Bunun yardımcı olup olmadığını bana bildirin.
Justin Pihony

2
Var olan bölüm dosyası sayısını azaltmak mümkün müdür? HDF'im yok, ancak birçok dosyada sorun var.

2
yeniden daralma istatistiksel olarak daha yavaş olacaktır, çünkü küçüldüğünü bilmemektedir ... belki de bunu optimize edebilirler. Dahili olarak sadece bir shuffle = truebayrakla birleşmeyi çağırıyor
Justin Pihony

172

Justin'in cevabı harika ve bu cevap daha derinlere iniyor.

repartitionAlgoritma tam karıştır yapar ve eşit dağıtılan verilerle yeni bölümler yaratır. 1'den 12'ye kadar rakamlarla bir DataFrame oluşturalım.

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

numbersDf makinemde 4 bölüm var.

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

Veriler bölümlere nasıl ayrılır:

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

repartitionYöntemle tam bir karışıklık yapalım ve bu verileri iki düğümde alalım .

val numbersDfR = numbersDf.repartition(2)

numbersDfRVeriler makinemde nasıl bölümlenir:

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

repartitionBu yöntem yeni bölümleri yapar ve düzgün bir şekilde (veri dağılımı daha da büyük veri setleri için) yeni bölümleri veri dağıtır.

Fark arasında coalesceverepartition

coalescekarıştırılan veri miktarını en aza indirmek için mevcut bölümleri kullanır. repartitionyeni bölümler oluşturur ve tam bir karıştırma yapar. coalescefarklı miktarlarda veri içeren bölümlerle sonuçlanır (bazen çok farklı boyutlara sahip bölümler) ve repartitionkabaca eşit boyutlu bölümlerle sonuçlanır.

Daha hızlı mı coalesceyoksa repartitiondaha hızlı mı?

coalescedaha hızlı çalışabilir repartition, ancak eşit olmayan boyutlu bölümlerin çalışması genellikle eşit boyutlu bölümlere göre daha yavaştır. Büyük bir veri kümesini filtreledikten sonra genellikle veri kümelerini yeniden bölümlendirmeniz gerekir. repartitionGenel olarak daha hızlı buldum çünkü Spark eşit boyutlu bölümlerle çalışacak şekilde üretildi.

Not: Yeniden bölümlemenin diskteki veri boyutunu artırabileceğini merakla gözlemledim . Büyük veri kümelerinde yeniden bölüm / birleşim kullanırken testler yaptığınızdan emin olun.

Daha fazla ayrıntı istiyorsanız bu blog gönderisini okuyun .

Uygulamada birleştirme ve yeniden bölümlemeyi kullanacağınız zaman


8
@Powers için harika bir yanıt, ancak A ve B Bölümündeki veriler çarpık değil mi? Eşit olarak nasıl dağıtılır?
anwartheravian

Ayrıca, OOM hatası almadan bölüm boyutunu almanın en iyi yolu nedir? Kullandığım rdd.glom().map(len).collect()ama OOM hataları çok verir.
anwartheravian

8
@anwartheravian - A Bölümü ve B Bölümü farklı boyutlardır çünkü repartitionalgoritma verileri çok küçük veri kümeleri için eşit olarak dağıtmaz. Eskiden repartition13 bölüme 5 milyon kayıt düzenlerdim ve her dosya 89.3 MB ile 89.6 MB arasındaydı - bu oldukça eşit!
Güçler

1
@Bu ayrıntı ile daha iyi bir cevap verir.
Yeşil

1
Bu farkı çok daha iyi açıklıyor. Teşekkürler!
Abhi

22

Burada belirtilmesi gereken ek bir nokta, Spark RDD'nin temel prensibi değişmezliktir. Yeniden bölümleme veya birleşme yeni RDD oluşturacaktır. Temel RDD, orijinal bölüm sayısı ile var olmaya devam edecektir. Kullanım durumunun önbellekte RDD'yi devam ettirmeyi talep etmesi durumunda, yeni oluşturulan RDD için de aynı şey yapılmalıdır.

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

güzel bir! Bu açık değildir, eleştirel ve en azından bu deneyimli scala dev etmektir - yani ne bölümlerini yeniden ne de kaynaşabilecek o düğümler dağıldığını ne kadar veri değiştirme girişimi
Doug

1
@Harikrishnan yani diğer cevapları doğru anladıysam, birleşme durumunda onlara göre Spark mevcut bölümleri kullanır ancak RDD değişmez olduğu için Coalesce'ın mevcut bölümleri nasıl kullandığını açıklayabilir misiniz? Anladığım kadarıyla Spark'ın mevcut bölümlere yeni bölümler eklediğini düşündüm.
Explorer

Ancak "eski" RDD artık yürütme grafiği tarafından bilindiği gibi kullanılmazsa, kalıcı değilse bellekten silinir, değil mi?
Markus

15

repartition - bölümlerin sayısını arttırırken kullanmanız önerilir, çünkü tüm verilerin karıştırılmasını içerir.

coalesce- bölüm sayısını azaltırken kullanılması tavsiye edilir. Örneğin, 3 bölümünüz varsa ve bunu 2'ye düşürmek istiyorsanız coalesce, 3. bölüm verilerini bölüm 1 ve 2'ye taşır. Bölüm 1 ve 2 aynı kapta kalacaktır. Öte yandan, repartitiontüm bölümlerde veri karıştıracaktır, bu nedenle yürütücüler arasındaki ağ kullanımı yüksek olacak ve performansı etkileyecektir.

coalescerepartitionbölüm sayısını azaltırken daha iyi performans gösterir .


Yararlı Açıklama.
Narendra Maru

11

Ne izler kod ve kod docs yani coalesce(n)aynıdır coalesce(n, shuffle = false)ve repartition(n)aynıcoalesce(n, shuffle = true)

Böylece, hem coalesceve hem de repartitionbölüm sayısını artırmak için kullanılabilir

İle shuffle = true, aslında daha fazla sayıda bölümle birleşebilirsiniz. Bu, 100 gibi az sayıda bölümünüz varsa, birkaç bölümün anormal derecede büyük olması durumunda kullanışlıdır.

Vurgulamak için bir diğer önemli not , bölüm sayısını önemli ölçüde azaltırsanız, karıştırılmış sürümünü kullanmayı düşünmeniz gerektiğidir coalesce( repartitionbu durumda olduğu gibi). Bu, hesaplamalarınızın üst bölümlerde paralel olarak gerçekleştirilmesine izin verecektir (çoklu görev).

Bununla birlikte, örneğin büyük bir birleşim yapıyorsanız numPartitions = 1, bu, hesaplamanızın istediğinizden daha az sayıda düğümde gerçekleşmesine neden olabilir (örneğin, bir düğüm durumunda numPartitions = 1). Bundan kaçınmak için geçebilirsiniz shuffle = true. Bu, bir karıştırma adımı ekleyecektir, ancak geçerli yukarı akış bölümlerinin paralel olarak yürütüleceği anlamına gelir (geçerli bölümleme ne olursa olsun).

Aynı zamanda ilgili cevaba bakınız burada


10

Tüm cevaplar bu sık sorulan soruya büyük bilgiler ekliyor.

Bu sorunun zaman çizelgesi geleneğine göre, işte benim 2 sentim.

Çok özel bir durumda yeniden bölümlemenin birleşmeden daha hızlı olduğunu gördüm .

Uygulamamda, tahmin ettiğimiz dosya sayısı belirli eşikten daha düşük olduğunda, yeniden bölümleme daha hızlı çalışır.

İşte demek istediğim

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

Yukarıdaki snippet'te, dosyalarım 20'den küçükse, yeniden bölümleme çok daha hızlıyken birleşme sonsuza dek sürüyordu ve böylece yukarıdaki kod.

Tabii ki, bu sayı (20) işçi sayısına ve veri miktarına bağlı olacaktır.

Umarım yardımcı olur.


6

Yeniden bölümleme: Verileri YENİ bölüm sayısına karıştırın.

Örneğin. İlk veri çerçevesi 200 bölüme ayrılmıştır.

df.repartition(500): Veriler 200 bölümden yeni 500 bölüme karıştırılacaktır.

Coalesce : Verileri mevcut bölüm sayısına karıştırın.

df.coalesce(5): Veriler kalan 195 bölümden mevcut 5 bölüme karıştırılacaktır.


4

Justin ve Power'ın cevabına şunu eklemek isterim -

repartitionmevcut bölümleri yoksayar ve yenilerini oluşturur. Böylece veri eğimini düzeltmek için kullanabilirsiniz. Dağıtımı tanımlamak için bölüm anahtarlarından bahsedebilirsiniz. Veri çarpıklığı, 'büyük veri' problem alanındaki en büyük problemlerden biridir.

coalescemevcut bölümlerle çalışacak ve bir alt kümesini karıştıracaktır. Veri çarpıklığını olduğu kadar düzeltemez repartition. Bu nedenle daha ucuz olsa bile ihtiyacınız olan şey olmayabilir.


3

Eklemek istediğim tüm harika cevaplara repartitionveri paralelleştirmeden yararlanmak için en iyi seçenek bu. Bölümleri coalesceazaltmak için ucuz bir seçenek sunar ve büyük yazmalardan yararlanmak için HDFS veya başka bir lavaboya veri yazarken çok kullanışlıdır.

Tam avantaj elde etmek için parke formatında veri yazarken bunu yararlı buldum.


2

PySpark'tan (AWS EMR) tek bir csv dosyası oluşturma ve çıktı olarak s3'e kaydetme konusunda sorun yaşayan biri için, yeniden bölümlendirme kullanarak yardımcı oldu. Nedeni, birleşme tam bir karışıklık yapamaz, ancak yeniden bölümleme yapabilir. Esas olarak, yeniden bölümlemeyi kullanarak bölüm sayısını artırabilir veya azaltabilirsiniz, ancak birleştirme kullanarak yalnızca bölüm sayısını (1 değil) azaltabilirsiniz. AWS EMR'den s3'e bir csv yazmaya çalışan herkes için kod:

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

0

Basit bir şekilde COALESCE: - sadece bölümlerin sayısını azaltır, sadece veri sıkıştırır bölümleri sıkıştırır

REPARTITION: - bölüm sayısını artırmak ve azaltmak içindir, ancak karıştırma gerçekleşir

Misal:-

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

Her ikisi de iyi çalışıyor

Ama genel olarak bu iki şey için gidiyoruz, bir kümede çıktı görmemiz gerektiğinde, bununla gideriz.


9
Kömür ile veri hareketi de olacaktır.
sun_dare

0

Ancak, büyük verilerle uğraşıyorsanız, birleşme düğümlerine gelen verilerin yüksek düzeyde yapılandırılmış olduğundan emin olmalısınız. Tüm veriler bu düğümlere yükleneceğinden, bellek istisnasına neden olabilir. Tazminat pahalı olsa da kullanmayı tercih ederim. Verileri eşit olarak karıştırıp dağıttığından.

Birleşme ve yeniden bölümleme arasında seçim yapmak akıllıca olun.


0

repartitionAlgoritma verilerin tam karıştır yapar ve verilerin eşit büyüklükte bölümleri oluşturur. coalescetam bir karışıklığı önlemek için mevcut bölümleri birleştirir.

Coalesce, çok sayıda bölüm içeren bir RDD'yi almak ve daha az bölümlü bir nihai RDD oluşturmak için bölümleri tek bir çalışan düğümü üzerinde birleştirmek için iyi çalışır.

Repartitionistediğiniz son bölüm sayısını üretmek için RDD'nizdeki verileri yeniden karıştırır. DataFrames'in bölümlenmesi, çerçeve tarafından yönetilmesi gereken düşük düzeyli bir uygulama ayrıntısı gibi görünür, ancak değildir. Büyük DataFrame'leri daha küçük olanlara filtrelerken, neredeyse her zaman verileri yeniden bölümlendirmelisiniz. Muhtemelen büyük DataFrame'leri daha küçük olanlara sık sık filtreleyeceksiniz.

Daha fazla ayrıntı istiyorsanız bu blog gönderisini okuyun .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.