package com.qf.mr.wordcount.version2;
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.mapred.JobConf;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
/**
* 获取Job对象,初始化job的信息
*/
public class WordCountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//获取配置对象
Configuration conf = new Configuration();
//获取job对象
Job job = Job.getInstance(conf, "wordcount");
//绑定两个阶段的主类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//设置驱动类型
job.setJarByClass(WordCountDriver.class);
//设置K2,V2的类型 注意:当K2与K3不同,就必须设置K2, 当V2与V3不同,就必须设置V2, 如果相同就不需要设置
//job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//设置K3,V3的类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//使用自定义分区器
job.setPartitionerClass(WordCountPartitioner.class);
//设置reduceTask的个数,如果不设置,默认为1个
job.setNumReduceTasks(5);
//设置输入输出路径, 注意:我们可以借助main方法的args数组参数,使路径更加灵活
FileInputFormat.addInputPath(job,new Path("D:\\academia\\The teaching material\\The required data\\data-mr\\wordcount"));
//先判断输出路径在不在,如果在,就删除。
Path output = new Path("D:/output");
FileSystem fileSystem = FileSystem.get(conf);
if(fileSystem.exists(output)){
fileSystem.delete(output,true);
}
FileOutputFormat.setOutputPath(job,output);
//提交程序
System.exit(job.waitForCompletion(true)?0:1);
}
public static class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
private Text k2;
private IntWritable v2;
/**
* 执行MapTask任务前会调用一次setup方法
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void setup(Context context) throws IOException, InterruptedException {
k2 = new Text();
v2 = new IntWritable(1);
}
/**
*
* @param key 是K1 行偏移量
* @param value 是V1 行记录
* @param context 上下文,提供了输出方法write, 可以将K2,V2当成键值对输出
* @throws IOException
* @throws InterruptedException
*
* 注意:每一对K1V1调用一次map函数
*
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//第一步:将value转为java类型的String
String line = value.toString();
//第二步:使用空格进行切分,返回数组类型,元素就是单词
String[] content = line.split(" ");
//将数组中的元素(单词)封装成K2, 整数1封装成V2 然后使用上下文的write方法写出去即可
for (String word : content) {
//将word单词设置到K2身上
k2.set(word);
//写出去
context.write(k2,v2);
}
}
}
public static class WordCountReducer extends Reducer<Text, IntWritable, Text, LongWritable> {
private LongWritable v3;
@Override
protected void setup(Context context) throws IOException, InterruptedException {
v3 = new LongWritable();
}
/**
*
* @param key 是K2 是某一个单词
* @param values 是v2的集合,也就是有一堆1.
* @param context
* @throws IOException
* @throws InterruptedException
*
* 注意: reduce函数的调用的次数与分组的组个数有关系,一组调用一次。默认情况下,一个单词就是一组
*
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//定义一个变量,用于累加
long count = 0;
//只需要将values中的1取出进行累加
for (IntWritable value : values) {
//获取基本数类型1
int temp = value.get();
count+=1;
}
//将累加之和封装成V3,K2作为K3,
v3.set(count);
//然后写出去
context.write(key,v3);
}
}
/**
* 自定义分区器:
* 第一步:继承Partitioner
* 第二步:定义K2V2的泛型
* 第三步:重写方法
*
* 需求: Aa-Nn在0分区,oO-zZ在1分区,其他在2分区
*
* 注意:分区号,必须是连续的自然数,从0开头
*/
public static class WordCountPartitioner extends Partitioner<Text,IntWritable> {
public int getPartition(Text key, IntWritable value, int numPartitions) {
String line = key.toString();
String first = line.substring(0, 1);
if(first.matches("[A-Na-n]")){
return 0;
}else if(first.matches("[O-Zo-z]")){
return 1;
}else{
return 2;
}
}
}
}
用java写的mrWordCount
最新推荐文章于 2022-08-24 14:06:11 发布