场景
MapReduce Java API-多输入路径方式:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/119453275
在上面的基础上,怎样用Partitioner的方式实现将学生的成绩数据
分段输出到不同的文件。
例如分为三个成绩段:
小于60分
大于等于60分小于等于80分
大于80分
Partitioner
1、Partion发生在Map阶段的最后,会先调用job.setPartitionerClass对这个List进行分区,
每个分区映射到一个Reducer。每个分区内又调用job.setSortComparatorClass设置的key
比较函数类排序。
2、 Partitioner的作用是对Mapper产生的中间结果进行分片,以便将同一个分组的数据交给同一个Reducer处理,
它直接影响Reducer阶段的复杂均衡。
3、Partitioner创建流程
① 先分析一下具体的业务逻辑,确定大概有多少个分区
②
首先书写一个类,它要继承org.apache.hadoop.mapreduce.Partitioner这个类
③
重写public int getPartition这个方法,根据具体逻辑,读数据库或者配置返回相同的数字
④
在main方法中设置Partioner的类,job.setPartitionerClass(DataPartitioner.class);
⑤ 设置Reducer的数量,job.setNumReduceTasks(6);
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
实现
1、首先新建数据集score.txt,用来进行分段输出。
1、自定义分区函数类
通过成绩判断,用return的值为0、1、2代表三个分区。
package com.badao.muloutput; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Partitioner; public class StudentPartitioner extends Partitioner<IntWritable, Text> { @Override public int getPartition(IntWritable intWritable, Text text, int i) { //学生成绩 int scoreInt = intWritable.get(); //默认指定分区0 if(i==0) { return 0; } if(scoreInt < 60) { return 0; }else if(scoreInt<=80) { return 1; }else { return 2; } } }
3、定义Mapper类
package com.badao.muloutput; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class MulOutputMapper extends Mapper<LongWritable,Text,IntWritable,Text> { @Override public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] studentArr = value.toString().split(" "); if(StringUtils.isNotBlank(studentArr[1])) { IntWritable pKey = new IntWritable(Integer.parseInt(studentArr[1].trim())); context.write(pKey,value); } } }
4、定义Reduce类
package com.badao.muloutput; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class MulOutputReducer extends Reducer<IntWritable,Text,NullWritable,Text> { @Override public void reduce(IntWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException { for(Text value:values) { context.write(NullWritable.get(),value); } } }
5、新建Job类
package com.badao.muloutput; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.NullWritable; 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; import org.apache.hadoop.mapreduce.lib.reduce.IntSumReducer; import java.io.IOException; public class MulOutputJob { public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException { wordCountLocal(); } public static void wordCountLocal()throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); System.setProperty("HADOOP_USER_NAME","root"); conf.set("fs.defaultFS","hdfs://192.168.148.128:9000"); //实例化一个作业,word count是作业的名字 Job job = Job.getInstance(conf, "muloutput"); //指定通过哪个类找到对应的jar包 job.setJarByClass(MulOutputJob.class); //为job设置Mapper类 job.setMapperClass(MulOutputMapper.class); //为job设置reduce类 job.setReducerClass(MulOutputReducer.class); //设置Partitioner类 job.setPartitionerClass(StudentPartitioner.class); //设置reduce的个数为3 job.setNumReduceTasks(3); //mapper输出格式 job.setMapOutputKeyClass(IntWritable.class); job.setMapOutputValueClass(Text.class); //reduce输出格式 job.setOutputKeyClass(NullWritable.class); job.setOutputValueClass(Text.class); //为job设置输入路径,输入路径是存在的文件夹/文件 FileInputFormat.addInputPath(job,new Path("/score.txt")); //为job设置输出路径 FileOutputFormat.setOutputPath(job,new Path("/muloutput8")); job.waitForCompletion(true); } }
6、将数据集上传到HDFS指定的目录下,运行job查看输出结果
注意事项
这里要注意坑点,因为这里在分解数据时是按照一个空格来拆分的,所以数据集中
每个key和value之间只能有一个空格。
并且不要再数据集的最后面添加多余的换行,不然会导致不能正常输出数据。
比如这里查看数据时发现多了个换行
然后找不到不出统计数据的原因,就在代码中将每步的结果输出下
如果是上面多了换行的话,下面输出key-value时就会有异常数据,都跟上面这样是正常的。