Kann mir jemand den Unterschied zwischen Map und FlatMap erklären und was ist ein guter Anwendungsfall für jeden?
Was bedeutet "Ergebnisse reduzieren"? Wozu ist es gut?
Kann mir jemand den Unterschied zwischen Map und FlatMap erklären und was ist ein guter Anwendungsfall für jeden?
Was bedeutet "Ergebnisse reduzieren"? Wozu ist es gut?
Antworten:
Hier ist ein Beispiel für den Unterschied als spark-shell
Sitzung:
Zunächst einige Daten - zwei Textzeilen:
val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue")) // lines
rdd.collect
res0: Array[String] = Array("Roses are red", "Violets are blue")
Nun map
wandelt eine RDD der Länge N in einer anderen RDD der Länge N
Beispielsweise werden zwei Zeilen in zwei Zeilenlängen abgebildet:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
Aber flatMap
(lose gesagt) transformiert eine RDD der Länge N in eine Sammlung von N Sammlungen und glättet diese dann in eine einzelne RDD von Ergebnissen.
rdd.flatMap(_.split(" ")).collect
res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")
Wir haben mehrere Wörter pro Zeile und mehrere Zeilen, aber am Ende haben wir ein einziges Ausgabearray von Wörtern
Um dies zu veranschaulichen, sieht flatMapping von einer Sammlung von Zeilen zu einer Sammlung von Wörtern folgendermaßen aus:
["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]
Die Eingangs- und Ausgangs-RDDs haben daher typischerweise unterschiedliche Größen für flatMap
.
Wenn wir versucht hätten, map
mit unserer split
Funktion zu arbeiten, hätten wir verschachtelte Strukturen erhalten (eine RDD von Arrays von Wörtern mit Typ RDD[Array[String]]
), weil wir genau ein Ergebnis pro Eingabe haben müssen:
rdd.map(_.split(" ")).collect
res3: Array[Array[String]] = Array(
Array(Roses, are, red),
Array(Violets, are, blue)
)
Ein nützlicher Sonderfall ist schließlich die Zuordnung zu einer Funktion, die möglicherweise keine Antwort zurückgibt und daher eine zurückgibt Option
. Wir können verwenden flatMap
, um die Elemente herauszufiltern, die zurückgeben, None
und die Werte aus denen zu extrahieren, die a zurückgeben 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)
(Beachten Sie hier, dass sich eine Option eher wie eine Liste verhält, die entweder ein Element oder null Elemente enthält.)
["a b c", "", "d"] => [["a","b","c"],[],["d"]]
?
split
über eine Liste von Strings eine Liste von Arrays erstellt)
Im Allgemeinen verwenden wir ein Beispiel für die Wortanzahl in hadoop. Ich werde den gleichen Anwendungsfall nehmen und verwenden map
und flatMap
und wir werden den Unterschied sehen, wie es die Daten verarbeitet.
Unten finden Sie die Beispieldatendatei.
hadoop is fast
hive is sql on hdfs
spark is superfast
spark is awesome
Die obige Datei wird mit map
und analysiert 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']
Die Eingabe hat 4 Zeilen und die Ausgabegröße beträgt ebenfalls 4, dh N Elemente ==> N Elemente.
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']
Die Ausgabe unterscheidet sich von der Karte.
Weisen wir jedem Schlüssel 1 als Wert zu, um die Wortanzahl zu erhalten.
fm
: RDD erstellt mit flatMap
wc
: RDD erstellt mit 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)]
Während flatMap
auf RDD wc
die folgende unerwünschte Ausgabe liefert:
>>> 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]
Sie können die Wortanzahl nicht erhalten, wenn map
anstelle von verwendet wird flatMap
.
Gemäß der Definition ist der Unterschied zwischen map
und flatMap
:
map
: Es wird eine neue RDD zurückgegeben, indem auf jedes Element der RDD eine bestimmte Funktion angewendet wird. Die Funktion inmap
gibt nur einen Artikel zurück.
flatMap
: Ähnlich wiemap
wird eine neue RDD zurückgegeben, indem auf jedes Element der RDD eine Funktion angewendet wird, die Ausgabe wird jedoch reduziert.
.map(lambda line:line.split(" "))
ist kein Array von Zeichenfolgen. Sie sollten ändern data.collect()
zu wc.collect
und Sie werden ein Array von Arrays sehen.
wc.collect()
?
Wenn Sie in Spark nach dem Unterschied zwischen RDD.map und RDD.flatMap fragen, transformiert map eine RDD der Größe N in eine andere der Größe N. z.B.
myRDD.map(x => x*2)
Zum Beispiel, wenn myRDD aus Doubles besteht.
Während flatMap das RDD in ein anderes mit einer anderen Größe umwandeln kann: z.
myRDD.flatMap(x =>new Seq(2*x,3*x))
Dies gibt eine RDD der Größe 2 * N oder zurück
myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
Es läuft auf Ihre erste Frage hinaus: Was meinen Sie mit Abflachen ?
Wenn Sie flatMap verwenden, wird eine "mehrdimensionale" Sammlung zu einer "eindimensionalen" Sammlung.
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)
Sie möchten eine flatMap verwenden, wenn,
Verwenden Sie test.md
als Beispiel:
➜ 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.)
Wenn Sie map
method verwenden, erhalten Sie die Zeilen test.md
, für flatMap
method erhalten Sie die Anzahl der Wörter.
Die map
Methode ist ähnlich flatMap
, sie geben alle eine neue RDD zurück. map
Methode häufig zur Verwendung einer neuen RDD zurückgeben, flatMap
Methode häufig zur Verwendung von geteilten Wörtern.
map
Gibt RDD mit der gleichen Anzahl von Elementen zurück, obwohl dies flatMap
möglicherweise nicht der Fall ist .
Ein Anwendungsbeispiel für dasflatMap
Herausfiltern fehlender oder falscher Daten.
Ein Anwendungsbeispiel für diemap
Verwendung in einer Vielzahl von Fällen, in denen die Anzahl der Eingabe- und Ausgabeelemente gleich ist.
number.csv
1
2
3
-
4
-
5
map.py fügt alle Zahlen in add.csv hinzu.
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 wird verwendet flatMap
, um fehlende Daten vor dem Hinzufügen herauszufiltern. Im Vergleich zur vorherigen Version werden weniger Zahlen hinzugefügt.
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 und flatMap sind insofern ähnlich, als sie eine Linie von der Eingabe-RDD nehmen und eine Funktion darauf anwenden. Sie unterscheiden sich darin, dass die Funktion in map nur ein Element zurückgibt, während die Funktion in flatMap eine Liste von Elementen (0 oder mehr) als Iterator zurückgeben kann.
Außerdem wird die Ausgabe der flatMap abgeflacht. Obwohl die Funktion in flatMap eine Liste von Elementen zurückgibt, gibt die flatMap eine RDD zurück, die alle Elemente aus der Liste auf flache Weise enthält (keine Liste).
Alle Beispiele sind gut ... Hier ist eine schöne visuelle Illustration ... Quelle mit freundlicher Genehmigung: DataFlair Training of Spark
Karte: Eine Karte ist eine Transformationsoperation in Apache Spark. Es gilt für jedes Element von RDD und gibt das Ergebnis als neues RDD zurück. In der Map kann der Operationsentwickler seine eigene benutzerdefinierte Geschäftslogik definieren. Die gleiche Logik wird auf alle Elemente von RDD angewendet.
Die Spark-RDD- map
Funktion verwendet ein Element als Eingabeprozess gemäß dem vom Entwickler angegebenen benutzerdefinierten Code und gibt jeweils ein Element zurück. Map transformiert eine RDD der Länge N in eine andere RDD der Länge N. Die Eingabe- und Ausgabe-RDDs haben normalerweise die gleiche Anzahl von Datensätzen.
Beispiel für die map
Verwendung von 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
ist eine Transformationsoperation. Es gilt für jedes Element von RDD und gibt das Ergebnis als neu zurück RDD
. Es ähnelt Map, aber FlatMap ermöglicht die Rückgabe von 0, 1 oder mehr Elementen aus der Map-Funktion. In der FlatMap-Operation kann ein Entwickler seine eigene benutzerdefinierte Geschäftslogik definieren. Die gleiche Logik wird auf alle Elemente der RDD angewendet.
Was bedeutet "Ergebnisse reduzieren"?
Eine FlatMap-Funktion verwendet ein Element als Eingabeprozess gemäß dem vom Entwickler angegebenen benutzerdefinierten Code und gibt jeweils 0 oder mehr Elemente zurück. flatMap
() transformiert eine RDD der Länge N in eine andere RDD der Länge M.
Beispiel für die flatMap
Verwendung von 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)
Der Unterschied ist aus dem folgenden Beispiel-Pyspark-Code ersichtlich:
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 und Map transformieren beide die Sammlung.
Unterschied:
map (func)
Gibt einen neuen verteilten Datensatz zurück, der durch Übergeben jedes Elements der Quelle durch eine Funktionsfunktion gebildet wird.
flatMap (func)
Ähnlich wie map, aber jedes Eingabeelement kann 0 oder mehr Ausgabeelementen zugeordnet werden (daher sollte func eine Seq anstelle eines einzelnen Elements zurückgeben).
Die Transformationsfunktion:
map : Ein Element rein -> ein Element raus.
flatMap : Ein Element in -> 0 oder mehr Elemente out (eine Sammlung).
RDD.map
Gibt alle Elemente in einem Array zurück
RDD.flatMap
Gibt Elemente in Arrays des Arrays zurück
Nehmen wir an, wir haben Text in der Datei text.txt als
Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD
Karte verwenden
val text=sc.textFile("text.txt").map(_.split(" ")).collect
Ausgabe:
text: **Array[Array[String]]** = Array(Array(Spark, is, an, expressive, framework), Array(This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD))
FlatMap verwenden
val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect
Ausgabe:
text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)
Für alle, die PySpark im Zusammenhang haben wollten:
Beispieltransformation: flatMap
>>> a="hello what are you doing"
>>> a.split()
['Hallo, was machst du']
>>> b=["hello what are you doing","this is rak"]
>>> b.split()
Traceback (letzter Aufruf zuletzt): Datei "", Zeile 1, in AttributeError: Das Objekt 'list' hat kein Attribut 'split'.
>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
... return x.split()
>>> rword=rline.map(fwords)
>>> rword.collect()
[['Hallo', 'Was', 'Sind', 'Du', 'Tun'], ['Dies', 'Ist', 'Rak']]
>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()
['Hallo', 'Was', 'Sind', 'Du', 'Tun', 'Dies', 'Ist', 'Rak']
Ich hoffe es hilft :)
map
: Es wird eine neue zurückgegeben, RDD
indem auf jedes Element der eine Funktion angewendet wird RDD
. Die Funktion in .map kann nur ein Element zurückgeben.
flatMap
: Ähnlich wie bei der Karte, gibt es eine neue RDD
durch eine Funktion zu jedem Element der RDD Anwendung, aber die Ausgangs abgeflacht ist.
Außerdem kann function in flatMap
eine Liste von Elementen zurückgeben (0 oder mehr).
Beispielsweise:
sc.parallelize([3,4,5]).map(lambda x: range(1,x)).collect()
Ausgabe: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]
sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()
Ausgabe: Hinweis o / p wird in einer einzelnen Liste abgeflacht [1, 2, 1, 2, 3, 1, 2, 3, 4]
Quelle: https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/
Karte :
ist eine Methode höherer Ordnung, die eine Funktion als Eingabe verwendet und auf jedes Element in der Quell-RDD anwendet.
flatMap:
eine Methode höherer Ordnung und eine Transformationsoperation, die eine Eingabefunktion übernimmt.
Unterschied in der Ausgabe von Map und FlatMap:
1.flatMap
val a = sc.parallelize(1 to 10, 5)
a.flatMap(1 to _).collect()
Ausgabe:
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()
Ausgabe:
3 6 6 3 8
während
RDD.map
undRDD.flatMap
in Apache Spark fragen . Im Allgemeinen werden die RDD-Operationen von Spark nach den entsprechenden Scala-Erfassungsoperationen modelliert. Die Antworten in stackoverflow.com/q/1059776/590203 , in denen die Unterscheidung zwischenmap
undflatMap
in Scala erläutert wird , können für Sie hilfreich sein.