Imp. MANCIA :
Ogni volta che si dispone di un'inizializzazione pesante che dovrebbe essere eseguita una volta per molti RDDelementi anziché una volta per RDDelemento e se questa inizializzazione, come la creazione di oggetti da una libreria di terze parti, non può essere serializzata (in modo che Spark possa trasmetterla attraverso il cluster a i nodi di lavoro), utilizzare mapPartitions()invece di
map(). mapPartitions()prevede che l'inizializzazione venga eseguita una volta per attività / thread / partizione di lavoro anziché una volta RDDper esempio per elemento dati : vedere di seguito.
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. si flatMapcomporta come una mappa o come mapPartitions?
Sì. vedere l'esempio 2 di flatmap... si spiega da sé.
Q1. Qual è la differenza tra un RDD mapemapPartitions
mapfunziona la funzione utilizzata a livello di elemento mentre
mapPartitionsesercita la funzione a livello di partizione.
Scenario di esempio : se abbiamo 100K elementi in unaRDDpartizioneparticolare, disattiveremo la funzione utilizzata dalla trasformazione della mappatura 100K volte quando usiamomap.
Al contrario, se lo utilizziamo mapPartitions, chiameremo la funzione specifica una sola volta, ma passeremo in tutti i record da 100K e otterremo tutte le risposte in una chiamata di funzione.
Ci sarà un miglioramento delle prestazioni poiché mapfunziona su una particolare funzione così tante volte, specialmente se la funzione sta facendo qualcosa di costoso ogni volta che non avrebbe bisogno di fare se passassimo tutti gli elementi contemporaneamente (in caso di mappartitions).
carta geografica
Applica una funzione di trasformazione su ciascun elemento del RDD e restituisce il risultato come nuovo RDD.
Elenco delle varianti
def map [U: ClassTag] (f: T => U): RDD [U]
Esempio :
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
Questa è una mappa specializzata che viene chiamata una sola volta per ogni partizione. L'intero contenuto delle rispettive partizioni è disponibile come flusso sequenziale di valori tramite l'argomento input (Iterarator [T]). La funzione personalizzata deve restituire ancora un altro Iteratore [U]. Gli iteratori di risultati combinati vengono automaticamente convertiti in un nuovo RDD. Si noti che le tuple (3,4) e (6,7) mancano dal seguente risultato a causa del partizionamento che abbiamo scelto.
preservesPartitioningindica se la funzione di input preserva il partizionatore, il che dovrebbe essere a falsemeno che questa non sia una coppia RDD e la funzione di input non modifichi le chiavi.
Elenco delle varianti
def mapPartitions [U: ClassTag] (f: Iterator [T] => Iterator [U], preservesPartitioning: Boolean = false): RDD [U]
Esempio 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))
Esempio 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)
Il programma sopra può anche essere scritto usando flatMap come segue.
Esempio 2 usando 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)
Conclusione :
mapPartitionsla trasformazione è più veloce di mapquando chiama la tua funzione una volta / partizione, non una volta / elemento ..
Ulteriori letture: foreach Vs foreachPartitions Quando usare cosa?