Apache spark 在Spark数据帧中查找每组的最大行数

Apache spark 在Spark数据帧中查找每组的最大行数,apache-spark,pyspark,apache-spark-sql,Apache Spark,Pyspark,Apache Spark Sql,我尝试使用Spark数据帧而不是RDD,因为它们看起来比RDD更高级,并且倾向于生成更可读的代码 在一个14节点的GoogleDataProc集群中,我有大约600万个名字被两个不同的系统翻译成ID:sa和sb。每个行包含名称、id\u sa和id\u sb。我的目标是生成从id\u sa到id\u sb的映射,这样对于每个id\u sa,相应的id\u sb是附加到id\u sa的所有名称中最常见的id 让我们试着用一个例子来说明。如果我有以下行: [Row(name='n1', id_sa=

我尝试使用Spark数据帧而不是RDD,因为它们看起来比RDD更高级,并且倾向于生成更可读的代码

在一个14节点的GoogleDataProc集群中,我有大约600万个名字被两个不同的系统翻译成ID:
sa
sb
。每个
包含
名称
id\u sa
id\u sb
。我的目标是生成从
id\u sa
id\u sb
的映射,这样对于每个
id\u sa
,相应的
id\u sb
是附加到
id\u sa
的所有名称中最常见的id

让我们试着用一个例子来说明。如果我有以下行:

[Row(name='n1', id_sa='a1', id_sb='b1'),
 Row(name='n2', id_sa='a1', id_sb='b2'),
 Row(name='n3', id_sa='a1', id_sb='b2'),
 Row(name='n4', id_sa='a2', id_sb='b2')]
[Row(id_sa=a1, max_id_sb=b2),
 Row(id_sa=a2, max_id_sb=b2)]
我的目标是生成从
a1
b2
的映射。实际上,与
a1
相关联的名称是
n1
n2
n3
,它们分别映射到
b1
b2
b2
,因此
b2
是与
a1
相关联的名称中最常见的映射。同样,
a2
将映射到
b2
。可以假设总会有一个赢家:不必打破僵局

我希望能在我的数据帧上使用
groupBy(df.id_sa)
,但我不知道下一步该怎么做。我希望聚合最终能够产生以下行:

[Row(name='n1', id_sa='a1', id_sb='b1'),
 Row(name='n2', id_sa='a1', id_sb='b2'),
 Row(name='n3', id_sa='a1', id_sb='b2'),
 Row(name='n4', id_sa='a2', id_sb='b2')]
[Row(id_sa=a1, max_id_sb=b2),
 Row(id_sa=a2, max_id_sb=b2)]
但也许我尝试使用了错误的工具,我应该回到使用RDD。

使用
join
(这将导致在组中出现多行,以防出现结):

使用窗口功能(将断开连接):

使用
struct
排序:

from pyspark.sql.functions import struct

(cnts
  .groupBy("id_sa")
  .agg(F.max(struct(col("cnt"), col("id_sb"))).alias("max"))
  .select(col("id_sa"), col("max.id_sb")))

另请参见

我认为您可能需要的是窗口功能:

下面是Scala中的一个示例(我现在没有带配置单元的Spark Shell,所以我无法测试代码,但我认为它应该可以工作):

使用窗口函数可能有更有效的方法来实现相同的结果,但我希望这为您指明了正确的方向

case class MyRow(name: String, id_sa: String, id_sb: String)

val myDF = sc.parallelize(Array(
    MyRow("n1", "a1", "b1"),
    MyRow("n2", "a1", "b2"),
    MyRow("n3", "a1", "b2"),
    MyRow("n1", "a2", "b2")
)).toDF("name", "id_sa", "id_sb")

import org.apache.spark.sql.expressions.Window

val windowSpec = Window.partitionBy(myDF("id_sa")).orderBy(myDF("id_sb").desc)

myDF.withColumn("max_id_b", first(myDF("id_sb")).over(windowSpec).as("max_id_sb")).filter("id_sb = max_id_sb")