一個MapReduce 程式示例 細節決定成敗(八):TotalOrderPartitioner
在上一個實驗中 一個MapReduce 程式示例 細節決定成敗(七) :自定義Key 及RecordReader,使用自定義的RecordReader 從split 中讀取資訊,封裝到自定義的key中。
這一步在使用TotalOrderPartitioner 進行詞頻統計是非常重要的。
下面進入主題:在一個MapReduce 程式示例 細節決定成敗(五) :Partitioner 中,演示瞭如何使用一下自定義Partitioner。
我們使用了一個自定義的Partitioner,來實現當設定3個reducer時輸出字元的排序問題。為了簡化問題,我使用在partitioner中直接進行判斷。
這裡面其實是有兩個我們應該注意的問題。
因為TotaOrderlPartitioner是已經封裝到hadoop 系統中了,所以我們只要正確配置就可以了。
partition file :描述了每個字元應該進入到哪兒個reducer中的檔案,功能就是上一篇中我們簡化處理的 a~i 分到0, h~q 分到1,r~z 分到2。
partition file 不用我們手動去寫,而且手動去寫也很難平均分佈各個reducer任務的負載。可以使用InputSampler.RandomSampler完成此項工作的。
關注 getPartitionFile和 new URI 的寫法。
結果分析: 下面資料是執行結果,可以看到抽樣劃分的界限是a~e f~p q~z 。
這一步在使用TotalOrderPartitioner 進行詞頻統計是非常重要的。
下面進入主題:在一個MapReduce 程式示例 細節決定成敗(五) :Partitioner 中,演示瞭如何使用一下自定義Partitioner。
我們使用了一個自定義的Partitioner,來實現當設定3個reducer時輸出字元的排序問題。為了簡化問題,我使用在partitioner中直接進行判斷。
這裡面其實是有兩個我們應該注意的問題。
1、在partitioner程式碼中寫死了,只有3個reducer,那如果我們想要把reducer的個數設定成其它值,還需要改程式碼。那接下來我們介紹的 TotalOrderPartitioner 就完美解決了上述兩個問題。
2、partitioner 的一個作用就是解決資料傾斜的問題,但我們上次寫的那個partitioner不適用
本次涉及到的內容有。
1、生成樣本partition file
2、使用使用CacheFile功能把partition file 分發到各個map task節點。
3、配置使用TotalOrderPartitioner.
因為TotaOrderlPartitioner是已經封裝到hadoop 系統中了,所以我們只要正確配置就可以了。
partition file :描述了每個字元應該進入到哪兒個reducer中的檔案,功能就是上一篇中我們簡化處理的 a~i 分到0, h~q 分到1,r~z 分到2。
partition file 不用我們手動去寫,而且手動去寫也很難平均分佈各個reducer任務的負載。可以使用InputSampler.RandomSampler完成此項工作的。
下面貼一下配置使用TotaOrderlPartitioner的程式碼
預設抽樣是在所有的split上進行的,當輸入檔案很大的時候,使用第一個方法進行抽樣代價會很大。點選(此處)摺疊或開啟
- /**
- * freq:每個key 可以被抽樣次數
- * numSamples:總樣本數
- */
- InputSampler.RandomSampler(double freq, int numSamples);
- /**
- * freq:每個key 可以被抽樣次數
- * numSamples:總樣本數
- * maxSplitsSampled:定義最多從多少個splits 上進行抽樣
- */
- InputSampler.RandomSampler(double freq, int numSamples, int maxSplitsSampled);
當處理檔案很大的時候,加上第三個引數maxSplitsSampled 限定最多處理多少個split。
freq 引數: 被抽樣到的split中的每一個key 被選中的概率。 numSamples 代表抽樣的總樣本數。 比如從10000條資料中抽取 10條數,假如freq 設定為0.5,那按概率大約執行到20條的時候,樣本數就夠了。
但然後程式會繼續執行,每個被抽中的樣本去隨機替換一條已經抽出的10條記錄中的一條,一直到最後。
關注 getPartitionFile和 new URI 的寫法。
點選(此處)摺疊或開啟
-
job.setPartitionerClass(TotalOrderPartitioner.class);
-
job.setNumReduceTasks(3);
-
RandomSampler<MyKey, NullWritable> sampler
-
= new InputSampler.RandomSampler<MyKey,NullWritable>(0.6, 20, 3);
-
InputSampler.writePartitionFile(job, sampler);
-
-
String partitionFile = TotalOrderPartitioner.getPartitionFile(job.getConfiguration());
-
URI uri = new URI(partitionFile+"#"+TotalOrderPartitioner.DEFAULT_PATH);
- job.addCacheFile(uri);
注意: 1、RecordReader的key與map輸入輸出key和reduce的輸入key 要保持一致。 因為取樣是從job 配置的InputFormat中得到RecordReader 然後不斷的得到Key ,從中取樣。
取到的樣使用TotalOrderPartitioner 得到的partitionFile 是供分配到不同reducer的,所以RecordReader的key 要與Reduer的輸入key 一致,又 RecordReader的key value 是輸入到 map 中的,
Reduce 的輸入又是Map的輸出。繞了半天結論就是: RecordReader的key, Map 的輸入輸出key ,Reduce的輸入key 是要保持一致的。
2、使用TotalOrderPartitioner前一定要配置了reduceTask 的個數、InputFormat、和上面討論的 key class。
貼一下結果:
點選(此處)摺疊或開啟
-
wordcount.MyKey@212cb585 8
-
wordcount.MyKey@212cb585 3
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 11
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 3
-
wordcount.MyKey@168497f6 8
-
wordcount.MyKey@168497f6 5
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 6
-
wordcount.MyKey@168497f6 7
-
wordcount.MyKey@168497f6 4
-
wordcount.MyKey@168497f6 12
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@2e67cd84 13
-
wordcount.MyKey@2e67cd84 4
-
wordcount.MyKey@2e67cd84 4
-
wordcount.MyKey@2e67cd84 6
-
wordcount.MyKey@2e67cd84 7
-
wordcount.MyKey@2e67cd84 3
-
wordcount.MyKey@2e67cd84 6
-
wordcount.MyKey@2e67cd84 3
點選(此處)摺疊或開啟
- wordcount.MyKey@212cb585 8
-
wordcount.MyKey@212cb585 3
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 11
-
wordcount.MyKey@212cb585 4
-
wordcount.MyKey@212cb585 3
-
wordcount.MyKey@168497f6 8
-
wordcount.MyKey@168497f6 5
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 6
-
wordcount.MyKey@168497f6 7
-
wordcount.MyKey@168497f6 4
-
wordcount.MyKey@168497f6 12
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@168497f6 3
-
wordcount.MyKey@2e67cd84 13
-
wordcount.MyKey@2e67cd84 4
-
wordcount.MyKey@2e67cd84 4
-
wordcount.MyKey@2e67cd84 6
-
wordcount.MyKey@2e67cd84 7
-
wordcount.MyKey@2e67cd84 3
-
wordcount.MyKey@2e67cd84 6
- wordcount.MyKey@2e67cd84 3
注意到key的格式,這是由於我們的MyKey沒有覆寫toString 方法,輸出的時候直接使用了Object的toString實現。
點選(此處)摺疊或開啟
-
@Override
-
public String toString(){
-
return String.valueOf(this.c);
- }
點選(此處)摺疊或開啟
-
[train@sandbox src]$ hdfs dfs -cat output/*0
-
a 8
-
b 3
-
c 4
-
d 4
-
e 11
-
[train@sandbox src]$ hdfs dfs -cat output/*1
-
f 4
-
g 3
-
h 8
-
i 5
-
j 3
-
k 3
-
l 6
-
m 7
-
n 4
-
o 12
-
p 3
-
[train@sandbox src]$ hdfs dfs -cat output/*2
-
q 3
-
r 13
-
s 4
-
t 4
-
u 6
-
w 7
-
x 3
-
y 6
-
z 3
-
下面貼出主程式程式碼
點選(此處)摺疊或開啟
-
package wordcount;
-
-
import java.io.IOException;
-
import java.net.URI;
-
-
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.NullWritable;
-
import org.apache.hadoop.io.Text;
-
import org.apache.hadoop.mapred.lib.TotalOrderPartitioner;
-
import org.apache.hadoop.mapreduce.Job;
-
import org.apache.hadoop.mapreduce.Mapper;
-
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.mapreduce.lib.partition.InputSampler;
-
import org.apache.hadoop.mapreduce.lib.partition.InputSampler.RandomSampler;
-
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<MyKey, NullWritable, MyKey, IntWritable> {
-
Text mKey = new Text();
-
IntWritable mValue = new IntWritable(1);
-
@Override
-
protected void map(MyKey key, NullWritable value, Context context)
-
throws IOException, InterruptedException {
-
context.write(key, mValue);
-
}
-
}
-
-
public static class MyWordCountReducer extends Reducer<MyKey, IntWritable, MyKey, IntWritable> {
-
Text rkey = new Text();
-
IntWritable rvalue = new IntWritable(1);
-
@Override
-
protected void reduce(MyKey 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.setInputFormatClass(MyCombinedFilesInputFormat.class);
-
MyCombinedFilesInputFormat.setMaxInputSplitSize(job, 1024*1024*64);
-
job.setOutputFormatClass(TextOutputFormat.class);
-
job.setMapOutputKeyClass(MyKey.class);
-
job.setMapOutputValueClass(IntWritable.class);
-
job.setOutputKeyClass(MyKey.class);
-
job.setOutputValueClass(IntWritable.class);
-
-
job.setPartitionerClass(TotalOrderPartitioner.class);
-
job.setNumReduceTasks(3);
-
RandomSampler<MyKey, NullWritable> sampler
-
= new InputSampler.RandomSampler<MyKey,NullWritable>(0.6, 20, 3);
-
InputSampler.writePartitionFile(job, sampler);
-
-
String partitionFile = TotalOrderPartitioner.getPartitionFile(job.getConfiguration());
-
URI uri = new URI(partitionFile+"#"+TotalOrderPartitioner.DEFAULT_PATH);
-
job.addCacheFile(uri);
-
-
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-2109331/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一個MapReduce 程式示例 細節決定成敗(一)
- 一個MapReduce 程式示例 細節決定成敗(五) :Partitioner
- 一個MapReduce 程式示例 細節決定成敗(九):RawComparator
- 一個MapReduce 程式示例 細節決定成敗(六) :CombineFileInputFormatORM
- 一個MapReduce 程式示例 細節決定成敗(三) :Combiner
- 一個MapReduce 程式示例 細節決定成敗(二) :觀察日誌及 Counter
- 一個MapReduce 程式示例 細節決定成敗(七) :自定義Key 及RecordReader
- 細節決定成敗 MapReduce任務實戰 Map Join
- 細節決定成敗 MapReduce任務實戰 Reduce Join
- 細節決定成敗 MapReduce任務實戰 倒排索引索引
- 第五章 Vlookup函式示例-細節決定成敗函式
- 細節決定成敗!APP設計不容忽視的20個細節APP
- 如何讓程式設計師幸福工作:細節決定成敗程式設計師
- 面試:黃金法則——細節決定成敗面試
- Java集合詳解8:Java集合類細節精講,細節決定成敗Java
- 開發者談F2P模式:細節決定成敗模式
- 邦芒簡歷:求職簡歷細節決定成敗求職
- Python讀書筆記:細節決定成敗(2)Python筆記
- Python讀書筆記:細節決定成敗(1)Python筆記
- 汪峰FIIL Diva智慧耳機究竟如何?細節決定成敗
- 細節決定ERP專案啟動會的成敗
- 細節決定成敗,不容忽視的10道Node面試題面試題
- 細節決定成敗——無CSS時網頁的可讀性CSS網頁
- 軟體設計是怎樣煉成的(7)——細節決定成敗(詳細設計)
- 【原創】構建高效能ASP.NET站點之三 細節決定成敗ASP.NET
- 一個簡單的MapReduce示例(多個MapReduce任務處理)
- 【2024-03-06】細節成敗
- 決定開發者面試成敗的 3 個問題面試
- AutoCAD 2024:細節決定成敗,精準設計從這裡開始 mac/win啟用版Mac
- MapReduce 程式設計模型 & WordCount 示例程式設計模型
- 細節決定一切-多工控制檔案有感
- 領導方式決定團隊成敗 (轉)
- Hadoop 除錯第一個mapreduce程式過程詳細記錄總結Hadoop除錯
- Laravel 的一個命名細節分享Laravel
- 一個小的技術細節
- h5效能優化,細節決定結果。H5優化
- Google TV以何定成敗Go
- 天貓魔盒3Pro內容分析:內容決定成敗