首先,为那些可能不知道稳定排序定义的阅读者设置上下文,我将引用此StackOverflow answer by Joey Adams
"如果两个对象相等,则称排序算法是稳定的
键在排序输出中出现的顺序与它们在
要排序的输入数组” - Joey Adams
现在,spark 中的窗口函数可以被认为是 Spark 处理整个集合的 mini-DataFrame,其中每个 mini-DataFrame 都是在指定的键(在本例中为“group_id”)创建的。
也就是说,如果提供的数据帧的“group_id”=2,我们最终会得到两个 Windows,其中第一个仅包含“group_id”=1 的数据,另一个仅包含“group_id”=2 的数据。
需要注意这一点,因为我们可以在示例数据帧上测试 .orderBy() 调用的效果,而不必真正担心窗口发生了什么。强调正在发生的事情:
- 数据按指定键分区
- 然后将转换应用于在每个窗口中创建的“迷你数据帧”
因此,对于预先排序的输入,例如:
df = spark.createDataFrame(
[
{'group_id': 1, 'id': 1, 'text': 'one', 'type': 'a'},
{'group_id': 1, 'id': 1, 'text': 'two', 'type': 't'},
{'group_id': 1, 'id': 2, 'text': 'three', 'type': 'a'},
{'group_id': 1, 'id': 2, 'text': 'four', 'type': 't'},
{'group_id': 1, 'id': 5, 'text': 'five', 'type': 'a'},
{'group_id': 1, 'id': 6, 'text': 'six', 'type': 't'},
{'group_id': 1, 'id': 7, 'text': 'seven', 'type': 'a'},
{'group_id': 1, 'id': 9, 'text': 'eight', 'type': 't'},
{'group_id': 1, 'id': 9, 'text': 'nine', 'type': 'a'},
{'group_id': 1, 'id': 10, 'text': 'ten', 'type': 't'},
{'group_id': 1, 'id': 11, 'text': 'eleven', 'type': 'a'}
]
)
+--------+---+------+----+
|group_id| id| text|type|
+--------+---+------+----+
| 1| 1| one| a|
| 1| 1| two| t|
| 1| 2| three| a|
| 1| 2| four| t|
| 1| 5| five| a|
| 1| 6| six| t|
| 1| 7| seven| a|
| 1| 9| eight| t|
| 1| 9| nine| a|
| 1| 10| ten| t|
| 1| 11|eleven| a|
+--------+---+------+----+
我们申请:
df.orderBy('id').show()
导致:
+--------+---+------+----+
|group_id| id| text|type|
+--------+---+------+----+
| 1| 1| one| a|
| 1| 1| two| t|
| 1| 2| three| a|
| 1| 2| four| t|
| 1| 5| five| a|
| 1| 6| six| t|
| 1| 7| seven| a|
| 1| 9| nine| a|
| 1| 9| eight| t|
| 1| 10| ten| t|
| 1| 11|eleven| a|
+--------+---+------+----+
起初,这看起来很稳定,但让我们将其应用于 DataFrame,其中 text="two" 的行与 text="three" 的行交换:
df = spark.createDataFrame(
[
{'group_id': 1, 'id': 1, 'text': 'one', 'type': 'a'},
{'group_id': 1, 'id': 2, 'text': 'three', 'type': 'a'},
{'group_id': 1, 'id': 1, 'text': 'two', 'type': 't'},
{'group_id': 1, 'id': 2, 'text': 'four', 'type': 't'},
{'group_id': 1, 'id': 5, 'text': 'five', 'type': 'a'},
{'group_id': 1, 'id': 6, 'text': 'six', 'type': 't'},
{'group_id': 1, 'id': 7, 'text': 'seven', 'type': 'a'},
{'group_id': 1, 'id': 9, 'text': 'eight', 'type': 't'},
{'group_id': 1, 'id': 9, 'text': 'nine', 'type': 'a'},
{'group_id': 1, 'id': 10, 'text': 'ten', 'type': 't'},
{'group_id': 1, 'id': 11, 'text': 'eleven', 'type': 'a'}
]
)
+--------+---+------+----+
|group_id| id| text|type|
+--------+---+------+----+
| 1| 1| one| a|
| 1| 2| three| a|
| 1| 1| two| t|
| 1| 2| four| t|
| 1| 5| five| a|
| 1| 6| six| t|
| 1| 7| seven| a|
| 1| 9| eight| t|
| 1| 9| nine| a|
| 1| 10| ten| t|
| 1| 11|eleven| a|
+--------+---+------+----+
然后申请:
df.orderBy(df.id).show()
结果:
+--------+---+------+----+
|group_id| id| text|type|
+--------+---+------+----+
| 1| 1| two| t|
| 1| 1| one| a|
| 1| 2| four| t|
| 1| 2| three| a|
| 1| 5| five| a|
| 1| 6| six| t|
| 1| 7| seven| a|
| 1| 9| nine| a|
| 1| 9| eight| t|
| 1| 10| ten| t|
| 1| 11|eleven| a|
+--------+---+------+----+
如您所见,即使行 text="one" 和 text="two" 以相同的顺序出现,.orderBy() 也会交换它们。因此,我们可以假设 .orderBy() 不是一个稳定的排序。