Python Pyspark-在多列上保留收集列表和收集集的顺序

Python Pyspark-在多列上保留收集列表和收集集的顺序,python,dataframe,apache-spark,pyspark,group-by,Python,Dataframe,Apache Spark,Pyspark,Group By,我有下面的pyspark数据框 Column_1 Column_2 Column_3 Column_4 1 A U1 12345 1 A A1 549BZ4G 预期产出: 第1列和第2列上的分组依据。收集集合第3列和第4列,同时保留输入数据帧中的顺序。它应该与输入的顺序相同。第3列和第4列之间的排序没有相关性。两者都必须保留输入数据帧顺序 Column_1 Column_2 Column_3 Column_4 1

我有下面的pyspark数据框

Column_1 Column_2 Column_3 Column_4
1        A        U1       12345
1        A        A1       549BZ4G
预期产出:

第1列和第2列上的分组依据。收集集合第3列和第4列,同时保留输入数据帧中的顺序。它应该与输入的顺序相同。第3列和第4列之间的排序没有相关性。两者都必须保留输入数据帧顺序

Column_1 Column_2 Column_3 Column_4
1        A        U1,A1    12345,549BZ4G
到目前为止,我尝试的是:

我第一次尝试使用窗口方法。其中,我按第1列和第2列划分,并按第1列和第2列排序。然后,我按照第1列和第2列进行分组,并在第3列和第4列进行收集

我没有得到预期的输出。我的结果如下

Column_1 Column_2 Column_3 Column_4
1        A        U1,A1    549BZ4G,12345
我还尝试使用单调递增的id创建一个索引,然后按索引排序,然后执行GROUPBY和collect集合以获得输出。但还是没有运气

它是由字母数字和数字值引起的吗?
如何保持第3列和第4列在输入中的顺序,而不改变顺序。

使用spark的
单向递增id
功能来维持顺序。您可以找到有关它的更多信息

使用
collect\u列表
顶部的
array\u distinct
来获得不同的值并维护顺序

    #InputDF
    # +----+----+----+-------+
    # |col1|col2|col3|   col4|
    # +----+----+----+-------+
    # |   1|   A|  U1|  12345|
    # |   1|   A|  A1|549BZ4G|
    # |   1|   A|  U1|123456 |
    # +----+----+----+-------+



    df1 = df.withColumn("id", F.monotonically_increasing_id()).groupby("Col1", "col2").agg(
        F.array_distinct(F.collect_list("col4")).alias("Col4"),F.array_distinct(F.collect_list("col3")).alias("Col3"))

    df1.select("col1", "col2", F.array_join("col3", ",").alias("col3"), F.array_join("col4", ",").alias("col4")).show(truncate=False)

    # +----+----+-----+---------------------+
    # |col1|col2|col3 |col4                 |
    # +----+----+-----+---------------------+
    # |1   |A   |U1,A1|12345,549BZ4G,123456 |
    # +----+----+-----+---------------------+

使用struct怎么样

val result = df.groupBy(
  "Column_1", "Column_2"
).agg(
  collect_list(
    struct(col("Column_3"), col("Column_4"))
  ).alias("coll")
).select(
  col("Column_1"), col("Column_2"), col("coll.Column_3"), col("coll.Column_4")
)
这应该会产生预期的结果。 诀窍是struct保留命名元素,以便您可以通过引用它们。存取器。它也适用于ArrayType(StructType)

通过struct对并置的概念进行分组感觉很自然,因为这是您试图在这里保留的结构关系

从理论上讲,您甚至可能不想解包结构,因为这些值似乎具有依赖性。

spark中的所有收集函数(collect\u set,collect\u list)都是不确定的,因为收集结果的顺序取决于底层数据帧中的行顺序,而底层数据帧又是不确定的

因此,总结一下,使用spark collect函数不能真正保持顺序


ref-

我不确定为什么它没有显示正确的结果,对我来说,这是按照预期的结果-

输入

df_a = spark.createDataFrame([(1,'A','U1','12345'),(1,'A','A1','549BZ4G')],[ "col_1","col_2","col_3","col_4"])
df_a.show()
+-----+-----+--------+----------------+
|col_1|col_2|   col_3|           col_4|
+-----+-----+--------+----------------+
|    1|    A|[U1, A1]|[12345, 549BZ4G]|
+-----+-----+--------+----------------+
逻辑

from pyspark.sql import functions as F
df_a = df_a.groupBy('col_1','col_2').agg(F.collect_list('col_3').alias('col_3'), F.collect_list('col_4').alias('col_4'))
输出

df_a = spark.createDataFrame([(1,'A','U1','12345'),(1,'A','A1','549BZ4G')],[ "col_1","col_2","col_3","col_4"])
df_a.show()
+-----+-----+--------+----------------+
|col_1|col_2|   col_3|           col_4|
+-----+-----+--------+----------------+
|    1|    A|[U1, A1]|[12345, 549BZ4G]|
+-----+-----+--------+----------------+

我尝试使用单调递增的id。我尝试使用collect set而不是collect list,因为我希望只保留不同的值,并且我没有得到column4的预期输出。您是否尝试使用collect set,但仍然获得了预期的输出?collect_set正在更改您提到的顺序。我更新了代码,在
collect\u列表
的顶部使用了
array\u distinct
。这可能是collect_集合的一个解决方法。希望能有帮助。谢谢你@Loka。我会尝试一下并更新youThank you@milos。我会试试这个