我有一个包含start_time
和end_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+。
答案 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"))
这不是理想的,但可能会有所帮助。