分區操作
為什么要分區?
要求將統計結果按照條件輸出到不同文件中(分區)。比如:將統計結果按
照手機歸屬地不同省份輸出到不同文件中(分區)
默認 partition 分區
/**
源碼中:numReduceTasks如果等於1 不會走getPartition方法
numReduceTasks:默認是1
*/
public class HashPartitioner<K, V> extends Partitioner<K, V> {
public int getPartition(K key, V value, int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
默認分區是根據 key 的 hashCode 對 reduceTasks 個數取模得到的。
用戶沒法控制哪個key 存儲到哪個分區
自定義Partition
(1)自定義類繼承 Partitioner,重寫 getPartition()方法
/**
該方法返回不同的partition的值,從而就控制了分區個數、前提是numReduceTasks不等於1
KV:是Map的輸出
*/
public class ProvincePartitioner extends Partitioner<Text, FlowBean> {
@Override
public int getPartition(Text key, FlowBean value, int numPartitions) {
// 1 獲取電話號碼的前三位
String preNum = key.toString().substring(0, 3);
int partition = 4;
// 2 判斷是哪個省
if ("136".equals(preNum)) {
partition = 0;
}else if ("137".equals(preNum)) {
partition = 1;
}else if ("138".equals(preNum)) {
partition = 2;
}else if ("139".equals(preNum)) {
partition = 3;
}
return partition;
}
}
(2)在Runner類中設置partition
job.setPartitionerClass(CustomPartitioner.class);
(3)自定義 partition 后,要根據自定義 partitioner 的邏輯設置相應數量的 reduce task
job.setNumReduceTasks(5);
(4)注意:
如果 reduceTask 的數量 > getPartition 的結果數,則會多產生幾個空的輸出文件part-r-000xx;
如果 1 < reduceTask的數量 < getPartition 的結果數,則有一部分分區數據無處安放,會Exception;
如果 reduceTask 的數量 = 1,則不管 mapTask 端輸出多少個分區文件,最終結果都交給這一個 reduceTask,
最終也就只會產生一個結果文件 part-r-00000;
例如:假設自定義分區數為 5,則
(1)job.setNumReduceTasks(1);會正常運行,只不過會產生一個輸出文件
(2)job.setNumReduceTasks(2);會報錯
(3)job.setNumReduceTasks(6);大於 5,程序會正常運行,會產生空文件
本博客僅為博主學習總結,感謝各大網絡平台的資料。蟹蟹!!