Apache Spark: Harita ve MapPartitions mı?


133

RDD'ler map ile mapPartitionsyöntem arasındaki fark nedir ? Ve böyle mi flatMapdavranıyor mu? Teşekkürler.mapmapPartitions

(değiştir) yani arasındaki fark nedir (anlamsal olarak veya uygulama açısından)

  def map[A, B](rdd: RDD[A], fn: (A => B))
               (implicit a: Manifest[A], b: Manifest[B]): RDD[B] = {
    rdd.mapPartitions({ iter: Iterator[A] => for (i <- iter) yield fn(i) },
      preservesPartitioning = true)
  }

Ve:

  def map[A, B](rdd: RDD[A], fn: (A => B))
               (implicit a: Manifest[A], b: Manifest[B]): RDD[B] = {
    rdd.map(fn)
  }

3
Aşağıdaki cevabı okuduktan sonra, onu gerçekten kullanan biri tarafından paylaşılan [bu deneyime] göz atabilirsiniz . ( Bzhangusc.wordpress.com/2014/06/19/… ) bzhangusc.wordpress.com/2014/06/19 /…
Abhidemon

Yanıtlar:


121

RDD'nin map ve mapPartitions yöntemi arasındaki fark nedir?

Yöntem haritası , kaynak RDD'nin her bir öğesini , bir işlev uygulayarak sonuç RDD'sinin tek bir öğesine dönüştürür. mapPartitions , kaynak RDD'nin her bölümünü sonucun birden çok öğesine dönüştürür (muhtemelen hiçbiri).

FlatMap, map gibi mi yoksa mapPartitions gibi mi davranır?

Ne, flatMap (şekilde tek bir eleman üzerinde çalışan map) ve sonuç (şekilde birden fazla elemanları üretir mapPartitions).


3
Teşekkürler - harita karışıklığa neden oluyor mu (veya bölüm sayısını değiştiriyor mu)? Verileri düğümler arasında taşır mı? Verileri düğümler arasında taşımaktan kaçınmak için mapPartitions'ı kullanıyorum, ancak flapMap'in bunu yapıp yapmayacağından emin değildim.
Nicholas White

- Eğer kaynaktan bakarsak github.com/apache/incubator-spark/blob/... ve github.com/apache/incubator-spark/blob/... - hem mapve flatMapebeveyn olarak aynı bölümleri var.
Alexey Romanov

13
Bir not olarak, 2013 San Francisco Spark Zirvesi'nde (goo.gl/JZXDCR) bir konuşmacı tarafından sağlanan bir sunum, kayıt başına yüksek ek yükü olan görevlerin mapPartition ile harita dönüşümünden daha iyi performans gösterdiğini vurgulamaktadır. Bu, sunuma göre, yeni bir görev oluşturmanın yüksek maliyetinden kaynaklanıyor.
Mikel Urkia

1
Bunun tam tersini görüyorum - çok küçük işlemlerde bile, mapPartitions'ı çağırmak ve haritayı aramaktan daha hızlı yinelemek. Bunun, harita görevini işleyecek dil motorunu çalıştırmanın ek yükü olduğunu varsayıyorum. (Ben R'deyim, daha fazla başlangıç ​​ek yükü olabilir.) Birden fazla işlem gerçekleştirecekseniz, mapPartitions biraz daha hızlı görünüyor - bunun RDD'yi yalnızca bir kez okuduğunu varsayıyorum. RDD, RAM'de önbelleğe alınmış olsa bile, bu, tür dönüşümünden çok fazla ek yük tasarrufu sağlar.
Bob

3
maptemelde işlevinizi alır fve ona aktarır iter.map(f). Yani temelde saran bir kolaylık yöntemi mapPartitions. Her iki durumda da saf harita tarzı dönüştürme işi için (yani işlevin aynı olduğu durumlarda) bir performans avantajı olsaydı şaşırırdım, işlemek için bazı nesneler oluşturmanız gerekirse, bu nesneler paylaşılabilirse mapPartitionsavantajlı olur.
Nightwolf

130

İth. İPUCU :

Her RDDöğe için bir kez yerine birçok öğe için bir kez yapılması gereken ağır başlatmanız olduğunda RDDve üçüncü taraf kitaplıktan nesnelerin oluşturulması gibi bu başlatma serileştirilemezse (böylece Spark bunu küme boyunca iletebilir. işçi düğümleri), mapPartitions()yerine kullanın map(). Örneğin,mapPartitions() her RDDveri öğesi için bir kez yerine çalışan görevi / iş parçacığı / bölüm başına bir kez başlatmanın yapılmasını sağlar : aşağıya bakın.

val newRd = myRdd.mapPartitions(partition => {
  val connection = new DbConnection /*creates a db connection per partition*/

  val newPartition = partition.map(record => {
    readMatchingFromDB(record, connection)
  }).toList // consumes the iterator, thus calls readMatchingFromDB 

  connection.close() // close dbconnection here
  newPartition.iterator // create a new iterator
})

S2. does flatMapuslu haritası gibi ya da benzeri mapPartitions?

Evet. lütfen 2. örneğe bakın flatmap, kendini açıklayıcı.

S1. Bir RDD en arasındaki fark nedir mapvemapPartitions

mapişlevi mapPartitionsbölüm düzeyinde uygularken , kullanılan işlevi öğe başına düzeyinde çalıştırır.

Örnek Senaryo : Belirli birRDDbölümde100K öğemiz varsa, kullandığımızda eşleme dönüşümü tarafından kullanılan işlevi 100K kez ateşleyeceğizmap.

Tersine, eğer kullanırsak, mapPartitionso zaman belirli bir işlevi yalnızca bir kez çağıracağız, ancak tüm 100K kayıtları aktaracağız ve tüm yanıtları bir işlev çağrısında geri alacağız.

mapBelirli bir işlev üzerinde pek çok kez çalıştığından, özellikle işlev her seferinde tüm öğeleri aynı anda geçsek (olması durumunda mappartitions) yapması gerekmeyecek pahalı bir şey yapıyorsa, performans kazanımı olacaktır .

harita

RDD'nin her öğesine bir dönüştürme işlevi uygular ve sonucu yeni bir RDD olarak döndürür.

Listeleme Varyantları

def eşleme [U: ClassTag] (f: T => U): RDD [U]

Misal :

val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)
 val b = a.map(_.length)
 val c = a.zip(b)
 c.collect
 res0: Array[(String, Int)] = Array((dog,3), (salmon,6), (salmon,6), (rat,3), (elephant,8)) 

mapPartitions

Bu, her bölüm için yalnızca bir kez çağrılan özel bir haritadır. İlgili bölümlerin tüm içeriği, giriş bağımsız değişkeni (Yineleyici [T]) aracılığıyla sıralı bir değer akışı olarak kullanılabilir. Özel işlev, başka bir Yineleyici [U] döndürmelidir. Birleşik sonuç yineleyiciler otomatik olarak yeni bir RDD'ye dönüştürülür. Lütfen, seçtiğimiz bölümleme nedeniyle tuple (3,4) ve (6,7) 'nin aşağıdaki sonuçta eksik olduğunu unutmayın.

preservesPartitioninggiriş işlevinin bölümleyiciyi koruyup korumadığını gösterir; falsebu, bu bir çift RDD değilse ve giriş işlevi tuşları değiştirmez.

Listeleme Varyantları

def mapPartitions [U: ClassTag] (f: Iterator [T] => Iterator [U], preservesPartitioning: Boolean = false): RDD [U]

örnek 1

val a = sc.parallelize(1 to 9, 3)
 def myfunc[T](iter: Iterator[T]) : Iterator[(T, T)] = {
   var res = List[(T, T)]()
   var pre = iter.next
   while (iter.hasNext)
   {
     val cur = iter.next;
     res .::= (pre, cur)
     pre = cur;
   }
   res.iterator
 }
 a.mapPartitions(myfunc).collect
 res0: Array[(Int, Int)] = Array((2,3), (1,2), (5,6), (4,5), (8,9), (7,8)) 

Örnek 2

val x = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9,10), 3)
 def myfunc(iter: Iterator[Int]) : Iterator[Int] = {
   var res = List[Int]()
   while (iter.hasNext) {
     val cur = iter.next;
     res = res ::: List.fill(scala.util.Random.nextInt(10))(cur)
   }
   res.iterator
 }
 x.mapPartitions(myfunc).collect
 // some of the number are not outputted at all. This is because the random number generated for it is zero.
 res8: Array[Int] = Array(1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 7, 7, 7, 9, 9, 10) 

Yukarıdaki program aşağıdaki gibi flatMap kullanılarak da yazılabilir.

Örnek 2 Flatmap kullanarak

val x  = sc.parallelize(1 to 10, 3)
 x.flatMap(List.fill(scala.util.Random.nextInt(10))(_)).collect

 res1: Array[Int] = Array(1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10) 

Sonuç:

mapPartitionsdönüşüm, mapişlevinizi bir kez / element değil, bir kez / bölüm çağırdığından daha hızlıdır ..

Daha fazla okuma: foreach Vs foreachPartitions Ne zaman Ne kullanılır?


4
Aynı sonuca ulaşmak için mapveya kullanabileceğinizi biliyorum mapPartitions(sorudaki iki örneğe bakın); bu soru neden bir yolu diğerine tercih ettiğinizle ilgilidir. Diğer cevaptaki yorumlar gerçekten kullanışlıdır! Ayrıca, söz etmedi mapve flatMappas falseiçin preservesPartitioningve etkileri nelerdir.
Nicholas White

2
her seferinde çalıştırılan fonksiyona karşı bir kez çalıştırılan işlev, eksik olduğum bağlantıydı. MapPartition ile aynı anda birden fazla veri kaydına erişim sağlamak paha biçilemez bir şeydir. cevabı takdir edin
Noktalı virgül ve Koli Bandı

1
mapDaha iyi olan bir senaryo var mı mapPartitions? Bu mapPartitionskadar iyiyse, neden varsayılan harita uygulaması değil?
ruhong

1
@oneleggedmule: her ikisi de farklı gereksinimler içindir, eğer db bağlantıları gibi masraflı kaynakları başlatıyorsanız (yukarıdaki örnekte gösterildiği gibi) akıllıca kullanmamız gerekir, o zaman mappartitions, bölüm başına bir bağlantı olduğundan doğru yaklaşımdır. ayrıca saveAsTextFile dahili olarak kullanılan haritalama bkz.
Ram Ghadiyaram

@oneleggedmule Benim bakış açıma göre map () daha kolay anlaşılır ve öğrenilir ve aynı zamanda birçok farklı dilin ortak bir yöntemidir. Başlangıçta birisi bu Spark'a özgü yönteme aşina değilse, mapPartitions () kullanmaktan daha kolay olabilir. Performans farkı yoksa map () kullanmayı tercih ederim.
Raymond Chen

15

Harita :

  1. MapReduce'un map () yöntemine çok benzer şekilde, her seferinde bir satırı işler.
  2. Her satırdan sonra dönüşümden dönersiniz.

MapPartitions

  1. Tüm bölümü tek seferde işler.
  2. Tüm bölümü işledikten sonra işlevden yalnızca bir kez dönebilirsiniz.
  3. Tüm bölümü işleyene kadar tüm ara sonuçların bellekte tutulması gerekir.
  4. MapReduce'un setup () map () ve cleanup () işlevini beğenmenizi sağlar

Map Vs mapPartitions http://bytepadding.com/big-data/spark/spark-map-vs-mappartitions/

Spark Map http://bytepadding.com/big-data/spark/spark-map/

Spark mapPartitions http://bytepadding.com/big-data/spark/spark-mappartitions/


2 ile ilgili olarak - yineleyiciden yineleyiciye dönüşümler gerçekleştiriyorsanız ve yineleyiciyi bir tür koleksiyonda gerçekleştirmiyorsanız, tüm bölümü bellekte tutmak zorunda kalmazsınız, aslında, bu şekilde spark yapabilecektir. bölümün parçalarını diske dökün.
ilcord

4
Tüm bölümü bellekte tutmak zorunda değilsiniz, ancak sonucu. Tüm bölümü
işleyene
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.