【问题标题】:Spark otherwise() is always being evaluatedSpark else() 总是被评估
【发布时间】:2020-03-04 16:16:52
【问题描述】:

假设我有以下代码:

val option: Option[String] = ??? // May be some or none
val validation: Boolean = ??? // May be true or false

val df = ??? // load data

现在我想添加两个新列:

  • 第一个是基于布尔值的列
  • 第二个基于 when-otherwise 子句。当上一个 列是真的,我只是放了一个lit(3) 值。当它是假的时,我打电话给 一个函数,应该在选项值时抛出异常 不存在:

    def dealWithOtherwise(maybeString: Option[String]): Column = {
       maybeString match {
         case Some(default) => lit(default)
         case None => throw new Exception()
       }
    }
    
    df
     .withColumn("validationIsOk", validation)
     .withColumn("field",
        when(col("validationIsOk"), lit(3)).otherwise(dealWithOtherwise(option))
     )
    

我想在option = Nonevalidation = false 时抛出异常。但是,当验证为真且默认选项为无时,我会抛出异常。就像 else 函数总是为每一行执行,无论 when 子句中的条件如何。

谢谢。

【问题讨论】:

    标签: apache-spark apache-spark-sql


    【解决方案1】:

    您混淆了两个不同的事情 - 评估执行计划(这就是这里发生的事情)和评估实际数据的物理计划(这不会发生在这里)。必须始终评估执行计划,否则 Spark 将不知道如何生成相应的代码。另一方面,不同的评估分支可以从计划中删除或在执行期间跳过(使用标准控制流)。

    在您的情况下,计划根本无效,因为 None 不能用作文字。这并不意味着根据实际数据评估此类计划的任何方式(实际上可能会或可能不会短路,具体取决于所使用的表达式)。

    事实上,你可以很容易地检查出在这种简单的情况下,CASE WHEN 的优化计划是否完全删除了其他分支

    spark.range(1).select(when(lit(true), 1).otherwise(2) as "x").explain(true)
    
    == Parsed Logical Plan ==
    Project [CASE WHEN true THEN 1 ELSE 2 END AS x#10]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Analyzed Logical Plan ==
    x: int
    Project [CASE WHEN true THEN 1 ELSE 2 END AS x#10]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Optimized Logical Plan ==
    Project [1 AS x#10]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Physical Plan ==
    *(1) Project [1 AS x#10]
    +- *(1) Range (0, 1, step=1, splits=8)
    
    spark.range(1).select(when(lit(false), 1).otherwise(2) as "x").explain(true)
    
    == Parsed Logical Plan ==
    Project [CASE WHEN false THEN 1 ELSE 2 END AS x#14]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Analyzed Logical Plan ==
    x: int
    Project [CASE WHEN false THEN 1 ELSE 2 END AS x#14]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Optimized Logical Plan ==
    Project [2 AS x#14]
    +- Range (0, 1, step=1, splits=Some(8))
    
    == Physical Plan ==
    *(1) Project [2 AS x#14]
    +- *(1) Range (0, 1, step=1, splits=8)
    

    但是,您不应该对此进行推断 - 某些执行模式(尤其是 UDF 的某些变体)无法通过这种方式进行优化。

    详情请参考SimplifyConditionals source

    【讨论】:

    • 我在这里所说的一切都是有效的-执行计划的评估!=根据实际数据评估生成的代码。您的代码甚至没有达到“为每一行执行”的地步。
    猜你喜欢
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-01
    • 2015-12-21
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 2013-11-23
    相关资源
    最近更新 更多