一锥惋、初識Partitioner
? ? ? ? 在認(rèn)識Partitioner之前我們先來回顧一下MapReduce流程中,Map階段的五個步驟眶痰。如下圖所示:
? ? ? ? 我們可以通過上圖看到step1.3就是一個Partition操作。其主要作用是計算應(yīng)該將哪些Key放到同一個Reduce中去。其次從圖上我們可以得知Partition的操作是基于map的輸出結(jié)果的描馅,而且分區(qū)操作的對象是key。
? ? ? ? 接下來讓我們一起看看官方文檔對這個Partition的解讀吧而线。
? ? ? ? 該文檔主要描述了:Partition的主類名為Class Partitioner<KEY,VALUE>其直屬子類有BinaryPartitioner,?HashPartitioner,?KeyFieldBasedPartitioner,?TotalOrderPartitioner這幾個類铭污。
? ? ? ? 并且說明了Partitioner直接采用了map的輸出,其中分區(qū)的典型方式是使用hash函數(shù)進(jìn)行分區(qū)將key相同的數(shù)據(jù)分為一組膀篮。上述的其子類?HashPartitioner就實現(xiàn)了這個功能嘹狞。
/** 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與上最大整形呢?這是因為如果Key為Text的話筷屡,Text的hashcode方法跟String的基本一致涧偷,都是采用的Horner公式計算,得到一個int整數(shù)毙死。但是燎潮,如果string太大的話這個int整數(shù)值可能會溢出變成負(fù)數(shù),所以和整數(shù)的上限值Integer.MAX_VALUE(即0111111111111111)進(jìn)行與運算扼倘,然后再對reduce任務(wù)個數(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
如果需要將每年的最高氣溫找出,那我們就必然需要將氣溫數(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ù)的時候我們可以繼承不同的子類以方便我們運算。其子類用法請參考
總結(jié):分區(qū)Partitioner主要作用在于以下兩點
(1)根據(jù)業(yè)務(wù)需要秃症,產(chǎn)生多個輸出文件候址;
(2)多個reduce任務(wù)并發(fā)運行,提高整體job的運行效率种柑;
(3)好的Partition可以有效的避免數(shù)據(jù)傾斜岗仑;