Qual è la differenza tra mappa e flatMap e un buon caso d’uso per ciascuno?

Qualcuno può spiegarmi la differenza tra mappa e flatMap e qual è un buon caso d’uso per ognuno?

Cosa significa “appiattire i risultati”? Per cosa è buono?

Ecco un esempio della differenza, come sessione spark-shell :

Innanzitutto, alcuni dati: due righe di testo:

 val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue")) // lines rdd.collect res0: Array[String] = Array("Roses are red", "Violets are blue") 

Ora, la map trasforma un RDD di lunghezza N in un altro RDD di lunghezza N.

Ad esempio, esegue il mapping da due righe in due lunghezze:

 rdd.map(_.length).collect res1: Array[Int] = Array(13, 16) 

Ma flatMap (genericamente parlando) trasforma un RDD di lunghezza N in una raccolta di collezioni N, quindi li appiattisce in un unico RDD di risultati.

 rdd.flatMap(_.split(" ")).collect res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue") 

Abbiamo più parole per riga e più righe, ma finiamo con un singolo array di parole in uscita

Solo per illustrare ciò, flatMapping da una raccolta di linee a una raccolta di parole assomiglia a:

 ["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"] 

Gli RDD di ingresso e di uscita saranno quindi di dimensioni diverse per flatMap .

Se avessimo provato ad usare map con la nostra funzione split , avremmo finito con strutture nidificate (un RDD di matrici di parole, con tipo RDD[Array[String]] ) perché dobbiamo avere esattamente un risultato per input:

 rdd.map(_.split(" ")).collect res3: Array[Array[String]] = Array( Array(Roses, are, red), Array(Violets, are, blue) ) 

Infine, un caso speciale utile è il mapping con una funzione che potrebbe non restituire una risposta, e quindi restituisce Option . Possiamo usare flatMap per filtrare gli elementi che restituiscono None e estrarre i valori da quelli che restituiscono Some :

 val rdd = sc.parallelize(Seq(1,2,3,4)) def myfn(x: Int): Option[Int] = if (x < = 2) Some(x * 10) else None rdd.flatMap(myfn).collect res3: Array[Int] = Array(10,20) 

(notando qui che un'opzione si comporta piuttosto come una lista che ha un elemento o zero elementi)

Generalmente utilizziamo un esempio di conteggio delle parole in hadoop. flatMap lo stesso caso d’uso e userò map e flatMap e vedremo la differenza su come sta elaborando i dati.

Di seguito è riportato il file di dati di esempio.

 hadoop is fast hive is sql on hdfs spark is superfast spark is awesome 

Il file sopra verrà analizzato usando map e flatMap .

Utilizzando la map

 >>> wc = data.map(lambda line:line.split(" ")); >>> wc.collect() [u'hadoop is fast', u'hive is sql on hdfs', u'spark is superfast', u'spark is awesome'] 

L’input ha 4 righe e anche la dimensione di output è 4, cioè N elementi ==> N elementi.

Utilizzando flatMap

 >>> fm = data.flatMap(lambda line:line.split(" ")); >>> fm.collect() [u'hadoop', u'is', u'fast', u'hive', u'is', u'sql', u'on', u'hdfs', u'spark', u'is', u'superfast', u'spark', u'is', u'awesome'] 

L’output è diverso dalla mappa.


Assegniamo 1 come valore per ogni chiave per ottenere il conteggio delle parole.

  • fm : RDD creato utilizzando flatMap
  • wc : RDD creato usando la map
 >>> fm.map(lambda word : (word,1)).collect() [(u'hadoop', 1), (u'is', 1), (u'fast', 1), (u'hive', 1), (u'is', 1), (u'sql', 1), (u'on', 1), (u'hdfs', 1), (u'spark', 1), (u'is', 1), (u'superfast', 1), (u'spark', 1), (u'is', 1), (u'awesome', 1)] 

Mentre la map su RDD wc fornirà il seguente output indesiderato:

 >>> wc.flatMap(lambda word : (word,1)).collect() [[u'hadoop', u'is', u'fast'], 1, [u'hive', u'is', u'sql', u'on', u'hdfs'], 1, [u'spark', u'is', u'superfast'], 1, [u'spark', u'is', u'awesome'], 1] 

Non è ansible ottenere il conteggio delle parole se viene utilizzata la map anziché flatMap .

Come da definizione, la differenza tra map e flatMap è:

map : restituisce un nuovo RDD applicando la funzione data a ciascun elemento del RDD. La funzione nella map restituisce solo un elemento.

flatMap : simile alla map , restituisce un nuovo RDD applicando una funzione a ciascun elemento dell’RDD, ma l’output è appiattito.

Se stai chiedendo la differenza tra RDD.map e RDD.flatMap in Spark, map trasforma un RDD di dimensione N in un altro di dimensione N. per esempio.

 myRDD.map(x => x*2) 

per esempio, se myRDD è composto da Doubles.

Mentre flatMap può trasformare l’RDD in un altro di dimensioni diverse: es .:

 myRDD.flatMap(x =>new Seq(2*x,3*x)) 

che restituirà un RDD di dimensione 2 * N o

 myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) ) 

Utilizzare test.md come esempio:

 ➜ spark-1.6.1 cat test.md This is the first line; This is the second line; This is the last line. scala> val textFile = sc.textFile("test.md") scala> textFile.map(line => line.split(" ")).count() res2: Long = 3 scala> textFile.flatMap(line => line.split(" ")).count() res3: Long = 15 scala> textFile.map(line => line.split(" ")).collect() res0: Array[Array[String]] = Array(Array(This, is, the, first, line;), Array(This, is, the, second, line;), Array(This, is, the, last, line.)) scala> textFile.flatMap(line => line.split(" ")).collect() res1: Array[String] = Array(This, is, the, first, line;, This, is, the, second, line;, This, is, the, last, line.) 

Se usi il metodo map , otterrai le linee di test.md , per il metodo flatMap , otterrai il numero di parole.

Il metodo map è simile a flatMap , tutti restituiscono un nuovo RDD. map metodo map spesso da utilizzare restituisce un nuovo RDD, il metodo flatMap spesso per utilizzare le parole divise.

map restituisce RDD di numero uguale di elementi mentre flatMap non può.

Un esempio di caso d’uso per flatMap Filtra i dati mancanti o errati.

Un esempio di utilizzo per la map Uso in un’ampia varietà di casi in cui il numero di elementi di input e output è lo stesso.

number.csv

 1 2 3 - 4 - 5 

map.py aggiunge tutti i numeri in add.csv.

 from operator import * def f(row): try: return float(row) except Exception: return 0 rdd = sc.textFile('a.csv').map(f) print(rdd.count()) # 7 print(rdd.reduce(add)) # 15.0 

flatMap.py utilizza flatMap per filtrare i dati mancanti prima dell’aggiunta. Vengono aggiunti meno numeri rispetto alla versione precedente.

 from operator import * def f(row): try: return [float(row)] except Exception: return [] rdd = sc.textFile('a.csv').flatMap(f) print(rdd.count()) # 5 print(rdd.reduce(add)) # 15.0 

map e flatMap sono simili, nel senso che prendono una linea dall’RDD di input e applicano una funzione su di essa. Il modo in cui differiscono è che la funzione nella mappa restituisce solo un elemento, mentre la funzione in flatMap può restituire un elenco di elementi (0 o più) come iteratore.

Inoltre, l’output di flatMap è appiattito. Sebbene la funzione in flatMap restituisca un elenco di elementi, flatMap restituisce un RDD che ha tutti gli elementi della lista in modo piatto (non una lista).

Flatmap e Map trasformano entrambi la collezione.

Differenza:

Mappa (func)
Restituisce un nuovo set di dati distribuito formato passando ogni elemento della sorgente attraverso una funzione func.

flatMap (func)
Simile alla mappa, ma ogni elemento di input può essere associato a 0 o più elementi di output (quindi func dovrebbe restituire un Seq piuttosto che un singolo elemento).

La funzione di trasformazione:
map : un elemento in -> one element out.
flatMap : un elemento in -> 0 o più elementi fuori (una raccolta).

La differenza può essere vista dal seguente codice di esempio pyspark:

 rdd = sc.parallelize([2, 3, 4]) rdd.flatMap(lambda x: range(1, x)).collect() Output: [1, 1, 2, 1, 2, 3] rdd.map(lambda x: range(1, x)).collect() Output: [[1], [1, 2], [1, 2, 3]] 

Si riduce alla tua domanda iniziale: cosa intendi per appiattimento ?

Quando si utilizza flatMap, una raccolta “multidimensionale” diventa raccolta “monodesmensionale” .

 val array1d = Array ("1,2,3", "4,5,6", "7,8,9") //array1d is an array of strings val array2d = array1d.map(x => x.split(",")) //array2d will be : Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) ) val flatArray = array1d.flatMap(x => x.split(",")) //flatArray will be : Array (1,2,3,4,5,6,7,8,9) 

Vuoi usare un flatMap quando,

  • la funzione della mappa risulta nella creazione di strutture multistrato
  • ma tutto quello che vuoi è una semplice – piatta – struttura unidimensionale, rimuovendo TUTTI i raggruppamenti interni

Per tutti quelli che hanno voluto correlare PySpark:

Esempio di trasformazione: flatMap

 >>> a="hello what are you doing" >>> a.split() 

[‘Ciao, cosa stai facendo’]

 >>> b=["hello what are you doing","this is rak"] >>> b.split() 

Traceback (ultima chiamata più recente): File “”, riga 1, in AttributeError: l’object ‘list’ non ha attributo ‘split’

 >>> rline=sc.parallelize(b) >>> type(rline) 

 >>> def fwords(x): ... return x.split() >>> rword=rline.map(fwords) >>> rword.collect() 

[[‘h ”, ‘what’, ‘are’, ‘you’, ‘doing’], [‘this’, ‘is’, ‘rak’]]

 >>> rwordflat=rline.flatMap(fwords) >>> rwordflat.collect() 

[‘ciao’, ‘cosa’, ‘sono’, ‘tu’, ‘facendo’, ‘questo’, ‘è’, ‘rak’]

Spero che sia d’aiuto 🙂

Differenza nell’output di map e flatMap:

1. flatMap

 val a = sc.parallelize(1 to 10, 5) a.flatMap(1 to _).collect() 

Produzione:

  1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 

2. map :

 val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3) val b = a.map(_.length).collect() 

Produzione:

 3 6 6 3 8 
  • map (func) Restituisce un nuovo set di dati distribuito formato passando ogni elemento della sorgente attraverso una funzione func dichiarato.so map () è a termine singolo

whiles

  • flatMap (func) Simile alla mappa, ma ogni elemento di input può essere mappato su 0 o più elementi di output in modo che func debba restituire una sequenza piuttosto che un singolo elemento.

map: restituisce un nuovo RDD applicando una funzione a ciascun elemento dell’RDD. La funzione in .map **** può restituire solo un elemento. ****

flatMap: simile alla mappa, restituisce un nuovo RDD per **** applicando una funzione a ciascun elemento del RDD, ma l’output è appiattito. ****

Inoltre, la funzione in flatMap può restituire un elenco di elementi (0 o più)

Per esempio: sc.parallelize ([3,4,5]). Map (lambda x: range (1, x)). Collect () Output: [[1, 2], [1, 2, 3], [ 1, 2, 3, 4]]

sc.parallelize ([3,4,5]). flatMap (lambda x: range (1, x)). collect () Output: notice o / p viene appiattito in una singola lista [1, 2, 1, 2 3, 1, 2, 3, 4]

Fonte: https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/