MapReduce入門介紹及WordCount代碼實現

1.MapReduce計算模型介紹

1.1理解MapReduce思想

MapReduce思想在生活中處處可見。或多或少都曾接觸過這種思想。MapReduce的思想核心是“分而治之”,適用於大量複雜的任務處理場景(大規模數據處理場景)。即使是發佈過論文實現分佈式計算的谷歌也只是實現了這種思想,而不是自己原創。
Map負責“分”,即把複雜的任務分解爲若干個“簡單的任務”來並行處理。可以進行拆分的前提是這些小任務可以並行計算,彼此間幾乎沒有依賴關係
Reduce負責“合”,即對map階段的結果進行全局彙總
這兩個階段合起來正是MapReduce思想的體現。
在這裏插入圖片描述
還有一個比較形象的語言解釋MapReduce:  
我們要數圖書館中的所有書。你數1號書架,我數2號書架。這就是“Map”。我們人越多,數書就更快。
現在我們到一起,把所有人的統計數加在一起。這就是“Reduce”。

1.2.Hadoop MapReduce設計構思

MapReduce是一個分佈式運算程序的編程框架,核心功能是將用戶編寫的業務邏輯代碼和自帶默認組件整合成一個完整的分佈式運算程序,併發運行在Hadoop集羣上。
既然是做計算的框架,那麼表現形式就是有個輸入(input),MapReduce操作這個輸入(input),通過本身定義好的計算模型,得到一個輸出(output)。
對許多開發者來說,自己完完全全實現一個並行計算程序難度太大,而MapReduce就是一種簡化並行計算的編程模型,降低了開發並行應用的入門門檻。
Hadoop MapReduce構思體現在如下的三個方面:

  • 如何對付大數據處理:分而治之
    對相互間不具有計算依賴關係的大數據,實現並行最自然的辦法就是採取分而治之的策略。並行計算的第一個重要問題是如何劃分計算任務或者計算數據以便對劃分的子任務或數據塊同時進行計算。不可分拆的計算任務或相互間有依賴關係的數據無法進行並行計算!
  • 構建抽象模型:Map和Reduce
    MapReduce借鑑了函數式語言中的思想,用Map和Reduce兩個函數提供了高層的並行編程抽象模型。
    Map: 對一組數據元素進行某種重複式的處理;
    Reduce: 對Map的中間結果進行某種進一步的結果整理。
    MapReduce中定義瞭如下的Map和Reduce兩個抽象的編程接口,由用戶去編程實現:
    map: (k1; v1) → [(k2; v2)]
    reduce: (k2; [v2]) → [(k3; v3)]
    Map和Reduce爲程序員提供了一個清晰的操作接口抽象描述。通過以上兩個編程接口,大家可以看出MapReduce處理的數據類型是<key,value>鍵值對
  • 統一構架,隱藏系統層細節
    如何提供統一的計算框架,如果沒有統一封裝底層細節,那麼程序員則需要考慮諸如數據存儲、劃分、分發、結果收集、錯誤恢復等諸多細節;爲此,MapReduce設計並提供了統一的計算框架,爲程序員隱藏了絕大多數系統層面的處理細節。
    MapReduce最大的亮點在於通過抽象模型和計算框架把需要做什麼(what need to do)與具體怎麼做(how to do)分開了,爲程序員提供一個抽象和高層的編程接口和框架。程序員僅需要關心其應用層的具體計算問題,僅需編寫少量的處理應用本身計算問題的程序代碼。如何具體完成這個並行計算任務所相關的諸多系統層細節被隱藏起來,交給計算框架去處理:從分佈代碼的執行,到大到數千小到單個節點集羣的自動調度使用

1.3.MapReduce框架結構

一個完整的mapreduce程序在分佈式運行時有三類實例進程:
1、MRAppMaster:負責整個程序的過程調度及狀態協調
2、MapTask:負責map階段的整個數據處理流程
3、ReduceTask:負責reduce階段的整個數據處理流程
運行流程圖

2.MapReduce編程規範及示例編寫

2.1.編程規範

(1)用戶編寫的程序分成三個部分:Mapper,Reducer,Driver(提交運行mr程序的客戶端)
(2)Mapper的輸入數據是KV對的形式(KV的類型可自定義)
(3)Mapper的輸出數據是KV對的形式(KV的類型可自定義)
(4)Mapper中的業務邏輯寫在map()方法中
(5)map()方法(maptask進程)對每一個<K,V>調用一次
(6)Reducer的輸入數據類型對應Mapper的輸出數據類型,也是KV
(7)Reducer的業務邏輯寫在reduce()方法中
(8)Reducetask進程對每一組相同k的<k,v>組調用一次reduce()方法
(9)用戶自定義的Mapper和Reducer都要繼承各自的父類
(10)整個程序需要一個Drvier來進行提交,提交的是一個描述了各種必要信息的job對象

2.2.WordCount示例編寫

需求:在一堆給定的文本文件中統計輸出每一個單詞出現的總次數
(1)定義一個mapper類

//首先要定義四個泛型的類型
//keyin:  LongWritable    valuein: Text
//keyout: Text            valueout:IntWritable

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
	//map方法的生命週期:  框架每傳一行數據就被調用一次
	//key :  這一行的起始點在文件中的偏移量
	//value: 這一行的內容
	@Override
	protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
		//拿到一行數據轉換爲string
		String line = value.toString();
		//將這一行切分出各個單詞
		String[] words = line.split(" ");
		//遍歷數組,輸出<單詞,1>
		for(String word:words){
			context.write(new Text(word), new IntWritable(1));
		}
	}
}

(2)定義一個reducer類

//生命週期:框架每傳遞進來一個kv 組,reduce方法被調用一次
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
		//定義一個計數器
		int count = 0;
		//遍歷這一組kv的所有v,累加到count中
		for(IntWritable value:values){
			count += value.get();
		}
		context.write(key, new IntWritable(count));
	}
}

(3)定義一個主類,用來描述job並提交job

public class WordCountRunner {
	//把業務邏輯相關的信息(哪個是mapper,哪個是reducer,要處理的數據在哪裏,輸出的結果放哪裏……)描述成一個job對象
	//把這個描述好的job提交給集羣去運行
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job wcjob = Job.getInstance(conf);
		//指定我這個job所在的jar包
//		wcjob.setJar("/home/hadoop/wordcount.jar");
		wcjob.setJarByClass(WordCountRunner.class);
		
		wcjob.setMapperClass(WordCountMapper.class);
		wcjob.setReducerClass(WordCountReducer.class);
		//設置我們的業務邏輯Mapper類的輸出key和value的數據類型
		wcjob.setMapOutputKeyClass(Text.class);
		wcjob.setMapOutputValueClass(IntWritable.class);
		//設置我們的業務邏輯Reducer類的輸出key和value的數據類型
		wcjob.setOutputKeyClass(Text.class);
		wcjob.setOutputValueClass(IntWritable.class);
		
		//指定要處理的數據所在的位置
		FileInputFormat.setInputPaths(wcjob, "hdfs://hdp-server01:8020/wordcount/data/big.txt");
		//指定處理完成之後的結果所保存的位置
		FileOutputFormat.setOutputPath(wcjob, new Path("hdfs://hdp-server01:8020/wordcount/output/"));
		
		//向yarn集羣提交這個job
		boolean res = wcjob.waitForCompletion(true);
		System.exit(res?0:1);
	}

3.MapReduce程序運行模式

3.1.本地運行模式

(1)mapreduce程序是被提交給LocalJobRunner在本地以單進程的形式運行
(2)而處理的數據及輸出結果可以在本地文件系統,也可以在hdfs上
(3)怎樣實現本地運行?寫一個程序,不要帶集羣的配置文件
本質是程序的conf中是否有mapreduce.framework.name=local以及yarn.resourcemanager.hostname參數
(4)本地模式非常便於進行業務邏輯的debug,只要在eclipse中打斷點即可

3.2.集羣運行

模式
(1)將mapreduce程序提交給yarn集羣,分發到很多的節點上併發執行
(2)處理的數據和輸出結果應該位於hdfs文件系統
(3)提交集羣的實現步驟:
將程序打成JAR包,然後在集羣的任意一個節點上用hadoop命令啓動
hadoop jar wordcount.jar cn.itcast.bigdata.mrsimple.WordCountDriver args

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章