困扰了自己1周的一个问题终于得到解决了,感谢给我帮助的同学,同时记录下来分享给大家.
问题简化描述:
- HDFS存在这样格式的文件:用户ID 主题ID 用户对此主题的偏好分数score。
- 现在要求实现对给定的几个主题T1,T2,T3,...TN,每个主题要求筛选出指定数量的用户ID是M1,M2,M3,...MX。
- 希望尽可能根据score来选出偏好的用户ID,并且主题之间的用户ID不可以重复。
- 另外HDFS上distinct的用户ID数量是大于等于M1+M2+M3+...+MX的。
思路分析:
问题有几个关键点,第一,不重复,第二,数量上要满足,第三,偏好分数score。
如何保证,主题之间的用户不重复呢?
其实就是完成,一个用户只能属于一个主题的过程,当然,我们可以很简单的对一个用户下的所有偏好分数进行排序,取出最偏好的主题。
虽然这样避免了重复的问题,可是问题来了,如果偏好主题T1要求的数量是100W,而仅仅只有90W的用户ID对T1最偏好,这该如何补数呢?又如何通过程序来自动化的实现这个过程呢?越想越复杂!
这个问题好像有点类似于高考填自愿的问题,我们每一个人会填写几个志愿,但是我们终究只会被一个院校录取,这是怎么做到的呢?是否可以从中借鉴呢?
首先,我们根据HDFS的内容,写一个MapReduce完成一次计算,形成下面的用户志愿HDFS内容:
用户ID 主题ID-A:score1;主题ID-B:score2;...
很简单,希望得到一个用户ID下面按照score desc排序的主题列表,上面一行其实就是说:
用户ID的第一志愿是主题A,第二志愿是主题B...。
------------------------------------------
接下来,形成下面的一个列表list信息:
主题A count-A
主题B count-B
主题C count-C
...
按照主题需要的用户ID的数量进行ASC排序。
------------------------------------------
下面,我们就来看如何进行主题选择用户的过程:
我们首先选择对数量要求最少的主题A完成下面的MapReduce计算:
这样,我们就完成了主题A的用户筛选问题。
接下来,我们取出list中数量要求比A多一点的主题B,那么它怎么取用户呢?
很简单,我们只需要在MAP处理阶段,传递主题A生成的结果HDFS路径(路径下面的文件内容当然是主题A的用户)用于reduce阶段取用户时进行过滤。
那么,主题C又如何取用户呢?
类似的,只需要给MAP多传递主题A,主题B已经占用的用户信息用于过滤,其他处理操作不变!
其实,我们可以发现,上面的MapReduce其实可以是一个通用的程序,类似于COMMAND:
hadoop jar XXX.jar 主题ID 数量 [input1,input2,input3,...] 用户志愿HDFS路径 输出路径
其中input1,input2,input3,...是可选的,其实就是用于用户过滤的。
最后,我们可以写一个Shell脚本,根据list的内容来进行重复调用上面的COMMAND,通过传递不同的参数信息达到目的,这样我们就可以自动化实现上面的要求了!