Spark DataFrame:是否保证withColumn的顺序?

时间:2017-08-23 21:39:48

标签: scala apache-spark dataframe apache-spark-sql

给出以下代码:

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

1 个答案:

答案 0 :(得分:5)

  1. IS 保证,对于dataFrame中的每个特定记录myUdf1将会myUdf2之前应用myUdf1;但是:
  2. 保证dataFramemyUdf2应用于myUdf2应用于<{1>}的所有记录 >任何记录 - 换句话说,myUdf1可能会在myUdf1应用于其他记录之前应用于某些记录
  3. 这是正确的,因为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"
    

    注意这也不是防弹的 - 例如,如果有失败和重试,订单可能再次是非确定性的。