Apache spark 我怎样才能选择一个;“最佳匹配”;在Apache Spark中,在数据帧内聚合时?

Apache spark 我怎样才能选择一个;“最佳匹配”;在Apache Spark中,在数据帧内聚合时?,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,假设我在Spark数据框中有这些数据: Person Position ----------------- Tom Gold Tom Silver Tom Silver Dick Silver Dick Silver Dick null Harry Gold Harry Silver Alice Bronze Alice null Bob null Bob null 这就是我希望在输出中实现的

假设我在Spark数据框中有这些数据:

Person   Position
-----------------
Tom      Gold
Tom      Silver
Tom      Silver
Dick     Silver
Dick     Silver
Dick     null
Harry    Gold
Harry    Silver
Alice    Bronze
Alice    null
Bob      null
Bob      null
这就是我希望在输出中实现的目标:

Person   BestPosition
-----------------
Tom      Gold
Dick     Silver
Harry    Gold
Alice    Bronze
Bob      null
这不是真实的情况,但这是一个相当好的近似值。职位的排名顺序可以是硬编码的,也可以是配置驱动的,我不介意(在真实场景中只有3或4个,它们不会改变)

如果我在C#中这样做,我想它会像这样:

var data = new List<int>{}.Select(x => new { Name = "Tom",  Position = "Gold" },  ... etc);
var aggregation = data
    .GroupBy(scores => scores.Name)
    .Select(grouping => new {
        Name = grouping.Key,
        BestPosition = new [] {"Gold", "Silver", "Bronze"}.FirstOrDefault(x => grouping.Any(score => score.Position == x))
    })
    .ToList();
var data=newlist{}。选择(x=>new{Name=“Tom”,Position=“Gold”};
变量聚合=数据
.GroupBy(分数=>scores.Name)
.选择(分组=>新建){
Name=grouping.Key,
BestPosition=new[]{“Gold”、“Silver”、“brown”}.FirstOrDefault(x=>grouping.Any(score=>score.Position==x))
})
.ToList();
我正在Spark for.NET中编写我的应用程序(回想起来,这是一个错误的决定,我现在无法改变方向)。我很感激没有其他人在使用Spark for.NET,但我在这里遇到的问题更多的是概念而不是代码,所以如果有人能用Scala/Java/Python解决这个问题,我很肯定我能转换


我是Spark的新手,所以解决方案可能是显而易见的,但我不确定该怎么做。

PySpark sql解决方案。优先级列表可以在窗口函数的
order by
子句中设置,然后可以使用该子句为个人选择最佳行

from pyspark.sql.functions import row_number,when,col
from pyspark.sql import Window
w = Window.partitionBy(col('Person')).orderBy(when(col('Position') == 'Gold',1)
                                              .when(col('Position') == 'Silver',2)
                                              .when(col('Position') == 'Bronze',3)
                                              .otherwise(4)
                                             )
rnum_df = df.withColumn('rnum',row_number().over(w))
result = rnum_df.filter(col('rnum') == 1).select(df.columns)
result.show()

另一种使用
collect\u set
array\u的解决方案包含带有groupBy的

df.groupBy($"Person").agg(collect_set(col("Position")).alias("Position")) 
  .withColumn("Position", when(array_contains($"Position", "Gold"), "Gold") 
                          .when(array_contains($"Position", "Silver"), "Silver") 
                          .when(array_contains($"Position", "Bronze"), "Bronze")
             ) 
  .show()
给出:

+------+--------+
|Person|Position|
+------+--------+
|   Tom|    Gold|
|  Dick|  Silver|
|   Bob|    null|
| Alice|  Bronze|
| Harry|    Gold|
+------+--------+

谢谢,这是一种享受——我相信另一种解决方案可能也能很好地工作(谢谢Vamsi),但我还是选择了这一种,因为它更适合我已经准备好的代码,并且对我来说更具可读性。