谁能给我解释一下map和flatMap之间的区别,以及它们各自的良好用例是什么?
“flatten the results”是什么意思? 它有什么好处?
谁能给我解释一下map和flatMap之间的区别,以及它们各自的良好用例是什么?
“flatten the results”是什么意思? 它有什么好处?
当前回答
如果您正在询问RDD之间的区别。map和RDD。在Spark中,map将一个大小为N的RDD转换为另一个大小为N的RDD。如。
myRDD.map(x => x*2)
例如,如果myRDD由double组成。
而flatMap可以将RDD转换为另一个不同大小的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) )
其他回答
所有的例子都很好....这是一个很好的视觉插图…资料来源:spark的DataFlair培训
Map: Map是Apache Spark中的转换操作。它应用于RDD的每个元素,并将结果作为新的RDD返回。在Map中,操作开发人员可以定义自己的自定义业务逻辑。同样的逻辑将应用于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的所有元素。
“flatten the results”是什么意思?
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)
map
通过将函数应用到该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)]]
flatMap
返回一个新的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)]
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
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
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/
下面是一个不同的例子,作为一个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.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的行为很像一个只有一个元素或者没有元素的列表)