web-dev-qa-db-fra.com

Apache Spark: map vs mapPartitions?

Quelle est la différence entre une méthode RDDmap et mapPartitions? Et est-ce que flatMap se comporte comme map ou comme mapPartitions? Merci.

(modifier) ​​c’est-à-dire quelle est la différence (soit sémantiquement, soit en termes d’exécution) entre

  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)
  }

Et:

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

Quelle est la différence entre la carte et la méthode mapPartitions d'un RDD?

La méthode map convertit chaque élément du RDD source en un seul élément du résultat RDD en appliquant une fonction. mapPartitions convertit chaque partition du RDD source en plusieurs éléments du résultat (éventuellement aucun).

Et flatMap se comporte-t-il comme une carte ou comme mapPartitions?

Ni l'un ni l'autre flatMap ne fonctionne sur un seul élément (sous la forme map) et génère plusieurs éléments du résultat (sous la forme mapPartitions).

108
Alexey Romanov

Lutin. POINTE :

Chaque fois que vous avez une initialisation lourde à effectuer une fois pour plusieurs éléments RDD plutôt qu'une fois par élément RDD, et si cette initialisation, telle que la création d'objets à partir d'une bibliothèque tierce, ne peut pas être sérialisée (de sorte que Spark peut le transmettre à travers le cluster aux nœuds de travail), utilisez mapPartitions() au lieu de map(). mapPartitions() prévoit que l'initialisation doit être effectuée une fois par tâche de travail/unité d'exécution/partition au lieu d'une fois par élément de données RDD pour exemple: voir ci-dessous.

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
})

Q2. flatMap se comporte-t-il comme map ou comme mapPartitions?

Oui. veuillez vous reporter à l'exemple 2 de flatmap .. son explicite.

Q1. Quelle est la différence entre les noms map et mapPartitions

map utilise la fonction utilisée au niveau de chaque élément alors que mapPartitions l'exerce au niveau de la partition.

Exemple de scénario : Si nous avons 100 000 éléments dans une partition RDD particulière, nous lancerons la fonction. utilisé par la transformation de mappage 100 000 fois lorsque nous utilisons map.

Inversement, si nous utilisons mapPartitions, nous n'appellerons cette fonction qu'une seule fois, mais nous transmettrons tous les enregistrements de 100 000 et nous récupérons toutes les réponses en un seul appel.

Il y aura un gain de performance car map fonctionne tellement souvent sur une fonction particulière, surtout si la fonction effectue quelque chose de coûteux à chaque fois qu'elle n'aurait pas besoin de le faire si nous transmettions tous les éléments à la fois ( dans le cas de mappartitions).

carte

Applique une fonction de transformation à chaque élément du RDD et renvoie le résultat sous la forme d'un nouveau RDD.

Liste des variantes

def map [U: ClassTag] (f: T => U): RDD [U]

Exemple :

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

Il s'agit d'une carte spécialisée appelée une seule fois pour chaque partition. L'ensemble du contenu des partitions respectives est disponible sous forme de flux séquentiel de valeurs via l'argument d'entrée (Iterarator [T]). La fonction personnalisée doit renvoyer un autre Iterator [U]. Les itérateurs de résultats combinés sont automatiquement convertis en un nouveau RDD. Veuillez noter que les tuples (3,4) et (6,7) sont absents du résultat suivant en raison du partitionnement choisi.

preservesPartitioning indique si la fonction d'entrée conserve le partitionneur, qui devrait être false à moins qu'il ne s'agisse d'une paire RDD et que la fonction d'entrée ne modifie pas les clés.

Variantes de référencement

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

Exemple 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)) 

Exemple 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) 

Le programme ci-dessus peut également être écrit en utilisant flatMap comme suit.

Exemple 2 en utilisant flatmap

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) 

Conclusion :

La transformation mapPartitions est plus rapide que map puisqu'elle appelle votre fonction une fois/partition, pas une fois/élément ..

Lectures supplémentaires: foreach Vs foreachPartitions Quand utiliser quoi?

99
Ram Ghadiyaram

Carte :

  1. Il traite une ligne à la fois, très similaire à la méthode map () de MapReduce.
  2. Vous revenez de la transformation après chaque ligne.

MapPartitions

  1. Il traite la partition complète en une fois.
  2. Vous ne pouvez quitter la fonction qu'une seule fois après avoir traité toute la partition.
  3. Tous les résultats intermédiaires doivent être conservés en mémoire jusqu'à ce que vous traitiez la partition entière.
  4. Vous fournit les fonctions setup () map () et cleanup () de MapReduce

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

Spark Maphttp://bytepadding.com/big-data/spark/spark-map/

Spark mapPartitionshttp://bytepadding.com/big-data/spark/spark-mappartitions/

15
KrazyGautam