Spark else() 总是被评估

Posted

技术标签:

【中文标题】Spark else() 总是被评估【英文标题】:Spark otherwise() is always being evaluated 【发布时间】: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 子句中的条件如何。

谢谢。

【问题讨论】:

【参考方案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。

【讨论】:

我在这里所说的一切都是有效的-执行计划的评估!=根据实际数据评估生成的代码。您的代码甚至没有达到“为每一行执行”的地步。

以上是关于Spark else() 总是被评估的主要内容,如果未能解决你的问题,请参考以下文章

&& 之后的条件是不是总是被评估

缓存后正在重新评估 Spark 数据帧

Spark ML机器学习库评估指标示例

是啥导致重新评估 if/else 表达式?

spark 评估指标

spark 评估指标