今天题发现一个有趣的题目:找到一个班级里成绩排名,并算出每个人的前1名和前2名作为超越的对手,如果没有前1名,则找前2名和前3名。例如:有两个第八名,则没有第九名,第十名的前一名是第八名,第十名的前2名是第七名
需要获取到每个人的排名以及他所在前1名同学和前2名同学的姓名,目标结果如下所示。
首先给每位同学成绩进行排名,分为跳跃排名和不跳跃排名。实际业务中,前1名和前2名是自己下次考试的超越对手。其中跳跃排名是正常使用的排名,而不跳跃排名是为了进行关联而使用的关联条件。
然后进行两次自关联,分别找到每一位同学的前1名和前2名,由于存在排名并列的情况,join后势必存在数据膨胀,也就是说前1名可能是多位同学,这里使用collect_list函数对结果进行收敛。
不难看出最后三位同学{郑水,孙见,赵君}的数据是有问题的,前1、2名数据有重复,为什么呢?
经过测试,实际上单独找前1名或者前2名使用collect_list都没有重复,如果找前1名和前2名放在一起会产生重复,因为collect相当于省略了group by操作,对膨胀的数据进行聚合(列转行),在第一次join中已经出现了数据膨胀,第二次join会加剧数据膨胀,而collect_list是在所有join完成之后,对重复的数据仅进行一次收敛。所以使用collect_set才会符合预期要求。