一個MapReduce 程式示例 細節決定成敗(五) :Partitioner
上一個博文中,我們分別介紹了使用combiner 和in-map 聚合 來優化 map reduce job。
這一篇中,繼續優化這個統計字元數量的mr 程式。
再次介紹下map reduce程式的目標: 統計輸入檔案中 a~z 字元分別有多少個。 A 與 a 都統計到 a 中。
先看一下上次執行的Job Counters 計數,可以看到Reducer Task的個數為1.
知識點:MR Job 預設的reducer 個數為1. reducer的個數可以通過job.setNumReducerTasks(num) 來進行設定。
留個問題:那map 任務的個數怎麼設定?
假如資料量很大時, 一個reducer task 可能成為任務的bottle neck。 那我們手工設定一下reducer 個數。
編譯後再次執行檢視日誌 可以看到 reducer的個數是3,符合我們的預期。但問題還沒有完!
下面看一下輸出,有三個輸出檔案,正常,一個reducer 對應一個輸出檔案。
我們看一下結果檔案中的內容
發現三個檔案中沒有按順序輸出,現在我們想要的是a~h 放到一個檔案中,i~q 放到第二個檔案中、r~z 放到第三個檔案中。我們應該怎麼辦?
這就要用到我們本次將要介紹的利器: Partitioner 。
Partition 就是用來決定map的輸出會輸送到哪兒個reducer中。當只有一個reducer 時,不會呼叫Partitioner,即使配置了也不會呼叫。
hadoop 框架中預設的Partitioner 是HashPartitioner。 它是根據key的hash值對reducer個數取餘進行分配的。
說明一下:返回0即本記錄將發往第一個reducer,返回1則本記錄發往第二個reducer.依次類推。
那接下來我們要定義自己的一個Partitioner ,它要按照我們預定的a~h 發往第一個reducer,i~q 發往第二個reducer、r~z發往第三個reducer。
執行檢視結果,可見實現了我們的預期。
下面照例把整個程式碼貼上
最後再嘮叨兩句: 一般情況要,自定義partitioner 是為了解決資料分佈不均的情況,又叫資料傾斜。 而且自定義的partitioner 要保證,相同的key要發往相同的reducer。
這一篇中,繼續優化這個統計字元數量的mr 程式。
再次介紹下map reduce程式的目標: 統計輸入檔案中 a~z 字元分別有多少個。 A 與 a 都統計到 a 中。
先看一下上次執行的Job Counters 計數,可以看到Reducer Task的個數為1.
點選(此處)摺疊或開啟
- Job Counters
-
Launched map tasks=3
-
Launched reduce tasks=1
-
Data-local map tasks=3
-
Total time spent by all maps in occupied slots (ms)=1207744
-
Total time spent by all reduces in occupied slots (ms)=341424
-
留個問題:那map 任務的個數怎麼設定?
假如資料量很大時, 一個reducer task 可能成為任務的bottle neck。 那我們手工設定一下reducer 個數。
點選(此處)摺疊或開啟
-
@Override
-
public int run(String[] args) throws Exception {
-
//valid the parameters
-
if(args.length !=2){
-
return -1;
-
}
-
-
Job job = Job.getInstance(getConf(), "MyWordCountJob");
-
job.setJarByClass(MyWordCountJob.class);
-
-
Path inPath = new Path(args[0]);
-
Path outPath = new Path(args[1]);
-
-
outPath.getFileSystem(getConf()).delete(outPath,true);
-
TextInputFormat.setInputPaths(job, inPath);
-
TextOutputFormat.setOutputPath(job, outPath);
-
-
-
job.setMapperClass(MyWordCountJob.MyWordCountMapper.class);
-
job.setReducerClass(MyWordCountJob.MyWordCountReducer.class);
-
job.setInputFormatClass(TextInputFormat.class);
-
job.setOutputFormatClass(TextOutputFormat.class);
-
-
job.setMapOutputKeyClass(Text.class);
-
job.setMapOutputValueClass(IntWritable.class);
-
job.setOutputKeyClass(Text.class);
-
job.setOutputValueClass(IntWritable.class);
-
-
job.setNumReduceTasks(3);
-
return job.waitForCompletion(true)?0:1;
- }
點選(此處)摺疊或開啟
-
File System Counters
-
FILE: Number of bytes read=642
-
FILE: Number of bytes written=507033
-
FILE: Number of read operations=0
-
FILE: Number of large read operations=0
-
FILE: Number of write operations=0
-
HDFS: Number of bytes read=556
-
HDFS: Number of bytes written=107
-
HDFS: Number of read operations=18
-
HDFS: Number of large read operations=0
-
HDFS: Number of write operations=6
-
Job Counters
-
Launched map tasks=3
-
Launched reduce tasks=3
-
Data-local map tasks=3
-
Total time spent by all maps in occupied slots (ms)=1207744
-
Total time spent by all reduces in occupied slots (ms)=341424
-
Map-Reduce Framework
-
Map input records=8
-
Map output records=78
-
Map output bytes=468
-
Map output materialized bytes=678
-
Input split bytes=399
-
Combine input records=0
-
Combine output records=0
-
Reduce input groups=26
-
Reduce shuffle bytes=678
-
Reduce input records=78
-
Reduce output records=26
-
Spilled Records=156
-
Shuffled Maps =9
-
Failed Shuffles=0
-
Merged Map outputs=9
-
GC time elapsed (ms)=507
-
CPU time spent (ms)=7770
-
Physical memory (bytes) snapshot=1329672192
-
Virtual memory (bytes) snapshot=5978918912
- Total committed heap usage (bytes)=1004273664
下面看一下輸出,有三個輸出檔案,正常,一個reducer 對應一個輸出檔案。
點選(此處)摺疊或開啟
-
[train@sandbox MyWordCount]$ hdfs dfs -ls output
-
Found 4 items
-
-rw-r--r-- 3 train hdfs 0 2016-05-11 11:48 output/_SUCCESS
-
-rw-r--r-- 3 train hdfs 37 2016-05-11 11:48 output/part-r-00000
-
-rw-r--r-- 3 train hdfs 34 2016-05-11 11:48 output/part-r-00001
- -rw-r--r-- 3 train hdfs 36 2016-05-11 11:48 output/part-r-00002
我們看一下結果檔案中的內容
點選(此處)摺疊或開啟
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00000
-
b 3
-
e 11
-
h 8
-
k 3
-
n 4
-
q 3
-
t 4
-
w 7
-
z 3
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00001
-
c 4
-
f 4
-
i 5
-
l 6
-
o 12
-
r 13
-
u 6
-
x 3
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00002
-
a 8
-
d 4
-
g 3
-
j 3
-
m 7
-
p 3
-
s 4
-
v 0
- y 6
這就要用到我們本次將要介紹的利器: Partitioner 。
Partition 就是用來決定map的輸出會輸送到哪兒個reducer中。當只有一個reducer 時,不會呼叫Partitioner,即使配置了也不會呼叫。
hadoop 框架中預設的Partitioner 是HashPartitioner。 它是根據key的hash值對reducer個數取餘進行分配的。
說明一下:返回0即本記錄將發往第一個reducer,返回1則本記錄發往第二個reducer.依次類推。
點選(此處)摺疊或開啟
-
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;
-
}
- }
點選(此處)摺疊或開啟
-
public static class MyWordCountPartitioner extends Partitioner<Text,IntWritable>{
-
-
@Override
-
public int getPartition(Text key, IntWritable value, int numPartitions) {
-
char c =key.toString().charAt(0);
-
if(c>='a'&& c<'i')
-
return 0;
-
else if(c>='i' && c<'q')
-
return 1;
-
else
-
return 2;
-
}
-
- }
點選(此處)摺疊或開啟
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00000
-
a 8
-
b 3
-
c 4
-
d 4
-
e 11
-
f 4
-
g 3
-
h 8
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00001
-
i 5
-
j 3
-
k 3
-
l 6
-
m 7
-
n 4
-
o 12
-
p 3
-
[train@sandbox MyWordCount]$ hdfs dfs -cat output/part-r-00002
-
q 3
-
r 13
-
s 4
-
t 4
-
u 6
-
v 0
-
w 7
-
x 3
-
y 6
- z 3
點選(此處)摺疊或開啟
-
package wordcount;
-
-
import java.io.IOException;
-
import java.util.HashMap;
-
import java.util.Map;
-
-
import org.apache.hadoop.conf.Configuration;
-
import org.apache.hadoop.conf.Configured;
-
import org.apache.hadoop.fs.Path;
-
import org.apache.hadoop.io.IntWritable;
-
import org.apache.hadoop.io.LongWritable;
-
import org.apache.hadoop.io.Text;
-
import org.apache.hadoop.mapreduce.Job;
-
import org.apache.hadoop.mapreduce.Mapper;
-
import org.apache.hadoop.mapreduce.Partitioner;
-
import org.apache.hadoop.mapreduce.Reducer;
-
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
-
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
-
import org.apache.hadoop.util.Tool;
-
import org.apache.hadoop.util.ToolRunner;
-
import org.apache.log4j.Logger;
-
-
public class MyWordCountJob extends Configured implements Tool {
-
Logger log = Logger.getLogger(MyWordCountJob.class);
-
-
public static class MyWordCountMapper extends
-
Mapper<LongWritable, Text, Text, IntWritable> {
-
Logger log = Logger.getLogger(MyWordCountJob.class);
-
Map<Character,Integer> map = new HashMap<Character,Integer>();
-
-
Text mapKey = new Text();
-
IntWritable mapValue = new IntWritable(1);
-
@Override
-
protected void map(LongWritable key, Text value, Context context)
-
throws IOException, InterruptedException {
-
for(char c :value.toString().toLowerCase().toCharArray()){
-
if(c>='a' && c <='z'){
-
map.put(c,map.get(c)+1);
-
}
-
}
-
}
-
-
@Override
-
protected void cleanup(Context context) throws IOException,
-
InterruptedException {
-
for(char key : map.keySet()){
-
mapKey.set(String.valueOf(key));
-
mapValue.set(map.get(key));
-
context.write(mapKey, mapValue);
-
}
-
-
}
-
-
@Override
-
protected void setup(Context context) throws IOException,
-
InterruptedException {
-
for(char c='a';c<='z' ;c++){
-
map.put(c, 0);
-
}
-
}
-
-
}
-
-
public class MyWordCountPartitioner extends Partitioner<Text,IntWritable>{
-
-
@Override
-
public int getPartition(Text key, IntWritable value, int numPartitions) {
-
char c =key.toString().charAt(0);
-
if(c>='a'&& c<'i')
-
return 0;
-
else if(c>='i' && c<'q')
-
return 1;
-
else
-
return 2;
-
}
-
-
}
-
-
public static class MyWordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
-
Text rkey = new Text();
-
IntWritable rvalue = new IntWritable(1);
-
@Override
-
protected void reduce(Text key, Iterable<IntWritable> values,Context context)
-
throws IOException, InterruptedException {
-
int n=0;
-
for(IntWritable value :values){
-
n+= value.get();
-
}
-
rvalue.set(n);
-
context.write(key, rvalue);
-
}
-
}
-
-
@Override
-
public int run(String[] args) throws Exception {
-
//valid the parameters
-
if(args.length !=2){
-
return -1;
-
}
-
-
Job job = Job.getInstance(getConf(), "MyWordCountJob");
-
job.setJarByClass(MyWordCountJob.class);
-
-
Path inPath = new Path(args[0]);
-
Path outPath = new Path(args[1]);
-
-
outPath.getFileSystem(getConf()).delete(outPath,true);
-
TextInputFormat.setInputPaths(job, inPath);
-
TextOutputFormat.setOutputPath(job, outPath);
-
-
-
job.setMapperClass(MyWordCountJob.MyWordCountMapper.class);
-
job.setReducerClass(MyWordCountJob.MyWordCountReducer.class);
-
job.setPartitionerClass(MyWordCountPartitioner.class);
-
job.setInputFormatClass(TextInputFormat.class);
-
job.setOutputFormatClass(TextOutputFormat.class);
-
job.setMapOutputKeyClass(Text.class);
-
job.setMapOutputValueClass(IntWritable.class);
-
job.setOutputKeyClass(Text.class);
-
job.setOutputValueClass(IntWritable.class);
-
-
job.setNumReduceTasks(3);
-
return job.waitForCompletion(true)?0:1;
-
}
-
public static void main(String [] args){
-
int result = 0;
-
try {
-
result = ToolRunner.run(new Configuration(), new MyWordCountJob(), args);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
System.exit(result);
-
}
-
- }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30066956/viewspace-2108214/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一個MapReduce 程式示例 細節決定成敗(一)
- 一個MapReduce 程式示例 細節決定成敗(九):RawComparator
- 一個MapReduce 程式示例 細節決定成敗(八):TotalOrderPartitioner
- 一個MapReduce 程式示例 細節決定成敗(六) :CombineFileInputFormatORM
- 一個MapReduce 程式示例 細節決定成敗(三) :Combiner
- 一個MapReduce 程式示例 細節決定成敗(二) :觀察日誌及 Counter
- 一個MapReduce 程式示例 細節決定成敗(七) :自定義Key 及RecordReader
- 第五章 Vlookup函式示例-細節決定成敗函式
- 細節決定成敗 MapReduce任務實戰 Map Join
- 細節決定成敗 MapReduce任務實戰 Reduce Join
- 細節決定成敗 MapReduce任務實戰 倒排索引索引
- 細節決定成敗!APP設計不容忽視的20個細節APP
- 如何讓程式設計師幸福工作:細節決定成敗程式設計師
- 面試:黃金法則——細節決定成敗面試
- Java集合詳解8:Java集合類細節精講,細節決定成敗Java
- 開發者談F2P模式:細節決定成敗模式
- 邦芒簡歷:求職簡歷細節決定成敗求職
- Python讀書筆記:細節決定成敗(2)Python筆記
- Python讀書筆記:細節決定成敗(1)Python筆記
- 汪峰FIIL Diva智慧耳機究竟如何?細節決定成敗
- 細節決定ERP專案啟動會的成敗
- 細節決定成敗,不容忽視的10道Node面試題面試題
- 細節決定成敗——無CSS時網頁的可讀性CSS網頁
- 軟體設計是怎樣煉成的(7)——細節決定成敗(詳細設計)
- MapReduce之自定義partitioner
- MapReduce框架Partitioner分割槽方法框架
- 【原創】構建高效能ASP.NET站點之三 細節決定成敗ASP.NET
- MapReduce之自定義分割槽器Partitioner
- 一個簡單的MapReduce示例(多個MapReduce任務處理)
- 【2024-03-06】細節成敗
- 決定開發者面試成敗的 3 個問題面試
- AutoCAD 2024:細節決定成敗,精準設計從這裡開始 mac/win啟用版Mac
- MapReduce 程式設計模型 & WordCount 示例程式設計模型
- 細節決定一切-多工控制檔案有感
- 領導方式決定團隊成敗 (轉)
- Hadoop 除錯第一個mapreduce程式過程詳細記錄總結Hadoop除錯
- Laravel 的一個命名細節分享Laravel
- 一個小的技術細節