Hadoop中的MapReducer学习之第一个例子

WordCountMR的主程序:

package wc;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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;

public class WordCountMR {
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		
		conf.set("fs.defaultFS", "hdfs://hadoop01:9000");
		System.setProperty("HADOOP_USER_NAME", "hadoop");
//		conf.set("fs.defaultFS", "file:///");
		System.out.println(conf.get("fs.defaultFS"));
		/**
		 * 获取一个job对象。一个job就是一个完整的MapReduce App 应用程序
		 * 
		 * job 一次工作
		 * task 一次任务
		 */
		Job job = Job.getInstance(conf);
		
		job.setJarByClass(WordCountMR.class);
		
		/**
		 * 设置该job的mapper和reducer组件
		 */
		
		job.setMapperClass(WCMapper.class);
		job.setReducerClass(WCReducer.class);
		
		/**
		 * 为什么要设置  job  mapper组件的输出的key-value的类型?
		 * 
		 * 因为 泛型 存在着  擦除的概念。  
		 * 
		 * 	      泛型只在编译生效
		 *    编译好了之后的class文件中,是压根没有泛型的概念
		 *    
		 *  因为既然在网络传输过程当中存在序列化的操作, 那么要存在反操作, 反序列化操作
		 *  
		 *  为什么只需要指定输出的泛型 ,  而不是指定输入的泛型?
		 *  
		 *  因为mapper组件的输入的key-value的类型是跟随 数据读取组件来决定 
		 *  
		 *  现在的wordcount程序的默认数据读取组件是 TextInputFormat和LineRecordReader
		 *  他们已经指定好了  mapper组件的输入的key-value的类型是  LongWritable和Text
		 */
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		
		/**
		 * 为什么不要指定 reducer的输入的key-value类型?
		 * 
		 * 因为reducer组件的输入的key-value的类型是由mapper组件的输出决定。
		 */
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(LongWritable.class);
		
		/**
		 * 设置reduceTsk的个数
		 * 
		 * 1、没有设置,  默认运行 1 个 reduceTask
		 * 
		 * 2、在默认的HashPartitioner的规则之下,  reduceTask的个数可以随意设置。
		 * 
		 * 3、如果自定义了 Paritioner组件, 那么设置 redcueTASK的个数就必须结合具体的业务
		 * 	
		 * 4、设置reduceTask为0 个。。那就表示  根本就没有reducer阶段。
		 *   所以mapper阶段的数据直接输出 成为最终的结果
		 *
		 * 5 、如果没有设置reducer组件,又没有指定reducetask的个数,那就表示 会运行一个reduceTask运行默认的实现。
		 * 
		 * 		第四种方式和第五种方式:
		 * 			所有maptask的结果数据都被原样输出。
		 * 			但是又不一样的地方: 如果没有reducer阶段,那就表示,mapreduce程序不会对key-value进行排序
		 * 			就表示没有 mapper和reducer中间的shuffle阶段
		 *
		 */
		job.setNumReduceTasks(3);	//reduceTask的编号是: 0	1	2
		// 如果有某一个值的getPartition方法的返回值不在这个取值范围之内,就会报错。!!!
		
		/**
		 * 指定该job的输入输出数据的路径
		 */
		FileInputFormat.setInputPaths(job,args[0]);
		Path outputPath = new Path(args[1]);
		FileSystem fs = FileSystem.get(conf);
		if(fs.exists(outputPath)){
			fs.delete(outputPath, true);
		}
		FileOutputFormat.setOutputPath(job, outputPath);
		
		/**
		 * 提交任务去运行
		 * 
		 * 提交任务到YARN集群去运行
		 * 
		 * 提交的方法可以是:
		 * 		job.submit();
		 * 		job.waitForComplrtion(true);
		 * 
		 * 		true : 是否打印执行过程
		 * 
		 * 		当前这个方式是一个阻塞方法。
		 * 
		 */
		boolean isDone = job.waitForCompletion(true);
		
		/**
		 * 这是退出整个MapReduce程序的命令
		 * 
		 * 	如果传参为0,表示正常退出。
		 */
		
		System.exit(isDone ? 0 : 1);
	
		
	}

}

WCMapper:

package wc;

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;

public class WCMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

	/**
	 * key: 当前的value这一行在当前整个文件中的起始偏移量
	 * 
	 * value: 就是默认的数据读取组件每次读取的一行数据
	 */
	
	@Override
	protected void map(LongWritable key, Text value, Context context)
			throws IOException, InterruptedException {
		/**
		 * 输出的key-value
		 * 	输出的key-value的含义: 某个单词出现了几次
		 * 	某个特定的单词出现了 一次
		 * 	key : word
		 * 	value : 1
		 */
		String[] split = value.toString().split(" ");
		for(String word : split){
			context.write(new Text(word), new IntWritable(1));
		}
		
	}

}

WCReducer:

package wc;

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

/**
 * 	当前的WCMApper组件就是WordCountMR中的第一个阶段的reduce函数的定义之地 
 * 	
 * 	四个泛型的含义:
 * 	前一对: reduce组件输入的key-value的类型
 * 	
 * 	后一对: reduce组件输出的key-value的类型
 *
 */

/**
 * reducer组件的输入key-value的类型必须和mapper组件的输出的key-value类型要一致
 *
 */

public class WCReducer extends Reducer<Text, IntWritable, Text, LongWritable>{

	/**
	 * reduce方法的参数:
	 * key : 单词
	 * values : 单词的次数的一个集合(是唯一的一个所有的相同单词的value集合)
	 * 
	 * key : hello
	 * values (1,1,1,1,1)
	 * reduce方法每执行一次,接收到的参数,就是所有key相同的key-value的集合
	 * 
	 * 每次shuffle过程处理完了一个key所对应的所有的key-value之后,就会调用reducer组件的reduce方法执行一次 	聚合操作(业务逻辑)
	 * 
	 */
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,
			Context context) throws IOException, InterruptedException {
		int sum = 0;
		for(IntWritable value : values){
			sum += value.get();
		}
		//输出结果
		context.write(key, new LongWritable(sum));
	}

	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

R_记忆犹新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值