大数据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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值