在不改变窗口逻辑的情况下并行化窗口函数或加速火花中的窗口函数

时间:2021-07-02 23:19:02

标签: apache-spark apache-spark-sql

我在 spark 查询中有一组窗口函数,其中包括 user_num 上的分区。其中一个 user_nums 的行比其他的多得多。这一行是在单个任务中计算的,它具有更高的随机读取、随机远程读取并最终需要大量时间。

Select LAG(e) OVER (PARTITION BY user_num, a, date ORDER BY time) as aa,
FIRST_VALUE(e)  OVER (PARTITION BY a, date ORDER BY time ROWS
BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as bbb
FROM table

是否有任何设置或任何方法可以在不同的任务上运行此程序,或者以不需要或最少更改窗口函数逻辑的方式缩短此时间?

I.E 我可以在某个点缓存,增加分区数,增加 exec mem 等

2 个答案:

答案 0 :(得分:0)

关于通过牺牲一些数据损失来扩大规模的建议,即增加分区窗口的粒度

示例

  • 将“HOUR”值提取到新列中。
  • 现在 PARTITION BY user_num, a, date, HOUR

现在,您的单个​​任务将分为 24 个任务

但这会为您的 LAG 带来更多 NULLS。例如,如果您正在计算偏移量为 4 的滞后,那么对于每一小时的数据,您将有 3 个 NULL 值。

所以,这就像速度与准确数据之间的权衡


您可以进一步将粒度增加到分钟,以实现更多的并行性,但代价是更多的 NULL。


在损失方面的进一步改进:

如果您选择使用较低的粒度,这可能会影响其他“user_nums”。 最好分成 2 个 dfs :

  • 分成 2 个 dfs(按计数使用一个组,并拥有一个线程,让 user_num 考虑倾斜,或者您可以硬编码,如果您认为它已修复。)
  • One_with_Skewed_Data
  • One_with_normal_Data
  • result_from_Skew = One_with_Skewed_Data ..低粒度窗口查询
  • result_from_normal = One_with_normal_Data .. 使用您的常规查询

result = result_from_Skew.union(result_from_normal)

答案 1 :(得分:0)

我在这里做了两件事:

  1. 将窗口函数更改为模仿窗口函数的连接。这允许计算并行运行
  2. 最终我采用的解决方案是将 First_Value 更改为 Last_Value 并按列切换顺序的方向。不知道为什么这会有所帮助,但它进行得更快。可能是 First_Value udf 中的一个错误。

FIRST_VALUE(e) OVER (PARTITION BY a, date ORDER BY time desc ROWS 无界前行和当前行之间) as bbb