PySpark中Order By对Window函数MAX计算结果影响的疑问咨询
为什么Spark窗口函数的MAX结果随排序顺序变化?
嘿,这个问题其实是Spark窗口函数里**默认窗口帧(Window Frame)**的行为搞的鬼,很多刚用窗口函数的朋友都会踩这个坑!
核心原因:orderBy会改变默认的窗口帧范围
当你在Window定义中添加orderBy时,Spark会自动将窗口帧的范围设置为:
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
简单说就是:只计算从分区的第一行到当前行这个范围内的聚合值,而不是整个分区的所有行!
我们来拆解你的两种情况:
- 升序排序(
orderBy(df['REVENUE'])):
数据按收入从小到大排列,每一行的窗口帧只包含它自己和前面比它小/相等的行。因为是升序,当前行是这个范围内最大的,所以max(REVENUE)自然等于当前行的收入值。 - 降序排序(
orderBy(df['REVENUE']).desc()):
数据按收入从大到小排列,第一行就是整个分区的最大值。后面每一行的窗口帧都包含第一行(最大值)到当前行,所以max(REVENUE)一直是整个分区的最大值。
解决方法:显式指定窗口帧为整个分区
如果你想获取整个分区的最大值,不受排序影响,有两种方式:
- 显式指定窗口帧范围覆盖整个分区:
window_spec = Window.partitionBy(df['CATEGORY']) \ .orderBy(df['REVENUE']) \ .rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
- 如果你不需要排序逻辑,直接去掉
orderBy——当窗口没有orderBy时,默认的窗口帧就是整个分区,此时max会直接返回分区内的最大值:
window_spec = Window.partitionBy(df['CATEGORY'])
验证修改后的结果
用修改后的窗口定义运行代码,不管是升序还是降序排序,revenue_difference都会显示每个分类的最大收入:
+----------+-------+------------------+ | CATEGORY|REVENUE|revenue_difference| +----------+-------+------------------+ |Cell Phone| 3000| 6000| |Cell Phone| 3000| 6000| |Cell Phone| 5000| 6000| |Cell Phone| 6000| 6000| |Cell Phone| 6000| 6000| | Tablet| 1500| 6500| | Tablet| 2500| 6500| | Tablet| 3000| 6500| | Tablet| 4500| 6500| | Tablet| 5500| 6500| | Tablet| 6500| 6500| +----------+-------+------------------+
内容的提问来源于stack exchange,提问作者Vlad Vlad
相关产品推荐
相关产品推荐

