【问题标题】:Pyspark Window orderByPyspark 窗口 orderBy
【发布时间】:2018-10-15 15:13:11
【问题描述】:

我有一个看起来像

的数据框
+--------+---+------+----+
|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|
+--------+---+------+----+

如果我通过在 group_id 上对其进行分区并按 id 对其进行排序来执行 Window 操作,那么 orderby 是否会确保已排序(排序)的行保持相同的顺序?

例如

window_spec = Window.partitionBy(df.group_id).orderBy(df.id)
df = df.withColumn("row_number", row_number().over(window_spec))

永远都是

+--------+---+------+----+------+                                               
|group_id| id|  text|type|row_number|
+--------+---+------+----+------+
|       1|  1|   one|   a|     1|
|       1|  1|   two|   t|     2|
|       1|  2| three|   a|     3|
|       1|  2|  four|   t|     4|
|       1|  5|  five|   a|     5|
|       1|  6|   six|   t|     6|
|       1|  7| seven|   a|     7|
|       1|  9| eight|   t|     8|
|       1|  9|  nine|   a|     9|
|       1| 10|   ten|   t|    10|
|       1| 11|eleven|   a|    11|
+--------+---+------+----+------+

简而言之,我的问题是,spark Window 的 orderBy 如何处理已排序(排序)的行?我的假设是它是稳定的,即它不会更改已排序行的顺序,但我在文档中找不到与此相关的任何内容。我怎样才能确保我的假设是正确的?

谢谢。

【问题讨论】:

  • 我没有任何文档,但我认为您不能假设这些行将保持任何预先存在的顺序。它可能在一些小例子中起作用,但对于更大的数据,你可能会遇到麻烦。在这些情况下,最好是明确的。

标签: apache-spark pyspark apache-spark-sql pyspark-sql


【解决方案1】:

首先,为那些可能不知道稳定排序定义的阅读者设置上下文,我将引用此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() 调用的效果,而不必真正担心窗口发生了什么。强调正在发生的事情:

  1. 数据按指定键分区
  2. 然后将转换应用于在每个窗口中创建的“迷你数据帧”

因此,对于预先排序的输入,例如:

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() 不是一个稳定的排序。

【讨论】:

  • 感谢您的回答。你是对的,订单不一样,所以 orderBy 不稳定,但它并不总是正确的。根据我的研究,orderBy 可以是稳定的,也可以不是稳定的。在某些情况下它会稳定,而在其他情况下则不会。所以行为是不确定的。
猜你喜欢
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 2019-08-16
  • 2019-09-21
  • 2018-03-14
  • 2018-08-27
相关资源
最近更新 更多