我经常在Apache Spark中使用Window-Functions来计算累积总和。到目前为止,我从未指定过帧,因为输出是正确的。但最近我在博客中看到了https://databricks.com/blog/2015/07/15/introducing-window-functions-in-spark-sql.html):
除了排序和分区外,用户还需要定义 开始帧的边界,帧的结束边界和 框架的类型,它是框架的三个组成部分 说明书
所以我想知道使用未指定的框架是否安全,例如:
import org.apache.spark.sql.expressions.Window
val df = (1 to 10000).toDF("i")
df
.select(
$"i",
sum($"i").over(Window.orderBy($"i")).as("running_sum1"),//unspecified frame
sum($"i").over(Window.orderBy($"i").rowsBetween(Window.unboundedPreceding, Window.currentRow)).as("running_sum2") // specified frame
)
.show()
+---+------------+------------+
| i|running_sum1|running_sum2|
+---+------------+------------+
| 1| 1| 1|
| 2| 3| 3|
| 3| 6| 6|
| 4| 10| 10|
| 5| 15| 15|
| 6| 21| 21|
| 7| 28| 28|
| 8| 36| 36|
| 9| 45| 45|
| 10| 55| 55|
| 11| 66| 66|
| 12| 78| 78|
| 13| 91| 91|
| 14| 105| 105|
| 15| 120| 120|
| 16| 136| 136|
| 17| 153| 153|
| 18| 171| 171|
| 19| 190| 190|
| 20| 210| 210|
+---+------------+------------+
显然他们会提供相同的输出,但是有些情况下使用未指定的框架是危险的吗?顺便使用Spark 2.x。
答案 0 :(得分:2)
是的,这是安全的。
查看github上Window
对象的主分支的源代码,有以下注释(它在2.3.0分支中不存在):
未定义排序时,默认使用无界窗框(rowFrame,unboundedPreceding,unboundedFollowing)。定义排序时,默认使用不断增长的窗口框架(rangeFrame,unboundedPreceding,currentRow)。
换句话说,当窗口上有排序时,即使用orderBy
时,帧上未指定的边界等于:
rowsBetween(Window.unboundedPreceding, Window.currentRow)
如果未使用orderBy
,则默认为无限制的无界窗口:
rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
进一步调查表明,由于在Spark 1.4.0中引入了窗口函数,因此使用了这些默认值,相关github branch:
def defaultWindowFrame(
hasOrderSpecification: Boolean,
acceptWindowFrame: Boolean): SpecifiedWindowFrame = {
if (hasOrderSpecification && acceptWindowFrame) {
// If order spec is defined and the window function supports user specified window frames,
// the default frame is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
SpecifiedWindowFrame(RangeFrame, UnboundedPreceding, CurrentRow)
} else {
// Otherwise, the default frame is
// ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.
SpecifiedWindowFrame(RowFrame, UnboundedPreceding, UnboundedFollowing)
}
}