在Spark中使用带有未定义框架的WindowSpec是否安全?

时间:2018-06-01 06:17:20

标签: scala apache-spark window-functions

我经常在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。

1 个答案:

答案 0 :(得分:2)

是的,这是安全的。

查看githubWindow对象的主分支的源代码,有以下注释(它在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)
  }
}