大數據MapReduce的原理小結

MapReduce定義

  1. MapReduce是一種分佈式計算模型,由Google提出,主要用於搜索領域,解決海量數據的計算問題.
  2. MapReduce是分佈式運行的,由兩個階段組成:Map和Reduce,Map階段是一個獨立的程序,有很多個節點同時運行,每個節點處理一部分數據。Reduce階段是一個獨立的程序,有很多個節點同時運行,每個節點處理一部分數據。
  3. MapReduce框架都有默認實現,用戶只需要覆蓋map()和reduce()兩個函數,即可實現分佈式計算,非常簡單。

原理

在這裏插入圖片描述

  • 在執行mapreduce之前,原始數據被分割成若干split,每個split作爲一個map任務的輸入。
  • 當Hadoop處理很多小文件(文件大小小於hdfs block大小)的時候,由於FileInputFormat不會對小文件進行劃分,所以每一個小文件都會被當做一個split並分配一個map任務,會有大量的map task運行,導致效率底下。

map階段

  • 框架使用InputFormat類的子類把輸入文件(夾)劃分爲很多InputSplit,默認,每個HDFS的block對應一個InputSplit。通過RecordReader類,把每個InputSplit解析成一個個<k1,v1>。默認,框架對每個InputSplit中的每一行,解析成一個<k1,v1>。
  • 框架調用Mapper類中的map(…)函數,map函數的形參是<k1,v1>對,輸出是<k2,v2>對。一個InputSplit對應一個map task。程序員可以覆蓋map函數,實現自己的邏輯。
  • (假設reduce存在)框架對map輸出的<k2,v2>進行分區。不同的分區中的<k2,v2>由不同的reduce task處理。默認只有1個分區。(假設reduce不存在)框架對map結果直接輸出到HDFS中。
  • (假設reduce存在)框架對每個分區中的數據,按照k2進行排序、分組。分組指的是相同k2的v2分成一個組。注意:分組不會減少<k2,v2>數量。
  • (假設reduce存在,可選)在map節點,框架可以執行reduce歸約。
  • (假設reduce存在)框架會對map task輸出的<k2,v2>寫入到linux 的磁盤文件中。 至此,整個map階段結束.

reduce階段

  • 框架對多個map任務的輸出,按照不同的分區,通過網絡copy到不同的reduce節點。這個過程稱作shuffle。
  • 框架對reduce端接收的[map任務輸出的]相同分區的<k2,v2>數據進行合併、排序、分組。
  • 框架調用Reducer類中的reduce方法,reduce方法的形參是<k2,{v2…}>,輸出是<k3,v3>。一個<k2,{v2…}>調用一次reduce函數。程序員可以覆蓋reduce函數,實現自己的邏輯.
  • 框架把reduce的輸出保存到HDFS中。 至此,整個reduce階段結束。

代碼示例1(單詞統計)

package deno;

import java.io.IOException;

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.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 MapReduceWC {
//第一部分,寫map階段
//指定map輸出輸出的key和value的序列化類型。
	public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
//map函數,處理每一行數據。一行數據是一個對象,調用一次map函數。
//	context 這個參數是上下文的意思,裏面包括整個任務信息,可以執行數據寫入寫出
		protected void map(LongWritable key, Text value,
				org.apache.hadoop.mapreduce.Mapper<LongWritable, Text, Text, LongWritable>.Context context)
				throws java.io.IOException, InterruptedException {
			// 先將該行數據轉換成字符串類型
			String line = value.toString();
			// 將一行數據進行切分。按照數據的分隔符。
			String[] split = line.split(",");
			// 遍歷數組
			for (String word : split) {
				// 組建 k2和v2,單詞統計將 value寫死 是 1
				// 數據通過context寫入到磁盤
				context.write(new Text(word), new LongWritable(1L));
			}
		};
	}

//第二部分,寫Reduce階段	
	public static class MyReduce extends Reducer<Text, LongWritable, Text, LongWritable> {
		// 同樣是有reduce函數
		@Override
		protected void reduce(Text k2, Iterable<LongWritable> v2s,
				Reducer<Text, LongWritable, Text, LongWritable>.Context context)
				throws IOException, InterruptedException {
			// 將value加起來,聚合
			long count = 0l;
			for (LongWritable value : v2s) {
				count += value.get();
			}
			// 將結果輸出,輸出到hdfs上
			context.write(k2, new LongWritable(count));
		}
	}

	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		// 設置配置參數
		Configuration conf = new Configuration();
		// 創建任務
		Job job = Job.getInstance(conf, MapReduceWC.class.getSimpleName());
		// 指定jar文件
		job.setJarByClass(MapReduceWC.class);
		// 指定輸入路徑,數據在hdfs上的輸入路徑,指定第一個參數是hdfs輸入路徑
		FileInputFormat.addInputPath(job, new Path(args[0]));
		// 指定map的類
		job.setMapperClass(MyMapper.class);
		// 指定map輸出的key和value的數據類型。
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(LongWritable.class);

		// 指定reduce類以及輸出數據類型。
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(LongWritable.class);
		// 指定輸出路徑hdfs
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		// 提交任務,如果是true,會返回任務執行的進度信息等。
		job.waitForCompletion(true);

	}

}

代碼示例2(求和)

package deno;

import java.io.IOException;

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.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;

import deno.MapReduce_Sum.MyMap.MyReduce;

public class MapReduce_Sum {
	public static class MyMap extends Mapper<LongWritable, Text, Text, LongWritable> {
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, LongWritable>.Context context)
				throws IOException, InterruptedException {
			// 數據樣式:張三,12月3號,20,三個字段
			String line = value.toString();
			String[] split = line.split(",");
			// 對數據進行過濾,將數組長度是3的過濾出來

			// 取出姓名字段
			String name = split[0];
			// 取出money字段
			long money = Long.parseLong(split[2]);
			context.write(new Text(name), new LongWritable(money));
		}

		public static class MyReduce extends Reducer<Text, LongWritable, Text, LongWritable> {
			@Override
			protected void reduce(Text k2, Iterable<LongWritable> v2s,
					Reducer<Text, LongWritable, Text, LongWritable>.Context context)
					throws IOException, InterruptedException {
				long sum = 0l;
				for (LongWritable value : v2s) {
					sum += value.get();
				}
				context.write(k2, new LongWritable(sum));
			}
		}
	}
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		// 設置配置參數
		Configuration conf = new Configuration();
		// 創建任務
		Job job = Job.getInstance(conf, MapReduce_Sum.class.getSimpleName());
		// 指定jar文件
		job.setJarByClass(MapReduce_Sum.class);
		// 指定輸入路徑,數據在hdfs上的輸入路徑,指定第一個參數是hdfs輸入路徑
		FileInputFormat.addInputPath(job, new Path(args[0]));
		// 指定map的類
		job.setMapperClass(MyMap.class);
		// 指定map輸出的key和value的數據類型。
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(LongWritable.class);

		// 指定reduce類以及輸出數據類型。
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(LongWritable.class);
		// 指定輸出路徑hdfs
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		// 提交任務,如果是true,會返回任務執行的進度信息等。
		job.waitForCompletion(true);

	}

}

打成JAR包
1、鼠標右擊項目,點擊Export;
2、選擇java–>jar file;
在這裏插入圖片描述
打成的JAR包,上傳到hadoop
hadoop 提交mapreduce任務的命令 hadoop jar jar路徑 程序的主類名 hdfs的輸入路徑 hdfs的輸出路徑

hadoop fs -put WC_test.txt /data
hadoop fs -ls /data/
hadoop jar shujia_WC.jar deno.MapReduceWC /data/WC_test.txt /MapOut/001
hadoop fs -ls /MapOut/001
hadoop fs -cat /MapOut/001/part-r-00000
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章