Performance ApacheSpark:map与mapPartitions?

Performance ApacheSpark:map与mapPartitions?,performance,scala,apache-spark,rdd,Performance,Scala,Apache Spark,Rdd,map和mapPartitions方法之间有什么区别?而flatMap的行为类似于map还是类似于mapPartitions?谢谢 (编辑) i、 e.两者之间的区别(无论是语义上还是执行方面)是什么 RDD的map和mapPartitions方法有什么区别 该方法通过应用函数将源RDD的每个元素转换为结果RDD的单个元素。将源RDD的每个分区转换为结果的多个元素(可能没有) flatMap的行为类似于map还是mapPartitions 两者都不适用于单个元素(如map)并生成结果的多个元素(

map
mapPartitions
方法之间有什么区别?而
flatMap
的行为类似于
map
还是类似于
mapPartitions
?谢谢

(编辑) i、 e.两者之间的区别(无论是语义上还是执行方面)是什么

RDD的map和mapPartitions方法有什么区别

该方法通过应用函数将源RDD的每个元素转换为结果RDD的单个元素。将源RDD的每个分区转换为结果的多个元素(可能没有)

flatMap的行为类似于map还是mapPartitions

两者都不适用于单个元素(如
map
)并生成结果的多个元素(如
map分区
)。

Imp.TIP: 每当你有重量级的初始化,应该做一次 对于许多
RDD
元素,而不是每个
RDD
元素一次,以及 初始化,例如从第三方创建对象 库,无法序列化(以便Spark可以跨 将群集连接到工作节点),使用
mapPartitions()
而不是
map()
<代码>映射分区()提供了要完成的初始化 每个辅助任务/线程/分区一次,而不是每个
RDD
数据一次 元素,请参见下文


问题2平面地图的行为是否类似于地图或地图分区

对。请参见
flatmap
的示例2。。这是不言自明的

问题1RDD的
map
mapPartitions
之间有什么区别

map
在每个元素级别上运行正在使用的功能,而
mapPartitions
在分区级别执行该功能

示例场景:如果我们在一个特定的
RDD
分区中有100K个元素,那么当我们使用
map
时,我们将触发映射转换使用的函数100K次

相反,如果我们使用
mapPartitions
,那么我们将只调用一次特定函数,但我们将传入所有100K记录,并在一次函数调用中返回所有响应

由于
map
多次在特定函数上工作,因此性能会有所提高,特别是如果函数每次都做一些昂贵的事情,而如果我们一次传入所有元素,它就不需要做这些事情(在
map分区
的情况下)

地图 对RDD的每个项应用转换函数并返回 结果显示为一个新的RDD

列出变体

def映射[U:ClassTag](f:T=>U):RDD[U]

例如:

val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)
 val b = a.map(_.length)
 val c = a.zip(b)
 c.collect
 res0: Array[(String, Int)] = Array((dog,3), (salmon,6), (salmon,6), (rat,3), (elephant,8)) 
映射分区 这是一个专门的映射,每个分区只调用一次。 各个分区的全部内容都可以作为 通过输入参数的连续值流(Iterarator[T])。 自定义函数必须返回另一个迭代器[U]。合并 结果迭代器将自动转换为新的RDD。请 请注意,下面缺少元组(3,4)和(6,7) 由于我们选择的分区而导致的结果

preserveSpatiting
指示输入函数是否保留 分区器,它应该是
false
,除非这是一对RDD和输入 函数不修改键

列出变体

def-mapPartitions[U:ClassTag](f:Iterator[T]=>Iterator[U], preserveSpatiting:Boolean=false):RDD[U]

例1

val a = sc.parallelize(1 to 9, 3)
 def myfunc[T](iter: Iterator[T]) : Iterator[(T, T)] = {
   var res = List[(T, T)]()
   var pre = iter.next
   while (iter.hasNext)
   {
     val cur = iter.next;
     res .::= (pre, cur)
     pre = cur;
   }
   res.iterator
 }
 a.mapPartitions(myfunc).collect
 res0: Array[(Int, Int)] = Array((2,3), (1,2), (5,6), (4,5), (8,9), (7,8)) 
例2

val x = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9,10), 3)
 def myfunc(iter: Iterator[Int]) : Iterator[Int] = {
   var res = List[Int]()
   while (iter.hasNext) {
     val cur = iter.next;
     res = res ::: List.fill(scala.util.Random.nextInt(10))(cur)
   }
   res.iterator
 }
 x.mapPartitions(myfunc).collect
 // some of the number are not outputted at all. This is because the random number generated for it is zero.
 res8: Array[Int] = Array(1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 7, 7, 7, 9, 9, 10) 
上述程序也可以使用flatMap编写,如下所示

示例2使用flatmap

val x  = sc.parallelize(1 to 10, 3)
 x.flatMap(List.fill(scala.util.Random.nextInt(10))(_)).collect

 res1: Array[Int] = Array(1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10) 
结论:
mapPartitions
转换比
map
更快,因为它只调用一次函数/partition,而不是一次/element


进一步阅读:

地图

  • 它一次处理一行,非常类似于MapReduce的map()方法
  • 您将在每一行之后从转换返回
  • 映射分区

  • 它可以一次性处理整个分区
  • 处理完整个分区后,只能从函数返回一次
  • 在处理整个分区之前,所有中间结果都需要保存在内存中
  • 提供类似MapReduce的setup()map()和cleanup()函数
  • 映射与映射分区

    Spark Map

    Spark映射分区

    地图:

    地图转换

    地图一次只能在一行上工作

    映射在每个输入行之后返回

    映射没有将输出结果保存在内存中

    地图没有办法弄清楚然后结束服务

    // map example
    
    val dfList = (1 to 100) toList
    
    val df = dfList.toDF()
    
    val dfInt = df.map(x => x.getInt(0)+2)
    
    display(dfInt)
    
    映射分区:

    映射分区转换

    MapPartition一次在一个分区上工作

    MapPartition在处理分区中的所有行后返回

    MapPartition输出保留在内存中,因为它可以在处理特定分区中的所有行后返回

    MapPartition服务可以在返回之前关闭

    // MapPartition example
    
    Val dfList = (1 to 100) toList
    
    Val df = dfList.toDF()
    
    Val df1 = df.repartition(4).rdd.mapPartition((int) => Iterator(itr.length))
    
    Df1.collec()
    
    //display(df1.collect())
    
    有关更多详细信息,请参阅本文


    希望这是有帮助的

    谢谢-那么map是否会导致混乱(或者改变分区的数量)?它是否在节点之间移动数据?我一直在使用Maviges避免在节点之间移动数据,但不确定FLAPMAP是否会这样做。如果您查看源代码-并且,无论是“代码> MAP < /COD>和图> <代码>都有与父分区完全相同的分区。作为说明,由2013届旧金山SCAPER峰会(GOO.GL/JZXDCR)的演讲者提供的演示文稿提供。突出显示具有高每记录ove的任务
    val x  = sc.parallelize(1 to 10, 3)
     x.flatMap(List.fill(scala.util.Random.nextInt(10))(_)).collect
    
     res1: Array[Int] = Array(1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10) 
    
    // map example
    
    val dfList = (1 to 100) toList
    
    val df = dfList.toDF()
    
    val dfInt = df.map(x => x.getInt(0)+2)
    
    display(dfInt)
    
    // MapPartition example
    
    Val dfList = (1 to 100) toList
    
    Val df = dfList.toDF()
    
    Val df1 = df.repartition(4).rdd.mapPartition((int) => Iterator(itr.length))
    
    Df1.collec()
    
    //display(df1.collect())