本文章采用創作共用版權協議, 要求署名、非商業用途和保持一致. 轉載本文章必須也遵循署名-非商業用途-保持一致的創作共用協議.
1. 再述MapReduce計算模型
- JobTracker用于管理和調度工作(
一個集群只有一個JobTracker
) - TaskTracker用于執行工作
- 每個MapReduce任務被初始化為一個Job, 每個Job分為Map(接收鍵值對)和Reduce階段
InputSplit(存儲分片長度和記錄數據位置的數組)把輸入數據傳送給單獨的Map, 數據傳給Map后, Map將輸入分片傳送到InputFormat()上, InputFormat()(用來生成可供Map處理的鍵值對
)調用getRecordReader()方法生成RecordReader, RecordReader再通過createKey(), createValue()方法創建可供Map處理的鍵值對.TextInputFormat
是Hadoop默認的輸入方法, 每個文件都讀作為Map的輸入, 每行數組生成一條鍵值對(key在數據分片中的字節偏移量LongWritable, value是每行內容Text)
2. 編譯打包運行WordCount
總結一下通過Eclipse來編譯打包運行自己寫的MapReduce程序(基于Hadoop2.6.0
)
2.1. Hadoop庫
在編寫Hadoop程序會用到Hadoop庫, 所以需要一些Hadoop庫文件, 用于編譯
- hadoop-common-2.6.0.jar
- hadoop-mapreduce-client-core-2.6.0.jar
- hadoop-test-1.2.1.jar
下載地址Group: org.apache.hadoop下載對應版本的庫文件
2.2. 創建工程
- 使用Eclipse創建名為WordCount的工程
- 在
Project Properties -> Java Build Path -> Libraries -> Add External Jars
添加第一步所下載Jar包, 點擊OK - 創建WordCount.java源文件
#WorkCount.java
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
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.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCount {
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
/*
* LongWritable 為輸入的key的類型
* Text 為輸入value的類型
* Text-IntWritable 為輸出key-value鍵值對的類型
*/
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString()); // 將TextInputFormat生成的鍵值對轉換成字符串類型
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();
/*
* Text-IntWritable 來自map的輸入key-value鍵值對的類型
* Text-IntWritable 輸出key-value 單詞-詞頻鍵值對
*/
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration(); // job的配置
Job job = Job.getInstance(conf, "word count"); // 初始化Job
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0])); // 設置輸入路徑
FileOutputFormat.setOutputPath(job, new Path(args[1])); // 設置輸出路徑
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
2.3. 打包源文件
- 在
File -> Export -> Java -> JAR File
, 然后點擊next - 選中WordCount源文件, 設置輸出路徑和文件名WordCount.jar, 選擇Finish則打包成功
- 在輸出路徑生成Wordcount.jar
2.4. 啟動HDFS服務
打開目錄/usr/local/Cellar/hadoop/2.6.0/sbin
$ start-dfs.sh #啟動HDFS
$ jps #驗證是否啟動成功
8324 Jps
8069 DataNode
7078 NodeManager
6696 NameNode
6987 ResourceManager
3453 SecondaryNameNode
$ stop-dfs.sh #停止HDFS
成功啟動服務后, 可以直接在瀏覽器中輸入http://localhost:50070/訪問Hadoop頁面
2.5. 將輸入文件上傳到HDFS
打開目錄/usr/local/Cellar/hadoop/2.6.0/bin
#在HDFS上創建輸入/輸出文件夾
$ hdfs dfs -mkdir /user
$ hdfs dfs -mkdir /user/input
$ hdfs dfs -ls /user
#上傳本地file中文件到集群的input目錄下
$ hdfs dfs -put /Users/andrew_liu/Java/Hadoop/input/* /user/input
#查看上傳到HDFS輸入文件夾中到文件
$ hadoop fs -ls /user/input
#輸出結果
-rw-r--r-- 1 andrew_liu supergroup 1808033 2015-04-05 12:37 /user/input/rural.txt
-rw-r--r-- 1 andrew_liu supergroup 2246756 2015-04-05 12:37 /user/input/science.txt
2.6. 運行Jar文件
#在當前文件夾創建一個工作目錄
$ mkdir WorkSpace
#將打包號的Jar包復制到當前工作目錄
$cp /usr/local/Cellar/hadoop/2.6.0/bin/WorkSpace/WordCount.jar ./WorkSpace
#運行Jar文件, 各字段的意義(Hadoop打包命令, 指定Jar文件, 指定Jar文件入口類, 指定job的HDFS上的輸入文件目錄, 指定job的HDFS輸出文件目錄)
$ hadoop jar WorkSpace/WordCount.jar WordCount /user/input output
... 省略部分
File System Counters
FILE: Number of bytes read=2025025
FILE: Number of bytes written=4443318
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=10356334
HDFS: Number of bytes written=616286
HDFS: Number of read operations=25
HDFS: Number of large read operations=0
HDFS: Number of write operations=5
Map-Reduce Framework
Map input records=33907
Map output records=663964
Map output bytes=6687108
Map output materialized bytes=1005779
Input split bytes=216
Combine input records=663964
Combine output records=68147
Reduce input groups=55800
Reduce shuffle bytes=1005779
Reduce input records=68147
Reduce output records=55800
Spilled Records=136294
Shuffled Maps =2
Failed Shuffles=0
Merged Map outputs=2
GC time elapsed (ms)=187
Total committed heap usage (bytes)=1323827200
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=4054789
File Output Format Counters
Bytes Written=616286
2.7. 查看運行結果
#查看FS上output目錄內容
$ hdfs dfs -ls output
-rw-r--r-- 1 andrew_liu supergroup 0 2015-04-05 13:20 output/_SUCCESS
-rw-r--r-- 1 andrew_liu supergroup 616286 2015-04-05 13:20 output/part-r-00000 # 存放結果文件
#查看結果輸出文件內容
hdfs dfs -cat output/part-r-00000
2.8. MapReduce運行流程
- JobTracker調度任務個TaskTracker, TaskTracker執行任務時, 返回進度報告, 如果執行失敗, JobTracker將任務分配給另一個TaskTracker, 知道任務完成
- 數據按照TextInputFormat被處理成InputSplit, 輸入到Map中, Map讀取InputSplit指定位置的數據,
按照設定的方式處理數據
, 最后寫入本地磁盤 - Reduce讀取Map輸出數據, 合并value, 然后輸出到HDFS上
3. MapReduce任務優化
- 計算性能優化
- I/O操作優化
- 任務調度(就近原則, 選用空閑原則)
- 數據預處理應合理設置block快大小及Map和Reduce任務數量
- combine函數用于本地合并數據的函數, 運行用戶combine用于本地合并, 可減少網絡I/O的消耗
- 對Map輸出和最終結果壓縮
- 自定義comparator實現數據的二進制比較, 省去數據序列化和反序列化時間
4. Hadoop流
當一個可執行未見作為Mapper時, 每個Map任務以一個獨立的進程啟動可執行未見, 任務執行時, 會把輸入劃分成行提供給可執行文件, 并作為Map的標準輸入, Map從標準輸出中收集數據, 并轉換為<key, value>
輸出
Reduce任務啟動可執行文件, 將鍵值對轉化為標準輸入, Reduce從標準輸出中收集數據, 并轉換為<key, value>
輸出
5. 參考鏈接
- MapReduce Tutorial 2.6.0
- Group: org.apache.hadoop
- HADOOP TUTORIAL: CREATING MAPREDUCE JOBS IN JAVA
- BIG DATA AND HADOOP
<Hadoop Action>
- 【Hadoop基礎教程】5、Hadoop之單詞計數
更多精彩請查看個人博客-雪憶