Java Spark中如何按列唯一名称排序?求各流派评分最多用户实现
解决每个流派下评分次数最多用户的问题
我明白你的需求啦——要找出每个流派中评分次数最多的用户,而且同一个用户可以出现在多个流派的结果里对吧?你的现有代码确实没达到预期,因为它只是把所有(userId, genres)的组合按评分次数降序排列,但没有针对每个流派单独提取出次数最多的那个用户。
问题根源
你的代码:
Dataset<Row> group = exploded.groupBy("userId", "genres").count().orderBy(org.apache.spark.sql.functions.col("count").desc());
这段代码是把每个用户-流派组合的评分次数算出来后做了全局排序,但并没有按流派分组去筛选每个组内的Top1用户,所以你看到的结果是所有组合的排序,而不是每个流派各自的Top用户。
正确解决方案:用窗口函数实现分组取Top1
要实现需求,我们需要借助窗口函数(Window Function),按流派分组,在每个组内按评分次数降序排序,然后取每个组里排名第一的记录。具体步骤如下:
- 首先导入Spark窗口函数相关的类:
import org.apache.spark.sql.expressions.Window; import org.apache.spark.sql.functions;
- 定义窗口规范:按
genres分区(也就是每个流派作为一个独立的组),然后按count降序排序:
Window genreWindow = Window.partitionBy("genres") .orderBy(functions.col("count").desc());
- 基于分组统计的结果,添加排名列,再过滤出每个流派的Top1用户:
Dataset<Row> topUserPerGenre = exploded.groupBy("userId", "genres") .count() // 先统计每个用户在每个流派的评分次数 .withColumn("rank", functions.row_number().over(genreWindow)) // 给每个流派内的记录按次数排名 .filter(functions.col("rank").equalTo(1)) // 只保留每个流派排名第一的记录 .drop("rank") // 移除不需要的排名列 .orderBy("genres"); // 最后按流派排序,方便查看结果
额外细节:处理并列第一的情况
如果某个流派下有多个用户的评分次数相同(并列第一),上面的row_number()只会保留其中一个用户。如果你想保留所有并列第一的用户,可以把row_number()换成rank()或者dense_rank():
// 用rank()保留所有并列第一的用户 .withColumn("rank", functions.rank().over(genreWindow))
这样就能精准得到每个流派下评分次数最多的用户啦,同一个用户完全可以出现在多个流派的结果里哦!
内容的提问来源于stack exchange,提问作者A.Koparanski
相关产品推荐
相关产品推荐

