Qualcuno può spiegarmi la differenza tra map e flatMap e qual è un buon caso d'uso per ciascuno?
Che cosa significa "appiattire i risultati"? Per cosa è buono?
Qualcuno può spiegarmi la differenza tra map e flatMap e qual è un buon caso d'uso per ciascuno?
Che cosa significa "appiattire i risultati"? Per cosa è buono?
Risposte:
Ecco un esempio della differenza, come spark-shell
sessione:
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 map
trasforma un RDD di lunghezza N in un altro RDD di lunghezza N.
Ad esempio, mappa da due linee in due lunghezze di linea:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
Ma flatMap
(parlando in senso lato) trasforma un RDD di lunghezza N in una raccolta di N raccolte, quindi li appiattisce in un singolo 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 di output
Giusto per illustrarlo, 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"]
I RDD di input e output saranno pertanto in genere di dimensioni diverse per flatMap
.
Se avessimo provato a utilizzare la map
nostra split
funzione, saremmo finiti con strutture nidificate (un RDD di matrici di parole, con tipo RDD[Array[String]]
) perché dovremmo 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 utile caso speciale è il mapping con una funzione che potrebbe non restituire una risposta, e quindi restituisce un Option
. Possiamo usare flatMap
per filtrare gli elementi che restituiscono None
ed estrarre i valori da quelli che restituiscono a 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 un elenco che ha un elemento o zero elementi)
["a b c", "", "d"] => [["a","b","c"],[],["d"]]
?
split
su un elenco di stringhe produrrà un elenco di array)
Generalmente usiamo l'esempio del conteggio delle parole in hadoop. Prenderò lo stesso caso d'uso map
e userò e flatMap
vedremo la differenza 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 sarà analizzato usando map
e flatMap
.
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 dell'output è 4, ovvero N elementi ==> N elementi.
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 utilizzando 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)]
Considerando che flatMap
su RDD wc
darà il risultato indesiderato di seguito:
>>> 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 è possibile ottenere il conteggio delle parole se map
viene utilizzato al posto di flatMap
.
Secondo la definizione, la differenza tra map
e flatMap
è:
map
: Restituisce un nuovo RDD applicando una determinata funzione a ciascun elemento del RDD. La funzione inmap
restituisce solo un elemento.
flatMap
: Simile amap
, restituisce un nuovo RDD applicando una funzione a ciascun elemento del RDD, ma l'output è appiattito.
.map(lambda line:line.split(" "))
non è una matrice di stringhe. Dovresti passare data.collect()
a wc.collect
e vedrai una serie di array.
wc.collect()
?
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)
ad esempio, se myRDD è composto da Doppio.
Mentre flatMap può trasformare l'RDD in un altro di dimensioni diverse: ad es .:
myRDD.flatMap(x =>new Seq(2*x,3*x))
che restituirà un RDD di dimensioni 2 * N o
myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
Si riduce alla tua domanda iniziale: cosa intendi per appiattimento ?
Quando si utilizza flatMap, una raccolta "multidimensionale" diventa una raccolta "monodimensionale" .
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 una mappa piatta quando,
Usa 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 map
metodo, otterrai le righe di test.md
, per il flatMap
metodo, otterrai il numero di parole.
Il map
metodo è simile a flatMap
, tutti restituiscono un nuovo RDD. map
il metodo spesso da usare restituisce un nuovo RDD, il flatMap
metodo spesso usa parole divise.
map
restituisce RDD di uguale numero di elementi mentre flatMap
potrebbe non farlo.
Un esempio di caso d'uso perflatMap
filtrare i dati mancanti o errati.
Un esempio di utilizzo per l'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'input RDD e applicano una funzione su di esso. Il modo in cui differiscono è che la funzione in map 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 dell'elenco in modo semplice (non un elenco).
tutti gli esempi sono buoni ... Ecco una bella illustrazione visiva ... fonte di cortesia: formazione DataFlair di spark
Mappa: una mappa è un'operazione di trasformazione in Apache Spark. Si applica a ciascun elemento di RDD e restituisce il risultato come nuovo RDD. Nella mappa, lo sviluppatore dell'operazione può definire la propria logica aziendale personalizzata. La stessa logica verrà applicata a tutti gli elementi di RDD.
La map
funzione Spark RDD accetta un elemento mentre l'input lo elabora in base al codice personalizzato (specificato dallo sviluppatore) e restituisce un elemento alla volta. La mappa trasforma un RDD di lunghezza N in un altro RDD di lunghezza N. Gli RDD di input e output avranno in genere lo stesso numero di record.
Esempio di map
utilizzo di scala:
val x = spark.sparkContext.parallelize(List("spark", "map", "example", "sample", "example"), 3)
val y = x.map(x => (x, 1))
y.collect
// res0: Array[(String, Int)] =
// Array((spark,1), (map,1), (example,1), (sample,1), (example,1))
// rdd y can be re writen with shorter syntax in scala as
val y = x.map((_, 1))
y.collect
// res1: Array[(String, Int)] =
// Array((spark,1), (map,1), (example,1), (sample,1), (example,1))
// Another example of making tuple with string and it's length
val y = x.map(x => (x, x.length))
y.collect
// res3: Array[(String, Int)] =
// Array((spark,5), (map,3), (example,7), (sample,6), (example,7))
FlatMap:
A flatMap
è un'operazione di trasformazione. Si applica a ciascun elemento di RDD e restituisce il risultato come nuovo RDD
. È simile a Mappa, ma FlatMap consente di restituire 0, 1 o più elementi dalla funzione mappa. Nell'operazione FlatMap, uno sviluppatore può definire la propria logica aziendale personalizzata. La stessa logica verrà applicata a tutti gli elementi del RDD.
Che cosa significa "appiattire i risultati"?
Una funzione FlatMap accetta un elemento mentre l'input lo elabora secondo il codice personalizzato (specificato dallo sviluppatore) e restituisce 0 o più elementi alla volta. flatMap
() trasforma un RDD di lunghezza N in un altro RDD di lunghezza M.
Esempio di flatMap
utilizzo di scala:
val x = spark.sparkContext.parallelize(List("spark flatmap example", "sample example"), 2)
// map operation will return Array of Arrays in following case : check type of res0
val y = x.map(x => x.split(" ")) // split(" ") returns an array of words
y.collect
// res0: Array[Array[String]] =
// Array(Array(spark, flatmap, example), Array(sample, example))
// flatMap operation will return Array of words in following case : Check type of res1
val y = x.flatMap(x => x.split(" "))
y.collect
//res1: Array[String] =
// Array(spark, flatmap, example, sample, example)
// RDD y can be re written with shorter syntax in scala as
val y = x.flatMap(_.split(" "))
y.collect
//res2: Array[String] =
// Array(spark, flatmap, example, sample, example)
La differenza può essere vista dal seguente codice pyspark di esempio:
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]]
Flatmap e Map trasformano entrambi la raccolta.
Differenza:
map (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 mappato su 0 o più elementi di output (quindi func dovrebbe restituire un Seq anziché un singolo elemento).
La funzione di trasformazione:
mappa : un elemento in -> un elemento in uscita.
flatMap : un elemento in -> 0 o più elementi in uscita (una raccolta).
RDD.map
restituisce tutti gli elementi in un singolo array
RDD.flatMap
restituisce elementi in array di array
supponiamo di avere testo nel file text.txt come
Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD
Utilizzando la mappa
val text=sc.textFile("text.txt").map(_.split(" ")).collect
produzione:
text: **Array[Array[String]]** = Array(Array(Spark, is, an, expressive, framework), Array(This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD))
Utilizzando flatMap
val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect
produzione:
text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)
Per tutti coloro che hanno voluto PySpark in relazione:
Trasformazione di esempio: 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'oggetto 'list' non ha attributi 'split'
>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
... return x.split()
>>> rword=rline.map(fwords)
>>> rword.collect()
[['hello', 'what', 'are', 'you', 'doing'], ['this', 'is', 'rak']]
>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()
['hello', 'what', 'are', 'you', 'doing', 'this', 'is', 'rak']
Spero che sia d'aiuto :)
map
: Restituisce un nuovo RDD
applicando una funzione a ciascun elemento di RDD
. La funzione in .map può restituire solo un elemento.
flatMap
: Simile a mappare, restituisce una nuova RDD
da applicando una funzione ad ogni elemento della RDD, ma l'uscita è appiattita.
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()
Uscita: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]
sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()
Output: l'avviso o / p è appiattito in un unico elenco [1, 2, 1, 2, 3, 1, 2, 3, 4]
Fonte: https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/
carta geografica :
è un metodo di ordine superiore che accetta una funzione come input e la applica a ciascun elemento nel RDD di origine.
flatMap:
un metodo di ordine superiore e un'operazione di trasformazione che accetta una funzione di input.
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
whiles
RDD.map
eRDD.flatMap
in Apache Spark . In generale, le operazioni RDD di Spark sono modellate sulla base delle corrispondenti operazioni di raccolta Scala. Le risposte in stackoverflow.com/q/1059776/590203 , che discutono della distinzione tramap
eflatMap
in Scala, possono esserti utili.