Spark窗口功能:引用范围的不同列

时间:2017-07-13 23:10:53

标签: apache-spark pyspark spark-dataframe window-functions pyspark-sql

我有一个包含start_timeend_time列的DataFrame。我想设置窗口,每个观察窗口是结束时间之前的两行,仅限于在观察之前end_time的{​​{1}} start_time

示例数据:

data = [('a', 10, 12, 5),('b', 20, 25, 10),('c', 30, 60, 15),('d', 40, 45, 20),('e', 50, 70, 25)]
df = sqlContext.createDataFrame(data, ['name', 'start_time', 'end_time', 'resource'])
+----+----------+--------+--------+
|name|start_time|end_time|resource|
+----+----------+--------+--------+
|   a|        10|      12|       5|
|   b|        20|      25|      10|
|   c|        30|      60|      15|
|   d|        40|      45|      20|
|   e|        50|      70|      25|
+----+----------+--------+--------+

所以&#39> e'应该包括' b'和' d',但不是' c'

没有结束时间的限制<开始时间,我能够使用

from pyspark.sql import Window        
from pyspark.sql import functions as func
window = Window.orderBy("name").rowsBetween(-2, -1)
df.select('*', func.avg("resource").over(window).alias("avg")).show()

我查看了rangeBetween(),但我找不到引用当前行的start_time的方法,或者我希望通过end_time来限制它其他行。有Window.currentRow,但在此示例中,它只会引用resource的值

这可以使用Window吗?我应该完全尝试别的吗?

编辑:如果重要的话,使用Spark 2.1.1和Python 2.7+。

2 个答案:

答案 0 :(得分:2)

您实际上可以使用groupBy函数对不同分区进行聚合,然后在同一个公共密钥上使用输出数据帧之间的内部联接。分区或窗口函数需要花费很多时间在spark中,所以如果可以的话,最好使用groupby。

答案 1 :(得分:1)

我不认为纯粹使用Windows是可能的。从给定的行开始,您需要能够以反向排序顺序返回前一行,直到您有两个符合您条件的命中。

您可以使用窗口函数创建每行遇到的所有先前值的列表,然后使用带有一些纯scala / python的UDF来确定总和,从而计算排除项。

在scala中:

val window = Window.partitionBy(???).orderBy("end_time").rowsBetween(Long.MinValue, -1)

val udfWithSelectionLogic = udf { values: Seq[Row] => INSERT_LOGIC_HERE_TO_CALCULATE_AGGREGATE }

val dataPlus = data.withColumn("combined", struct($"start_time", $"end_time", $"resource"))
        .withColumn("collected", collect_list($"combined") over window)
        .withColumn("result", udfWithSelectionLogic($"collected"))

这不是理想的,但可能会有所帮助。