Scala Spark优化链式转换吗?
将一个复杂的映射操作表示为代码中的一系列链式映射任务,而不是一个大型操作,通常更为简洁。我知道Spark DAG调度程序执行优化,但它是否也会以这种方式优化链式操作 下面是一个人为的示例,其中从CSV字段中提取不同日期的列表: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
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美元;我已经看得更深了;优化器可以查看映射操作内部吗?