谁能给我解释一下map和flatMap之间的区别,以及它们各自的良好用例是什么?

“flatten the results”是什么意思? 它有什么好处?


当前回答

对于所有想要PySpark相关的人:

示例转换:flatMap

>>> a="hello what are you doing"
>>> a.split()

['hello', 'what', 'are', 'you', 'doing']

>>> b=["hello what are you doing","this is rak"]
>>> b.split()

回溯(最近一次调用): 文件“”,第1行,在 AttributeError: 'list'对象没有属性'split'

>>> rline=sc.parallelize(b)
>>> type(rline)

>>> def fwords(x):
...     return x.split()


>>> rword=rline.map(fwords)
>>> rword.collect()

[[‘你好’,‘什么’,‘是’,‘你’,‘做’],[‘这个’,‘是’,'爱你']]

>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()

[‘你好’,‘什么’,‘是’,‘你’,‘做’,‘这’,‘是’,‘爱’)

希望能有所帮助。

其他回答

下面是一个不同的例子,作为一个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的行为很像一个只有一个元素或者没有元素的列表)

这可以归结为你最初的问题:你所说的扁平化是什么意思?

当您使用flatMap时,“多维”集合就变成了“一维”集合。

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时,

你的地图功能的结果是创建多层结构 但所有你想要的是一个简单的-平面-一维结构,通过删除所有的内部分组

使用测试。以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.)

如果您使用映射方法,您将得到测试线。md,对于flatMap方法,您将得到字数。

map方法类似于flatMap,它们都返回一个新的RDD。map方法经常使用返回一个新的RDD, flatMap方法经常使用分割词。

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的每个元素应用函数来返回一个新的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/