【MapReduce】从wordcount看mapreduce的编程套路

本文通过wordcount实例,深入探讨MapReduce的编程模式。详细介绍了wordcount的题目描述,包括输入输出要求,接着讲解了WordCountMapper、WordCountReducer的实现,并展示了运行结果,最后提炼了MapReduce的一般编程套路。
摘要由CSDN通过智能技术生成

1. wordcount题目描述

wordcount:统计2个文件中单词出现的总次数

$ cat 1.txt  
hello	hi	love	me	brief
outlook	me	hello	china	brief
hi	love	beijing	hi	hi
$ cat 2.txt
hello	hi	love	me	brief
outlook	me	hello	china	brief
hi	love	beijing	hi	hi
facebook	china	beijing	china	beijing
2. wordcount编程

WordCountMapper.java

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/*
 * 统计每一个小文件的
 * 1)继承Mapper
 * 2)重写map
 * 
 * Mapper需要的4个泛型:
 * 	框架读取完文件给你的内容
 * 	KEYIN, 输入的键的类型  这里指的是每一行的起始字节偏移量 
 * 	VALUEIN, 输入的值的类型  这里指的是一行的内容   String
 * 
 * 	输出
 * 	KEYOUT,   输出的建的类型  这里指的是每一个单词  String
 * 	VALUEOUT   输出的值的类型  这里指的是单词的次数  int
 * 
 * 因为map数据要经过网络传输到reduce那,所有的数据类型必须具备序列化和反序列化的能力
 * 序列化:字符串---》二进制
 * 反序列化:二进制---》字符串
 * java中的序列化  反序列化接口  Serializable
 * 但是hadoop弃用了java中的   
 * java中的序列化反序列化  太重   过于繁杂
 * Long  java序列化反序列化将类结构一并序列化反序列化
 * hadoop中重新定义了一套序列化  反序列化的接口  Writable  轻
 * 对于我们常用的一些类型  帮我们实现了对应的类型:
 * long---->LongWritable
 * int------>IntWritable
 * byte---->ByteWritable
 * double---->DoubleWritable
 * Null---->NullWritable
 * String---->Text
 */
/*
 * 在map端   获取每一行的内容  切分   发送
 */
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
	/*
	 * LongWritable key:输入的每一行的偏移量   框架读取的
	 * Text value:输入的每一行的内容
	 * Context context:上下文对象   用于向reduce发送数据 读取框架给的东西
	 * 
	 * 调用频率:一行调用一次
	 * 一个文本100行  这个方法就会调用100次
	 */
	@Override
	protected void map(LongWritable key, 
			Text value, 
			Context context)
			throws IOException, InterruptedException {
		//获取每一行内容  转换为String
		String line = value.toString();
		//切分每一个单词  hello	hi	love	me	brief
		String[] words = line.split("\t");
		/*
		 * 如果要统计  只能统计一行的  并不能统计一个文件的
		 * 全部发送到reduce端进行统计
		 * key:单词
		 * value:1
		 */
		//循环遍历每一个单词  发送给reduce
		for(String w:words){
			Text k=new Text(w);
			IntWritable v=new IntWritable(1);
			//把单词 1发送reduce
			context.write(k, v);
		}
	}
}

WordCountReducer.java

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

/*
 * 统计分析
 * 1.继承Reducer
 * 2.重写reduce()
 * 
 * Reducer中的四个泛型:
 * 输入:从map过来的   对应的map的输出类型
 * KEYIN, reduce的输入的key的类型  --map输出的key的类型  Text
 * VALUEIN, reduce的输入的value的类型--map输出的value类型
 * 
 * 输出:最终的结果输出
 * KEYOUT, 输出的key类型  这里指的最终的单词  Text
 * VALUEOUT  输出的value类型   这里指的是每一个单词的最终的词频  IntWritable
 */

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
	/*map到reduce之间有一个shuffle的过程(洗牌/将map输出的数据进行打乱  重洗)   
	 * 目前我们使用的是默认的  洗牌过程中有一步分组的
	 * 默认的分组 按照map输出的key进行分组的
	 * 
	 * 这里map输出的key是单词  按照单词进行分组
	 * 会把单词相同的所有的数据分在一组
	 * hello,1  hello,1
	 * a,1  hello,1
	 * 分组:
	 * hello,1  hello,1  hello,1   组1
	 * a,1  组2
	 * 
	 * Text key, 一组中的任意一个key  hello
	 * Iterable<IntWritable> values,  一组中的相同的key对应的所有的value  <1,1,1>
	Context context  上下文对象   向上承接map 向下输出结果 hdfs/本地
	
	这个函数的调用频率:一组调用一次  有多少组就调用几次
	 */
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,
			Context context) throws IOException, InterruptedException {
		//循环遍历values求和即可
		int sum=0;
		for(IntWritable v:values){
			//将v转为int类型   get  hadoop--->java
			sum+=v.get();
		}
		//写出
		IntWritable rv=new IntWritable(sum);
		context.write(key, rv);
		
	}
}

Driver.java

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


/*
 * 提交运行mapreduce的程序的
 */
public class Driver {
	/*
	 * String[] args 代表程序运行过程中接受的参数
	 * 按照参数的顺序放在数组的下标中
	 * 第一个参数  --  数组的下标0的位置
	 */
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		//加载配置文件
		/*
		 * 优先加载jar包中的  hdfs-default.xml   mapred-default.xml ...
		 * src下的   -site.xml   -default.xml
		 * 代码中的
		 * 最后加载的最终生效
		 */
		Configuration conf=new Configuration();
		//启动一个job
		/*
		 * job的概念 一个mapreduce程序  封装的map或reduce的相关的配置项
		 */
		//创建job对象
		Job job=Job.getInstance(conf);
		
		//封装上面的job   将自定义的mapper  reducer类封装到job上
		//指定当前job的入口  main入口
		//参数class 类型    1)类名.class 2)对象。getClass 3)class.forname()
		job.setJarByClass(Driver.class);
		
		//指定job的对应的Mapper类
		job.setMapperClass(WordCountMapper.class);
		//指定job对应的reducer的类
		job.setReducerClass(WordCountReducer.class);
		
		//指定mapper的输出的key 和value类型
		/*
		 * 泛型的作用范围:
		 * 	编译时可以进行检查数据类型  运行时泛型自动擦除
		 */
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		//指定reducer输出的key  value的类型
		/*
		 * 这个方法设定的是输出的key value的类型
		 * 如果map指定了  这个指的就是reduce
		 * 如果map没有指定 这个指的是map和reduce的
		 * 当map  reduce的输出的key value的类型一致的时候只需指定下面的就可以
		 */
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		
		//指定输入  需要处理的文件   添加输入路径
		//参数1  job  参数2  输入路径
		//FileInputFormat.addInputPath(job, new Path("hdfs://hdp01:9000/in"));
		FileInputFormat.addInputPath(job, new Path(args[0]));
		//指定输出路径  输出路径不能存在   否则报错
		//FileOutputFormat.setOutputPath(job, new Path("/out_01"));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		//提交job
		
		//这个方法基本不用   不打印日志
		//job.submit();
		//可以打印日志的  参数代表是否打印运行的进程
		job.waitForCompletion(true);
	}
}

运行结果:

[hdp01@hdp01 jars]$ hadoop jar follow-1.0-SNAPSHOT.jar com.study.follow.wordcount.Driver /wcin /wcout
输出日志省略
[hdp01@hdp01 jars]$ hdfs dfs -cat /wcout/part-r-00000
beijing	4
brief	4
china	4
facebook	1
hello	4
hi	8
love	4
me	4
outlook	2
3. mr编程套路

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值