这次用MapReduce计算模型做一个二次排序,发现一些问题,记录下来。
源文件数据格式如下:
id timestamp
10001 20170821115501
10001 20170821115502
10001 20170821115503
10002 20170821115504
10001 20170821115505
10001 20170821115506
10001 20170821115507
10002 20170821115508
10002 20170821115509
10002 20170821115510
10003 20170821115509
10003 20170821115508
10003 20170821115507
10003 20170821115506
10003 20170821115505
我们需要将每个用户(id)的时间戳进行排序。
一开始在我对MapReduce的理解上,直接弄个组合键 (id + timestamp)然后按照 时间戳全排序(timestamp),然后自定义分组组件(GroupingComparator)按照用户Id(id)进行分组,进入Reduce的时候,每组默认就是有序的了:
像这样:
1、2、3、4、5、6、7、8、9、10 (全排序)
假定2、4、7、10 为一组,这样取出来还是有序的(全局有序即局部有序),但是实际的结果却是不符合我的设想的,实际结果如下:
10001 20170821115501 20170821115501
10001 20170821115502 20170821115502
10001 20170821115503 20170821115503
I am a reduce ! I am a values ! (用字符串分隔表示一个组的结束)
10002 20170821115504 20170821115504
I am a reduce ! I am a values !
10003 20170821115505 20170821115505
I am a reduce ! I am a values !
10001 20170821115505 20170821115505
10001 20170821115506 20170821115506
I am a reduce ! I am a values !
10003 20170821115506 20170821115506
I am a reduce ! I am a values !
10001 20170821115507 20170821115507
I am a reduce ! I am a values !
10003 20170821115507 20170821115507
I am a reduce ! I am a values !
10002 20170821115508 20170821115508
I am a reduce ! I am a values !
10003 20170821115508 20170821115508
I am a reduce ! I am a values !
10002 20170821115509 20170821115509
I am a reduce ! I am a values !
10003 20170821115509 20170821115509
I am a reduce ! I am a values !
10002 20170821115510 20170821115510
I am a reduce ! I am a values !
查了很多资料才发现一个问题:Reduce的迭代器在分组的时候 不是全区扫描的,而是迭代器迭代下一个key,如果相同则放入迭代器缓存区中,然后迭代下一个,一旦发现不同的key则认为这一组结束。
所以我们在实现如上需求(二次排序)的时候,自定义组合键实现WritableComparable接口的时候记得将 组合键中第一个键也进行排序。
修改后排序的结果如下:
10001 20170821115501 20170821115501
10001 20170821115502 20170821115502
10001 20170821115503 20170821115503
10001 20170821115505 20170821115505
10001 20170821115506 20170821115506
10001 20170821115507 20170821115507
I am a reduce ! I am a values !
10002 20170821115504 20170821115504
10002 20170821115508 20170821115508
10002 20170821115509 20170821115509
10002 20170821115510 20170821115510
I am a reduce ! I am a values !
10003 20170821115505 20170821115505
10003 20170821115506 20170821115506
10003 20170821115507 20170821115507
10003 20170821115508 20170821115508
10003 20170821115509 20170821115509
备注:①、reduce阶段分组的时候不是全区扫描,而是遇到“相同” key放入迭代器,遇到“不同” key, 则结束这个分组。
②、Map的shuffle阶段,分完区(partitioner)后会进行一次key的排序;如果定义了SortComparatorClass,则按照该类的compare()方法进行排序,如果没有自定义SortComparatorClass,则按照Key的CompareTo()方法排序。