hadoop的使用中,一般只关注运行结果。对于mapper和reducer之间的处理逻辑往往不care。比如key-value对到达reducer的先后顺序等
目前接触到的运用场景有:
1.根据用户操作时间来整理事件链,在网站分析里比较常用。需要按时间先后顺序来处理,如果过亿的访问操作全在reducer里来排序,对计算能力和内存都是一个挑战。
2.海量数据处理中,求去重distinct这种操作,往往需要先缓存很大的数据集,对单个reducer的内存要求很高,特别是上亿的数据时,很容易就撑爆内存。这里如果在reducer进入前就排好序,后续处理就简单的多。
二次排序相当于把一个reducer的负载推给了多个maper。
例子:如果我们要将日志按用户的访问时间排序。
1.map阶段输出key-value对:key是 : uid,sid,time value是url,time
2.进入二次排序。
3.进入reducer的key-valuelist:key是: uid,sid valuelist是: [{url1,time2},{url,time2},……]
其中valuelist是按time来排序的。
这里说下阶段2,以下三个都是可以由用户定义的:
1.partition: 简单粗暴的解释就记录即将进入的reducer实例的ID
2.group: 群组,一个事件链表。所以群组里的记录会比较时间,而群组间则不会。
3.key map输出的key
你要写这三个类,hadoop会调用这几个函数来比较。你可以自己定义比较的逻辑,是字典排序还是数字排序,是从大到小,还是从小到大。 具体实现可以看hadoop权威指南。
需要强调的是:
1. 一个群组会在一个reduce函数里被处理。
例 如:
在配置里指定30个reducer ,日志里根据uidsid会有100个group 。平均1个reducer进程会调多次次reduce函数,处理多个group。所以每次处理一个group后,相关变量要清理。
2.进入reducer时候,key是group里定义的key ,已经不是map输出的那个key了,被丢弃了。
所以时间要放到value里传递进来。