一、初識Partitioner
? ? ? ? 在認(rèn)識Partitioner之前我們先來回顧一下MapReduce流程中,Map階段的五個(gè)步驟。如下圖所示:

? ? ? ? 我們可以通過上圖看到step1.3就是一個(gè)Partition操作。其主要作用是計(jì)算應(yīng)該將哪些Key放到同一個(gè)Reduce中去。其次從圖上我們可以得知Partition的操作是基于map的輸出結(jié)果的,而且分區(qū)操作的對象是key。
? ? ? ? 接下來讓我們一起看看官方文檔對這個(gè)Partition的解讀吧。

? ? ? ? 該文檔主要描述了:Partition的主類名為Class Partitioner<KEY,VALUE>其直屬子類有BinaryPartitioner,?HashPartitioner,?KeyFieldBasedPartitioner,?TotalOrderPartitioner這幾個(gè)類。
? ? ? ? 并且說明了Partitioner直接采用了map的輸出,其中分區(qū)的典型方式是使用hash函數(shù)進(jìn)行分區(qū)將key相同的數(shù)據(jù)分為一組。上述的其子類?HashPartitioner就實(shí)現(xiàn)了這個(gè)功能。
/** Partition keys by their {@link Object#hashCode()}. */
public class HashPartitioner<K, V> extends Partitioner<K, V> {
/** Use {@link Object#hashCode()} to partition. */
public int getPartition(K key, V value, int numReduceTasks){
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}//其中key和value為map輸出,numReduceTasks是reduce的數(shù)量。
? ? ? ? 我們可以看到上面的代碼中最關(guān)鍵的一行為:key.hashCode() & Integer.MAX_VALUE) % numReduceTasks。那么為什么要用hashcode與上最大整形呢?這是因?yàn)槿绻鸎ey為Text的話,Text的hashcode方法跟String的基本一致,都是采用的Horner公式計(jì)算,得到一個(gè)int整數(shù)。但是,如果string太大的話這個(gè)int整數(shù)值可能會溢出變成負(fù)數(shù),所以和整數(shù)的上限值Integer.MAX_VALUE(即0111111111111111)進(jìn)行與運(yùn)算,然后再對reduce任務(wù)個(gè)數(shù)取余,這樣就可以讓key均勻分布在reduce上。?
二、自定義Partitioner
現(xiàn)在我們有一下天氣數(shù)據(jù),我們需要按要求將每年的最高氣溫找出來。
1949-10-01 14:21:02 34C
1949-10-02 14:21:12 36C
1950-02-02 11:21:12 32C
1950-05-02 11:31:12 37C
1951-12-02 11:31:12 23C
1950-12-02 11:31:12 47C
1950-12-02 11:31:12 27C
1951-06-02 11:31:12 48C
1951-07-02 11:31:12 45C
如果需要將每年的最高氣溫找出,那我們就必然需要將氣溫?cái)?shù)據(jù)按年分組。
public class wdPartitioner extends Partitioner<Text, Text>{
@Override public int getPartition(Text key, Text value, int numReduceTasks) {
?String str = key.toString().split("-")[0];
int num = Integer.parseInt(str);
if(num == 1949){ return 1%numReduceTasks; }
else if(num == 1950) { return 2%numReduceTasks; }
else if(num == 1951){ return 3%numReduceTasks; }
return 1%numReduceTasks; }
}
可以看到這里由于年份只有這三年所以就按照年份來進(jìn)行判斷了,如果年份較多需要分成很多組那么就可以寫成return (num.hashCode() & Integer.MAX_VALUE) % numReduceTasks;在處理不同的數(shù)據(jù)的時(shí)候我們可以繼承不同的子類以方便我們運(yùn)算。其子類用法請參考
總結(jié):分區(qū)Partitioner主要作用在于以下兩點(diǎn)
(1)根據(jù)業(yè)務(wù)需要,產(chǎn)生多個(gè)輸出文件;
(2)多個(gè)reduce任務(wù)并發(fā)運(yùn)行,提高整體job的運(yùn)行效率;
(3)好的Partition可以有效的避免數(shù)據(jù)傾斜;