MapReduce概述:
MapReduce是一種分佈式計算模型,由Google提出,主要用於搜索領域,解決海量數據的計算問題。
MR由兩個階段組成:Map和Reduce,用戶只需要實現map()和reduce()兩個函數,即可實現分佈式計算,非常簡單。
這兩個函數的形參是key,value對,表示函數的輸入信息。
執行步驟:
1、map任務處理
1.1讀取輸入文件內容,解析成key、value對。對輸入文件的每一行,解析成key、value對。每一個鍵值對調用一次map函數。
1.2寫自己的邏輯,對輸入的key、value處理,轉換成新的key、value輸出。
1.3對輸出的key、value進行分區。
1.4對不同分區的數據,按照key進行排序、分組。相同key和value放到一個集合中。
1.5(可選)分組後的數據進行歸約。
2、reduce任務處理
2.1對多個map任務的輸出,按照不同的分區,通過網絡copy到不同的reduce節點
2.2對多個map任務的輸出進行合併、排序。寫reduce函數自己的邏輯,對輸入的key、value處理,轉換成新的key、value輸出。
2.3把reduce的輸出保存到文件中。
map、reduce鍵值對格式
函數 輸入鍵值對 輸出鍵值對
map() <k1,v1> <k2,v2>
reduce() <k1,{v2}> <k3,v3>
MapperReduce的原理圖如下:
例子:實現WCCount
流程圖如下:
代碼實現如下::::(注意導的包哦)
Mapper實現:
package com.zhou.hadoop.mr;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
/**
* 解釋:Mapper需要實現序列化,因爲有些數據是需要寫到磁盤然後傳遞的
* LongWritable和Text都是hadoop實現的序列化的機制,hadoop沒有使用jdk默認的序列化機制
* Long和String本身就實現了序列化機制
* Long的化身就是LongWritable,String的化身就是Text
* @param key
* @param value
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//根據思想,輸入的值是-key:偏移量 value:每行數據
// 輸出的值是-key:字符串 value:1(因爲按照每個字母是1個,後續好計算)
//accept
String line = value.toString();
//split 按照空格分隔字母
String[] words = line.split(" ");
//loop
for (String w : words) {
//send
context.write(new Text(w), new LongWritable(1));
}
}
}
Reduce實現:
package com.zhou.hadoop.mr;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class WCReduce extends Reducer <Text, LongWritable, Text, LongWritable>{
/**
* 解釋:
* 此方法是接收mapper方法傳遞過來的數值,然後進行彙總等一系列的處理
* @param key
* @param values
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
//define a counter
long counter=0;
//loop
for (LongWritable l:values) {
counter+=l.get();
}
context.write(key,new LongWritable(counter));
}
}
WCCount實現:
package com.zhou.hadoop.mr;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
* 1、分析具體的業務邏輯,確定輸入輸出數據的樣式
* 2、自定義一個類,這個類要繼承mapper類,重寫map方法,
* 在map方法實現具體業務邏輯,將新的key,value輸出
*3、自定義一個類,這個類要繼承Reduce類,重寫reduce方法,
*在reduce方法中實現具體業務邏輯
* 4、將自定義的mapper和reduce統計job對象組裝起來
*/
public class WCCount {
public static void main(String[] args) throws Exception {
//構建job對象
Job job = Job.getInstance(new Configuration());
//注意:main方法所在的類
job.setJarByClass(WCCount.class);
//設置Mapper相關屬性
job.setMapperClass(WCMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
FileInputFormat.setInputPaths(job, new Path("/words"));
//設置reducer相關屬性
job.setReducerClass(WCReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
FileOutputFormat.setOutputPath(job, new Path("/wcount"));
//提交任務 true是代表打印日誌,false不打印日誌
job.waitForCompletion(true);
}
}
編寫完代碼之後,測試的話需要打jar包部署在hadoop環境上進行測試。
使用hadoop jar 的命令進行測試
MR1.0流程講解:
1.執行MR的命令:
hadoop jar <jar在linux的路徑> <main方法所在的類的全類名> <參數>
例子:
hadoop jar /root/wc1.jar cn.itcast.d3.hadoop.mr.WordCount hdfs://itcast:9000/words /out2
2.MR執行流程
(1).客戶端提交一個mr的jar包給JobClient(提交方式:hadoop jar …)
(2).JobClient通過RPC和JobTracker進行通信,返回一個存放jar包的地址(HDFS)和jobId
(3).client將jar包寫入到HDFS當中(path = hdfs上的地址 + jobId)
(4).開始提交任務(任務的描述信息,不是jar, 包括jobid,jar存放的位置,配置信息等等)
(5).JobTracker進行初始化任務
(6).讀取HDFS上的要處理的文件,開始計算輸入分片,每一個分片對應一個MapperTask
(7).TaskTracker通過心跳機制領取任務(任務的描述信息)
(8).下載所需的jar,配置文件等
(9).TaskTracker啓動一個java child子進程,用來執行具體的任務(MapperTask或ReducerTask)
(10).將結果寫入到HDFS當中