有人可以向我解释一下map和flatMap之间的区别吗?每个人的用例是什么?
“压扁结果”是什么意思? 有什么好处?
答案 0 :(得分:164)
这是差异的一个例子,作为spark-shell
会话:
首先,一些数据 - 两行文字:
val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue")) // lines
rdd.collect
res0: Array[String] = Array("Roses are red", "Violets are blue")
现在,map
将长度为N的RDD转换为另一个长度为N的RDD。
例如,它将两行映射为两个行长度:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
但flatMap
(松散地说)将长度为N的RDD转换为N个集合的集合,然后将这些RDD展平为单个RDD结果。
rdd.flatMap(_.split(" ")).collect
res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")
我们每行有多个单词和多行,但我们最终得到一个单词输出数组
为了说明这一点,从一组行到一组单词的flatMapping看起来像是:
["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]
因此,flatMap
的输入和输出RDD通常具有不同的大小。
如果我们尝试将map
与我们的split
函数一起使用,我们最终会得到嵌套结构(单词数组的RDD,类型为RDD[Array[String]]
),因为我们每个输入必须有一个结果:
rdd.map(_.split(" ")).collect
res3: Array[Array[String]] = Array(
Array(Roses, are, red),
Array(Violets, are, blue)
)
最后,一个有用的特例是使用可能不返回答案的函数进行映射,因此返回Option
。我们可以使用flatMap
过滤掉返回None
的元素,并从返回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)
(这里注意到Option的行为与包含一个元素或零元素的列表相似)
答案 1 :(得分:79)
通常我们在hadoop中使用单词计数示例。我将采用相同的用例,并使用map
和flatMap
,我们将看到它处理数据的方式不同。
以下是示例数据文件。
hadoop is fast
hive is sql on hdfs
spark is superfast
spark is awesome
上述文件将使用map
和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']
输入有4行,输出大小也是4,即N个元素==&gt; N个元素。
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']
输出与地图不同。
让我们为每个键指定1作为值以获得字数。
fm
:使用flatMap
wc
:使用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)]
而RDD map
上的wc
会给出以下不受欢迎的输出:
>>> 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]
如果使用map
代替flatMap
,则无法获得字数。
根据定义,map
和flatMap
之间的区别是:
map
:它通过将给定函数应用于每个元素来返回新的RDD 的RDD。map
中的函数只返回一个项目。
flatMap
:与map
类似,它通过应用函数返回新的RDD 到RDD的每个元素,但输出是扁平的。
答案 2 :(得分:16)
如果你在Spark中询问RDD.map和RDD.flatMap之间的区别,map会将大小为N的RDD转换为另一个大小为N的RDD。例如
myRDD.map(x => x*2)
例如,如果myRDD由双打组成。
虽然flatMap可以将RDD转换为另一个不同大小的另一个: 例如:
myRDD.flatMap(x =>new Seq(2*x,3*x))
将返回大小为2 * N的RDD 或
myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
答案 3 :(得分:13)
以test.md
为例:
➜ 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.)
如果您使用map
方法,您将获得test.md
行,flatMap
方法,您将获得字数。
map
方法类似于flatMap
,它们都返回一个新的RDD。经常使用map
方法返回一个新的RDD,flatMap
方法经常使用拆分字。
答案 4 :(得分:9)
map
返回相同数量元素的RDD,而flatMap
可能不会。
flatMap
的示例用例过滤掉丢失或不正确的数据。
map
的示例用例在各种情况下使用,其中输入和输出的元素数量相同。
<强> number.csv 强>
1
2
3
-
4
-
5
map.py 会在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 使用flatMap
在添加之前过滤掉缺失的数据。与之前的版本相比,添加的数字更少。
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
答案 5 :(得分:8)
归结为您最初的问题:扁平化是什么意思?
当您使用flatMap时,&#34;多维&#34; 集合将成为&#34; one-dimensional&#34; 集合。
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)
当你想要使用flatMap时,
答案 6 :(得分:7)
map和flatMap是相似的,从某种意义上说,它们从输入RDD中取一条线并在其上应用一个函数。它们的区别在于map中的函数只返回一个元素,而flatMap中的函数可以返回一个元素列表(0或更多)作为迭代器。
此外,flatMap的输出变平。虽然flatMap中的函数返回一个元素列表,但flatMap返回一个RDD,它以平面方式(不是列表)包含列表中的所有元素。
答案 7 :(得分:5)
差异可以从以下示例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]]
答案 8 :(得分:3)
Flatmap和Map都会转换集合。
差异:
<强>地图(FUNC)强>
返回通过函数函数传递源的每个元素而形成的新分布式数据集。
<强> flatMap(FUNC)强>
与map类似,但每个输入项可以映射到0个或更多输出项(因此func应返回Seq而不是单个项)。
转换功能:
地图: - &gt;中的一个元素一个元素出来。
flatMap : - &gt;中的一个元素0个或更多元素(集合)。
答案 9 :(得分:3)
RDD.map
返回单个数组中的所有元素
RDD.flatMap
返回数组数组中的元素
假设我们在text.txt文件中输入的文本为
Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD
使用地图
val text=sc.textFile("text.txt").map(_.split(" ")).collect
输出:
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
val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect
输出:
text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)
答案 10 :(得分:2)
对于所有想要PySpark相关的人:
示例转换:flatMap
>>> a="hello what are you doing"
>>> a.split()
[&#39;你好&#39;,&#39;什么&#39;,&#39;&#39;,&#39;你&#39;,&#39;做&#39;] < / p>
>>> b=["hello what are you doing","this is rak"]
>>> b.split()
追踪(最近一次通话): 文件&#34;&#34;,第1行,in AttributeError:&#39; list&#39;对象没有属性&#39; split&#39;
>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
... return x.split()
>>> rword=rline.map(fwords)
>>> rword.collect()
[[&#39;你好&#39;,&#39;什么&#39;,&#39;&#39;,&#39;你&#39;,&#39;做&#39;] ,[&#39;此&#39;,&#39;是&#39;,&#39; rak&#39;]
>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()
[&#39;你好&#39;,&#39;什么&#39;,&#39;&#39;,&#39;你&#39;,&#39;做&#39;,& #39;这&#39;,&#39;&#39;&#39; rak&#39;]
希望有所帮助:)
答案 11 :(得分:1)
map
:通过将函数应用于RDD
的每个元素,它返回一个新的RDD
。 .map 中的函数只能返回一项。
flatMap
:与map类似,它通过将函数应用于RDD的每个元素来返回新的RDD
,但输出被展平。
此外,flatMap
中的函数可以返回元素列表(0个或更多)
例如:
sc.parallelize([3,4,5]).map(lambda x: range(1,x)).collect()
输出:[[1、2],[1、2、3],[1、2、3、4]]
sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()
输出:注意o / p在一个列表中展平[1、2、1、2、3, 1,2,3,4]
来源:https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/
答案 12 :(得分:1)
所有示例都很好。...这是不错的视觉插图...来源:DataFlair training of spark
Map:映射是Apache Spark中的转换操作。它适用于RDD的每个元素,并将结果作为新的RDD返回。在地图中,操作开发人员可以定义自己的自定义业务逻辑。相同的逻辑将应用于RDD的所有元素。
Spark RDD map
函数根据自定义代码(由开发人员指定)将一个元素作为输入过程,并一次返回一个元素。 Map将长度为N的RDD转换为长度为N的另一个RDD。输入和输出RDD通常具有相同数量的记录。
使用scala的map
的示例:
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:
flatMap
是转换操作。它适用于RDD的每个元素,并以新的RDD
返回结果。它类似于Map,但是FlatMap允许从map函数返回0、1或多个元素。在FlatMap操作中,开发人员可以定义自己的自定义业务逻辑。相同的逻辑将应用于RDD的所有元素。
“整理结果”是什么意思?
FlatMap函数根据自定义代码(由开发人员指定)将一个元素作为输入过程,并一次返回0个或多个元素。 flatMap
()将长度为N的RDD转换为长度为M的另一个RDD。
使用scala的flatMap
的示例:
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)
答案 13 :(得分:0)
地图:
是一种以函数为输入并将其应用于源RDD中每个元素的高阶方法。
flatMap:
采用输入函数的高阶方法和转换操作。
答案 14 :(得分:0)
地图
通过对这个 RDD 的每个元素应用一个函数来返回一个新的 RDD。
>>> rdd = sc.parallelize([2, 3, 4])
>>> sorted(rdd.map(lambda x: [(x, x), (x, x)]).collect())
[[(2, 2), (2, 2)], [(3, 3), (3, 3)], [(4, 4), (4, 4)]]
平面地图
首先对这个RDD的所有元素应用一个函数,然后将结果展平,从而返回一个新的RDD。 这里可以将一个元素转换为多个元素
>>> rdd = sc.parallelize([2, 3, 4])
>>> sorted(rdd.flatMap(lambda x: [(x, x), (x, x)]).collect())
[(2, 2), (2, 2), (3, 3), (3, 3), (4, 4), (4, 4)]
答案 15 :(得分:-1)
田地
答案 16 :(得分:-1)
map和flatMap的输出差异:
1。flatMap
val a = sc.parallelize(1 to 10, 5)
a.flatMap(1 to _).collect()
输出:
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()
输出:
3 6 6 3 8