Quelqu'un peut-il m'expliquer la différence entre map et flatMap et quel est un bon cas d'utilisation pour chacun?
Que signifie «aplatir les résultats»? À quoi ça sert?
Quelqu'un peut-il m'expliquer la différence entre map et flatMap et quel est un bon cas d'utilisation pour chacun?
Que signifie «aplatir les résultats»? À quoi ça sert?
Réponses:
Voici un exemple de différence, en spark-shell
session:
Tout d'abord, quelques données - deux lignes de texte:
val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue")) // lines
rdd.collect
res0: Array[String] = Array("Roses are red", "Violets are blue")
Maintenant, map
transforme un RDD de longueur N en un autre RDD de longueur N.
Par exemple, il mappe de deux lignes en deux longueurs de ligne:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
Mais flatMap
(en gros) transforme un RDD de longueur N en une collection de N collections, puis les aplatit en un seul RDD de résultats.
rdd.flatMap(_.split(" ")).collect
res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")
Nous avons plusieurs mots par ligne et plusieurs lignes, mais nous nous retrouvons avec un seul tableau de sortie de mots
Juste pour illustrer cela, flatMapping d'une collection de lignes à une collection de mots ressemble à:
["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]
Les RDD d'entrée et de sortie seront donc généralement de tailles différentes pour flatMap
.
Si nous avions essayé d'utiliser map
avec notre split
fonction, nous nous serions retrouvés avec des structures imbriquées (un RDD de tableaux de mots, avec type RDD[Array[String]]
) car nous devons avoir exactement un résultat par entrée:
rdd.map(_.split(" ")).collect
res3: Array[Array[String]] = Array(
Array(Roses, are, red),
Array(Violets, are, blue)
)
Enfin, un cas spécial utile est le mappage avec une fonction qui peut ne pas retourner de réponse, et renvoie donc un Option
. Nous pouvons utiliser flatMap
pour filtrer les éléments qui retournent None
et extraire les valeurs de ceux qui retournent 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)
(notant ici qu'une option se comporte plutôt comme une liste qui a soit un élément, soit zéro élément)
["a b c", "", "d"] => [["a","b","c"],[],["d"]]
?
split
sur une liste de chaînes produira une liste de tableaux)
Généralement, nous utilisons l'exemple de comptage de mots dans hadoop. Je prendrai le même cas d'utilisation map
et utiliserai et flatMap
nous verrons la différence dans la façon dont il traite les données.
Voici un exemple de fichier de données.
hadoop is fast
hive is sql on hdfs
spark is superfast
spark is awesome
Le fichier ci-dessus sera analysé à l'aide de map
et 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'entrée a 4 lignes et la taille de sortie est également 4, c'est-à-dire N éléments ==> N éléments.
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']
La sortie est différente de la carte.
Attribuons 1 comme valeur à chaque clé pour obtenir le nombre de mots.
fm
: RDD créé en utilisant flatMap
wc
: RDD créé en utilisant 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)]
Alors que flatMap
sur RDD wc
donnera la sortie indésirable ci-dessous:
>>> 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]
Vous ne pouvez pas obtenir le nombre de mots si map
est utilisé à la place de flatMap
.
Selon la définition, la différence entre map
et flatMap
est:
map
: Il renvoie un nouveau RDD en appliquant une fonction donnée à chaque élément du RDD. La fonctionmap
ne renvoie qu'un seul élément.
flatMap
: Similaire àmap
, il renvoie un nouveau RDD en appliquant une fonction à chaque élément du RDD, mais la sortie est aplatie.
.map(lambda line:line.split(" "))
n'est pas un tableau de chaînes. Vous devez passer data.collect()
à wc.collect
et vous verrez un tableau de tableaux.
wc.collect()
?
Si vous demandez la différence entre RDD.map et RDD.flatMap dans Spark, map transforme un RDD de taille N en un autre de taille N. par exemple.
myRDD.map(x => x*2)
par exemple, si myRDD est composé de doubles.
FlatMap peut transformer le RDD en un anthère de taille différente: par exemple:
myRDD.flatMap(x =>new Seq(2*x,3*x))
qui renverra un RDD de taille 2 * N ou
myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
Cela se résume à votre question initiale: que voulez-vous dire par aplatissement ?
Lorsque vous utilisez flatMap, une collection "multidimensionnelle" devient une collection "unidimensionnelle" .
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)
Vous souhaitez utiliser un flatMap lorsque,
Utilisez test.md
comme exemple:
➜ 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.)
Si vous utilisez la map
méthode, vous obtiendrez les lignes de test.md
, pour la flatMap
méthode, vous obtiendrez le nombre de mots.
La map
méthode est similaire à flatMap
, ils renvoient tous un nouveau RDD. map
souvent utiliser pour retourner un nouveau RDD, flatMap
souvent utiliser des mots séparés.
map
renvoie RDD d'un nombre égal d'éléments alors flatMap
qu'il ne le peut pas.
Un exemple d'utilisation pourflatMap
filtrer les données manquantes ou incorrectes.
Un exemple de cas d'map
utilisation pour une utilisation dans une grande variété de cas où le nombre d'éléments d'entrée et de sortie est le même.
number.csv
1
2
3
-
4
-
5
map.py ajoute tous les nombres dans 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 utilise flatMap
pour filtrer les données manquantes avant l'ajout. Moins de numéros sont ajoutés par rapport à la version précédente.
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 et flatMap sont similaires, dans le sens où ils prennent une ligne du RDD d'entrée et y appliquent une fonction. La façon dont ils diffèrent est que la fonction dans map ne renvoie qu'un seul élément, tandis que la fonction dans flatMap peut renvoyer une liste d'éléments (0 ou plus) en tant qu'itérateur.
De plus, la sortie du flatMap est aplatie. Bien que la fonction dans flatMap renvoie une liste d'éléments, le flatMap renvoie un RDD qui contient tous les éléments de la liste de manière plate (pas une liste).
tous les exemples sont bons .... Voici une belle illustration visuelle ... source courtoisie: Formation DataFlair de spark
Carte: une carte est une opération de transformation dans Apache Spark. Il s'applique à chaque élément de RDD et renvoie le résultat en tant que nouveau RDD. Dans la carte, le développeur d'opérations peut définir sa propre logique métier personnalisée. La même logique sera appliquée à tous les éléments de RDD.
La map
fonction Spark RDD prend un élément en entrée le traite selon le code personnalisé (spécifié par le développeur) et retourne un élément à la fois. La carte transforme un RDD de longueur N en un autre RDD de longueur N. Les RDD d'entrée et de sortie auront généralement le même nombre d'enregistrements.
Exemple d' map
utilisation de 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
est une opération de transformation. Il s'applique à chaque élément de RDD et renvoie le résultat comme nouveau RDD
. Il est similaire à Map, mais FlatMap permet de retourner 0, 1 ou plusieurs éléments de la fonction map. Dans l'opération FlatMap, un développeur peut définir sa propre logique métier personnalisée. La même logique sera appliquée à tous les éléments du RDD.
Que signifie «aplatir les résultats»?
Une fonction FlatMap prend un élément en entrée, le traite selon le code personnalisé (spécifié par le développeur) et renvoie 0 ou plusieurs éléments à la fois. flatMap
() transforme un RDD de longueur N en un autre RDD de longueur M.
Exemple d' flatMap
utilisation de 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 différence peut être vue à partir de l'exemple de code pyspark ci-dessous:
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 et Map transforment tous les deux la collection.
Différence:
map (func)
Retourne un nouvel ensemble de données distribué formé en passant chaque élément de la source à travers une fonction func.
flatMap (func)
Similaire à map, mais chaque élément d'entrée peut être mappé à 0 ou plusieurs éléments de sortie (donc func doit retourner un Seq plutôt qu'un seul élément).
La fonction de transformation:
map : un élément en entrée -> un élément en sortie.
flatMap : un élément entrant -> 0 ou plusieurs éléments sortants (une collection).
RDD.map
renvoie tous les éléments dans un seul tableau
RDD.flatMap
renvoie des éléments dans des tableaux de tableau
supposons que nous ayons du texte dans le fichier text.txt comme
Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD
Utilisation de la carte
val text=sc.textFile("text.txt").map(_.split(" ")).collect
production:
text: **Array[Array[String]]** = Array(Array(Spark, is, an, expressive, framework), Array(This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD))
Utilisation de flatMap
val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect
production:
text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)
Pour tous ceux qui ont voulu PySpark liés:
Exemple de transformation: flatMap
>>> a="hello what are you doing"
>>> a.split()
['salut que fais tu']
>>> b=["hello what are you doing","this is rak"]
>>> b.split()
Traceback (dernier appel le plus récent): Fichier "", ligne 1, dans AttributeError: l'objet 'list' n'a pas d'attribut 'split'
>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
... return x.split()
>>> rword=rline.map(fwords)
>>> rword.collect()
[['bonjour', 'quoi', 'êtes', 'vous', 'faire'], ['ceci', 'est', 'rak']]
>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()
['bonjour', 'quoi', 'êtes', 'vous', 'faire', 'ceci', 'est', 'rak']
J'espère que ça aide :)
map
: Il retourne un nouveau RDD
en appliquant une fonction à chaque élément du RDD
. La fonction dans .map ne peut renvoyer qu'un seul élément.
flatMap
: Similaire à la carte, il renvoie un nouveau RDD
en appliquant une fonction à chaque élément du RDD, mais la sortie est aplatie.
De plus, la fonction in flatMap
peut renvoyer une liste d'éléments (0 ou plus)
Par exemple:
sc.parallelize([3,4,5]).map(lambda x: range(1,x)).collect()
Sortie: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]
sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()
Sortie: l'avis o / p est aplati dans une seule liste [1, 2, 1, 2, 3, 1, 2, 3, 4]
Source: https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/
carte:
est une méthode d'ordre supérieur qui prend une fonction en entrée et l'applique à chaque élément du RDD source.
flatMap:
une méthode d'ordre supérieur et une opération de transformation qui prend une fonction d'entrée.
Différence de sortie de map et flatMap:
1.flatMap
val a = sc.parallelize(1 to 10, 5)
a.flatMap(1 to _).collect()
Production:
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()
Production:
3 6 6 3 8
alors
RDD.map
etRDD.flatMap
dans Apache Spark . En général, les opérations RDD de Spark sont modélisées d'après leurs opérations de collecte Scala correspondantes. Les réponses dans stackoverflow.com/q/1059776/590203 , qui discutent de la distinction entremap
etflatMap
dans Scala, peuvent vous être utiles.