Hadoop中Mapper和Reduce的原理与使用

470 阅读2分钟

Hadoop中Mapper和Reduce的原理与使用

1.1 为什么要用Hadoop?

我们来看一下对Hadoop的介绍,Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。

1.2 Mapper和Reduce的原理

MapReduce:是一个编程模型,一个处理和生成超大数据集的算法模型的相关实现。简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。

1.2.1 map过程:

1.map读取输入文件内容,按行解析成key1、value1键值对,key为每行首字母在文件中的偏移量,value为行的内容,每个键值对调用一次map函数。

我们以word.txt作为例子,计算word.txt中的单词个数,讲述一下Map函数和Reduce函数的运行原理

word.txt文件:

Hello World
Hello Hadoop
Hello EveryOne

执行流程:

  1. 每行数据运行一次map函数

12.jpg

  1. 拿V1来做Map分析:拆解内容(把词汇拆解成单词)

2.jpg

  1. 对Map的输出的结果进行shuffle:分区、排序、分组、初步汇总(该操作为Hadoop自动执行,不需要操作)

3.jpg

1.2.2 reduce过程

程序员根据业务需要编写Reduce函数对数据进行统计

4.jpg

2.1 Java代码的实现

package example;

import java.io.IOException;
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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 WordCount {
        //该为 hadoop的地址,我使用的是虚拟机,在Centos中使用ifconfig查看当前ip地址
	static final String INPUT_PATH = "hdfs://192.168.136.136:9000/input/word.txt";
	static final String OUTPUT_PATH = "hdfs://192.168.136.136:9000/output";
	
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Path inpath = new Path(INPUT_PATH);
		Path outpath = new Path(OUTPUT_PATH);
		//判断输出文件的地址是否存在
		FileSystem fs = FileSystem.get(new URI(OUTPUT_PATH),conf);
		if(fs.exists(outpath)){
			fs.delete(outpath,true);
		}
		//开始数据分析
		Job job = Job.getInstance(conf, "wordcount");
		//数据从哪读
		FileInputFormat.setInputPaths(job, inpath);
		//结果往哪写
		FileOutputFormat.setOutputPath(job, outpath);
		//用哪个Map函数和Reduce函数
		job.setMapperClass(MyMapper.class);
		job.setReducerClass(MyReducer.class);
		//输出的数据类型是什么
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(LongWritable.class);
		//开始运行
		job.waitForCompletion(true);
	}
	
	static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable>{ 
        //k1,v1,k2,v2的类型

		@Override
		protected void map(LongWritable key, Text value, 
				Mapper<LongWritable, Text, Text, LongWritable>.Context context)
				throws IOException, InterruptedException {
			String v1 = value.toString();
                        //使用空格来分割字符串,得到一个字符串数组
			String[] v1s = v1.split(" ");
                        //遍历字符串数组,将其写入 k2 v2
			for(String word:v1s){
				context.write(new Text(word), new LongWritable(1));
			}
		}  
	}
	
	
	static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
        //k2,v2,k3,v3的类型

		@Override
		protected void reduce(Text k2, Iterable<LongWritable> v2s,
				Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
			long sum = 0;
			for(LongWritable v2:v2s){
				sum += v2.get();
			}
			context.write(k2, new LongWritable(sum));
		}   
	}
}