我正在寻找创建一个需要一些数字序列和一个火花列的函数,然后高效计算一个列表中匹配最多的新列,默认为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
这个计划至少比另一个计划更冗长,但似乎效率低得多,因为它(貌似)必须一遍又一遍地计算相同的条件。我的理论是,当条件需要评估前一步骤时,计算何时条件并进一步应用。在折叠中,这需要一遍又一遍地计算相同的条件。
有关为何发生这种情况的任何见解,或者如何编写类似于makeRange
的函数,该函数创建的计划与manualAdjustment
一样简单?
答案 0 :(得分:1)
这似乎与您的manualAdjustment
创建了相同的计划:
val makeRange = (c: Column, range:Seq[Int]) =>
range.foldLeft(when(c.isNull, -1))((acc: Column, curr: Int) => acc.when(c>curr,curr)).otherwise(0)
== Physical Plan ==
LocalTableScan [CASE WHEN (i IS NULL) THEN -1 WHEN (i > 500) THEN 500 WHEN (i > 100) THEN 100 WHEN (i > 1) THEN 1 ELSE 0 END#10]