WordCount(mapreduce、yarn)

       作为一个hadoop的初学者,在经历了一系列繁琐复杂的hadoop集群环境安装配置之后,终于自主完成了一个wordcount程序。通过mapreduce进行分布式运算,并通过yarn进行运行调度。

      wordcount是一个经典的案例,相信大家都熟悉。主要任务就是计算每个单词出现的次数并保存。实现该过程,主要包括两个阶段:map阶段: 将每一行文本数据变成<单词,1>这样的kv数据;reduce阶段:将相同单词的一组kv数据进行聚合,即累加所有的v。主要包括三个类的开发:WordcountMapper类开发;WordcountReducer类开发;JobSubmitter客户端类开发。

     WordcountMapper类:

package ldp.wordcount;

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;


/**
 * KEYIN:是map task读取到的数据的key类型,是一行的起始偏移量Long
 * VALUEIN:是map task读取到的数据的value类型,是一行的内容String
 * KEYOUT:是用户自定义map方法要返回的结果kv数据的key类型,在wordcount逻辑中,为单词String
 * VALUEOUT:是用户自定义map方法要返回的结果kv数据的value类型,在wordcount逻辑中,为整数Integer
 *
 * 在mapreduce中,map产生的数据需要传输给reduce,需要进行序列化和反序列化,所以hadoop设计了自己            
 * 的序列化机制
 * hadoop为jdk中的常用基本类型序列化接口:
 * Long     LongWritable
 * String   Text
 * Integer  IntWritable
 * Float    FloatWritable
 */
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
		
			@Override
			protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
					throws IOException, InterruptedException {
				
				//切单词,将每一行数据按照分割符" "切分
				String line = value.toString();
				String[] words = line.split(" ");
				for (String word : words) {
					context.write(new Text(word), new IntWritable(1));
				}				
			}			
}

  WordcountReducer类:

package ldp.wordcount;

import java.io.IOException;
import java.util.Iterator;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
		
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,
			Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
	
		//统计词频,values为一个迭代对象
		Iterator<IntWritable> iterator = values.iterator();

		int count = 0;
		
		while (iterator.hasNext()) {			
			IntWritable value = (IntWritable) iterator.next();
			count += value.get();			
		}
		context.write(key, new IntWritable(count));		
	}	
}

JobSubmitter客户端类:

package ldp.mapreduce;

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.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 job的客户端程序
 *功能:
 *1、封装本次job运行时所需要的必要参数
 *2、跟yarn进行交互,将mapreduce程序成功的启动运行
 */
public class JobSubmitter {
    	
	public static void main(String[] args) throws Exception {
				
		Configuration conf = new Configuration();
				
		Job job = Job.getInstance(conf);
		
		//封装参数:jar包所在的位置
		job.setJarByClass(JobSubmitter.class);
		
		//封装参数:本次job要调用的Mapper实现类、Reducer实现类
		job.setMapperClass(WordCountMapper.class);
		job.setReducerClass(WordCountReducer.class);
		
		//封装参数:本次job的Mapper实现类、Reducer实现类产生的结果数据的key、value类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
				
		//封装参数:本次job要处理的输入数据集所在路径、最终结果的输出路径
          //注意:此时输入路径为hadoop集群环境的目录
		FileInputFormat.setInputPaths(job, new Path("/wordcount/input"));
		//注意:输出路径必须不存在,否则报错
		FileOutputFormat.setOutputPath(job, new Path("/wordcount/output"));
		
		//封装参数:想要启动的reducer task的数量
		job.setNumReduceTasks(2);
		
		//提交job给yarn
		boolean res = job.waitForCompletion(true);
		
        //用于以后的日志需要,可删掉
		System.exit(res?0:-1);		
	}				
}

三个类都完成以后,就需要将工程打成一个jar包并上传至linux服务器。然后在hadoop集群的机器上,用命令

hadoop jar wordcount.jar ldp.wordcount.JobSubmitter运行,hadoop jar命令会将这台机器上的hadoop安装目录中的所有jar包和配置文件全部加入运行时的classpath,此时运行结束,大功告成。

       同时,有时候需要调试,也可以在本地运行,只需要把JobSubmitter客户端类的

FileInputFormat.setInputPaths(job, new Path("/wordcount/input"));
FileOutputFormat.setOutputPath(job, new Path("/wordcount/output"));

修改成本地目录,即:

FileInputFormat.setInputPaths(job, new Path("e:/wordcount/input"));
FileOutputFormat.setOutputPath(job, new Path("e:/wordcount/output"));

此时,mapreduce程序就会在本机运行,同时可以轻松调试及debug。

猜你喜欢

转载自blog.csdn.net/ldpKing/article/details/84317102
今日推荐