Scala Spark优化链式转换吗?

Scala Spark优化链式转换吗?,scala,apache-spark,Scala,Apache Spark,将一个复杂的映射操作表示为代码中的一系列链式映射任务,而不是一个大型操作,通常更为简洁。我知道Spark DAG调度程序执行优化,但它是否也会以这种方式优化链式操作 下面是一个人为的示例,其中从CSV字段中提取不同日期的列表: csv.map(row => row.split(",")) .map(row => row(6)) // extract the proper field .map(date_field => DateTime.parse(date_fie

将一个复杂的映射操作表示为代码中的一系列链式映射任务,而不是一个大型操作,通常更为简洁。我知道Spark DAG调度程序执行优化,但它是否也会以这种方式优化链式操作

下面是一个人为的示例,其中从CSV字段中提取不同日期的列表:

csv.map(row => row.split(","))
   .map(row => row(6)) // extract the proper field
   .map(date_field => DateTime.parse(date_field).withTimeAtStartOfDay())
   .distinct()

如果一个映射操作后跟一个
distinct()
,这个例子会更有效吗?

我想我会把我的评论变成一个答案,因为没有其他人决定回答。基本上,这是拥有惰性DAG体系结构的要点之一。因为在看到最终的DAG之前不会执行任何操作,所以进行优化(比如组合不需要洗牌的操作)相对来说是很简单的(我将看看是否能找到实际的代码)。假设一行中有一组映射,spark知道它可以丢弃上一个映射的结果,除非缓存,否则缓存可以防止RDD在多次使用时必须重新计算。因此,当您考虑许多MR样式的作业是IO绑定时,合并到1 MAP函数将不仅仅是一种微优化,而且可能不会产生影响。p>
更新:通过查看spark用户列表,似乎一个
阶段可以有多个任务,特别是可以像地图一样链接在一起的任务可以放在一个阶段中。

简短回答:是的,但仅适用于线性相关性

长答案:比较Spark SQL/DataFrame的查询优化器,几乎不存在

Spark core API不会重写DAG的执行计划,即使它显然是有益的。以下是一个例子:

考虑到DAG:

A > B > D
  > C >
其中D被收集,A没有被持久化(持久化是一个昂贵的操作,另外,如果您不知道D是否将被收集,那么您无法决定何时取消持久化)。理想情况下,优化器应该将这个DAG转换为线性的&更便宜的A>Tuple2(B,C)>D。所以让我们测试一下:

val acc = sc.accumulator(0)
val O = sc.parallelize(1 to 100)
val A = O.map{
  v =>
    acc += 1
    v * 2
}
val B = A.map(_*2)
val C = A.map(_*3)
val D = B.zip(C).map(v => v._1 + v._2)

D.collect()

assert(acc.value == 100)
结果如何

200 did not equal 100
显然,执行了未优化的DAG


此外,从未提出过此类功能(或任何相近的功能,例如广播加入/洗牌加入基于成本的优化器)。可能是因为大多数Spark开发人员更喜欢对执行进行更直接的控制,或者与SQL查询优化器相比,此类优化的效果非常有限。

这正是DAG调度程序的目的,基本上Spark体系结构允许它丢弃上一个映射的结果,除非缓存它,有可能只有一张地图可能是一个微观优化,但我不会担心它。关于Spark如何从转换中创建DAG的信息,bitI建议您查看这篇文章?它是如何管道化(优化)狭窄的转换和执行计划的?优化器不会注意到您正在使用
acc.value
,因此不允许更改它吗?如果是这种情况,结果无论如何都应该是100。但是它是200.00美元;我已经看得更深了;优化器可以查看映射操作内部吗?