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 = None
和validation = 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() 总是被评估的主要内容,如果未能解决你的问题,请参考以下文章