【发布时间】:2018-02-21 20:38:44
【问题描述】:
我正在寻找一个函数,该函数采用一些数字序列和一个 spark 列,然后 有效地 计算一个具有列表中匹配的最高数字的新列,如果没有,则默认为 0匹配。
例如取序列 [500, 100, 1]。
天真的方法是为序列手动编写以下内容:
val manualAdjustment = (c: Column) =>
when(c.isNull, -1)
.when(c > 500, 500)
.when(c > 100, 100)
.when(c > 1, 1)
.otherwise(0)
当我们提供一个列时,例如lit(1),我们会得到简洁明了的计划:
CASE WHEN (1 IS NULL) THEN -1 WHEN (1 > 500) THEN 500 WHEN (1 > 100) THEN 100 WHEN (1 > 1) THEN 1 ELSE 0 END.
如果有一个函数在给定一列和一个任意有序整数序列的情况下组成相同的计划,而不是手动为每个序列写出先前的代码,那会好得多。
这导致我编写以下函数:
val makeRange: (Column, Seq[Int]) => Column = (col: Column, range: Seq[Int]) => {
val whenFunction = (c: Column, condition: Column, value: Int) =>
c.when(condition, value)
val reduced: Column => Column =
range.map(i => (column: Column) => whenFunction(column, column > i, i))
.reduce(_ compose _)
reduced(when(col.isNull, -1)).otherwise(0)
}
此函数根据列值大于 int 将每个 int 映射到 when 条件,因此至少在理论上它执行与上述 manualAdjustment 函数相同的操作。但是,makeRange(lit(1), Seq(500, 100, 1)) 的输出却是:
CASE WHEN (1 IS NULL) THEN -1 WHEN (CASE WHEN (1 IS NULL) THEN -1 END > 500) THEN 500 WHEN (CASE WHEN (1 IS NULL) THEN -1 WHEN (CASE WHEN (1 IS NULL) THEN -1 END > 500) THEN 500 END > 100) THEN 100 WHEN (CASE WHEN (1 IS NULL) THEN -1 WHEN (CASE WHEN (1 IS NULL) THEN -1 END > 500) THEN 500 WHEN (CASE WHEN (1 IS NULL) THEN -1 WHEN (CASE WHEN (1 IS NULL) THEN -1 END > 500) THEN 500 END > 100) THEN 100 END > 1) THEN 1 ELSE 0 END
这个计划至少比另一个计划更冗长,但似乎效率低得多,因为它(似乎)必须一遍又一遍地计算相同的 where 条件。我的理论是,当条件计算到位并在条件需要评估折叠中的前一个“步骤”时进一步应用,这就需要一遍又一遍地计算相同的条件。
了解为什么会发生这种情况,或者如何编写类似于makeRange 的函数来创建像manualAdjustment 这样简单的计划?
【问题讨论】:
标签: scala apache-spark fold