apache-spark - Spark else() 总是被评估
问题描述
想象一下我有以下代码:
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 子句中的条件如何。
谢谢。
解决方案
您混淆了两件不同的事情——执行计划的评估(这就是这里发生的事情)和对实际数据的物理计划的评估(这里没有发生)。必须始终评估执行计划,否则 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
来源。
推荐阅读
- react-native - 在 react-native 中模糊图像的一半
- c++ - 在 quickwidget openstreet 地图中添加/删除标记
- go - 更新时锁定特定分支的 go 模块
- solr - Solr - 如何在将数据发布到核心时修复“添加字段时出错 ... msg = For input string”
- python - 有人帮我解决这些关于英特尔 5300 wifi 卡数据的参数,这是什么意思?
- tensorflow - Tensorflow 中流式 F1 分数计算中的数据类型不匹配
- postgresql - 无法将 aurora-postgresql 从 9.6.9 升级到 10.7
- consul - Consul proxy failed to dial: dial tcp 127.0.0.1:0: connect: connection refused
- .net-core - 启用 Cors .Net Core
- jquery - AngularJS get parsed HTML