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
执行流程:
- 每行数据运行一次map函数
- 拿V1来做Map分析:拆解内容(把词汇拆解成单词)
- 对Map的输出的结果进行shuffle:分区、排序、分组、初步汇总(该操作为Hadoop自动执行,不需要操作)
1.2.2 reduce过程
程序员根据业务需要编写Reduce函数对数据进行统计
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));
}
}
}