给出以下代码:
dataFrame
.withColumn("A", myUdf1($"x")) // withColumn1 from x
.withColumn("B", myUdf2($"y")) // withColumn2 from y
是否保证在withColumn1
之前执行withColumn2
?
一个更好的例子:
dataFrame
.withColumn("A", myUdf1($"x")) // withColumn1 from x
.withColumn("B", myUdf2($"A")) // withColumn2 from A!!
请注意,withColumn2对A
的{{1}}进行操作。
我问,因为我在同一代码的多次运行中得到了不一致的结果,我开始认为这可能是问题的根源。
编辑:添加了更详细的代码示例
withColumn1
答案 0 :(得分:5)
dataFrame
中的每个特定记录,myUdf1
将会myUdf2
之前应用myUdf1
;但是:dataFrame
在myUdf2
应用于myUdf2应用于<{1>}的所有记录 >任何记录 - 换句话说,myUdf1
可能会在myUdf1
应用于其他记录之前应用于某些记录这是正确的,因为Spark可能会将两个操作合并为一个阶段,并在每个分区的每个记录上执行此阶段(应用myUdf2
和// sample data:
val dataFrame = Seq("A", "V", "D").toDF("x")
// two UDFs with "side effects" (printing to console):
val myUdf1 = udf[String, String](x => {
println("In UDF1")
x.toLowerCase
})
val myUdf2 = udf[String, String](x => {
println("In UDF2")
x.toUpperCase
})
// repartitioning between UDFs
dataFrame
.withColumn("A", myUdf1($"x"))
.repartition(dataFrame.rdd.partitions.length + 1)
.withColumn("B", myUdf2($"A"))
.show()
// prints:
// In UDF1
// In UDF1
// In UDF1
// In UDF2
// In UDF2
// In UDF2
)
如果您的UDF“纯功能”或“幂等”,或者没有副作用,这不应该造成任何问题 - 而且应该,因为Spark假定所有转换都是这样的。如果不是这样,Spark就无法通过“组合”转换来优化执行,在不同的分区上并行运行它们,重试转换等。
编辑:如果您想在将UDF2应用到任何记录之前完全应用强制 UDF1,则必须强制它们进入单独的阶段< / strong> - 这可以通过重新分区 DataFrame来完成:
// example.h
#include "a.h"
#include "b.h"
#include "c.h"
#include "d.h"
#include "e.h"
注意这也不是防弹的 - 例如,如果有失败和重试,订单可能再次是非确定性的。