问题的提出
hive或者spark中collect_list一般是用来做分组后的合并,翻一下CSDN上的博客,大部分都是写了它和group by连用的情况,而几乎没有和partition by连用的情况,因此本篇特定来讲collect_list + partition by的这个用法。
会发现这个问题也算是一个巧合,它来源于业务上的一个问题:如何求一个用户的续课次数,续课金额?
假如给定这样一个场景:有严格规定的两个课程期次序列:s1,s2,s3,s4和p1,p2,p3,我们规定满足如下条件才算是一个用户的续课:
- 当课程属于同一课程序列时,必须遵循严格的期次顺序,且不得有重复。如 s1, s3, s4, s2,站在s1的角度看,续课了3次(s3,s4,s2);站在s3的角度看续课了1次(s4);
- 当课程属于不同的课程系列时,只要后面跟的是不同的课程序列都算1次,重复值不算。如s2,p2,p1,s2,站在s2的角度看,续费了2次(p2,p1);站在p2的角度看,续费了1次(s2)
解决思路
我们先来看一下这题的解决思路:
- 如果我们先不考虑减少数据量,那么对于用户参加的每一次的课程而言,附加一列生成一个这个用户的全量有序的购课记录就好,只是要记录一下对应的这门课在整个序列中的位置,然后后面的续课期次和续课金额的计算如果实在是不能用sql解决,放在spark rdd里面也是能解决的;
- 最好的方式肯定是对于每一个用户而言,附加一个该用户在这门课之后有序的选课记录,这里也有两种实现方式:1)自身关联这张购课表一次,找出每一个用户买了这门课之后的所有购课记录和购课金额;2)要是我们实在是不想自关联一次,那我们就要考虑一下如何用其他方式合理的解决这个问题(没想出来这种咋解决)
其实最早在处理的时候,使用collect_list + partition by 本来是想使用了第一种方法的(实在是不想搞自关联,觉得数据量有点太大了),但是没想到误打误撞发现了collect_list一个比较神奇的地方,下章说~
实际上如何解决
好,我们开始考虑如何用上面提出的第一种方案来解决这个问