MapReduce基础编程——combiner基础运用

内容:

假设一个年级有两个班级,数据分别在class1.csv和class2.csv中,求该年级的数学成绩平均值。数据第一列为学号,第二列为数学成绩。 要求,必须使用Combiner类,且最后输出一行数据,该行仅有一个平均值。

结果

(一)自定义Writable

  import java.io.DataInput;
  import java.io.DataOutput;
  import java.io.IOException;
   
  import org.apache.hadoop.io.Writable;
   
  public class TxtAVG implements Writable{
          private int count;
          private double average;
          public int getCount() {
                  return count;
          }
          public void setCount(int count) {
                  this.count = count;
          }
          public double getAverage() {
                  return average;
          }
          public void setAverage(double average) {
                  this.average = average;
          }
          public void readFields(DataInput in)throws IOException{
                  count = in.readInt();
                  average = in.readDouble();
          }
          public void write(DataOutput out)throws IOException{
                  out.writeInt(count);
                  out.writeDouble(average);
          }
          public String toString(){
                  return count+"\t"+average;
          }
  }

(二)MapReduce程序

import java.io.IOException;
 import java.util.StringTokenizer;
  
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.mapreduce.Job;
 import org.apache.hadoop.mapreduce.Mapper;
 import org.apache.hadoop.mapreduce.Reducer;
 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
 import org.apache.hadoop.io.*;
  
 public class WordCount {
  
     public static class AvgMapper extends Mapper<Object, Text, Text, TxtAVG> {
             private TxtAVG w = new TxtAVG();
         @Override
         protected void map(Object key, Text value, Context context)throws IOException, InterruptedException {
  
             StringTokenizer tokenizer = new StringTokenizer(value.toString(), "\n");
             while (tokenizer.hasMoreTokens()) {
                 String line = tokenizer.nextToken();
                 StringTokenizer tk = new StringTokenizer(line.toString(), ",");
  
                 //获取学号
                 String idString = tk.nextToken().toString();
                 //获取年级
                 String grade_class = idString.substring(0, 4);
                 //获取成绩
                 String scoreString = tk.nextToken().toString();
                 w.setCount(1);
                 w.setAverage(Integer.parseInt(scoreString));
                 context.write(new Text(grade_class), w);
             }
         }
     }
     
     public static class AvgReducer extends Reducer<Text, TxtAVG, Text, TxtAVG>
 {
             private TxtAVG r = new TxtAVG();
             @Override
         protected void reduce(Text key, Iterable<TxtAVG> values,Context context)throws IOException, InterruptedException {
             int sum = 0;
             int count = 0;
  
             for (TxtAVG val : values) {
                    System.out.println(val);
                    sum += val.getCount()*val.getAverage();
                    count += val.getCount();
             }
             r.setCount(count);
             r.setAverage(sum / count);
             context.write(new Text(key.toString()), r);
             System.out.println();
         }
     }
  
     public static void main(String[] args) throws Exception {
             String inputpath="hdfs://localhost:9000/Ainput";
                 String outputpath="hdfs://localhost:9000/Aoutput";
                 
                 args = new String[] {inputpath,outputpath};
                 Configuration conf = new Configuration();
                 
                 Job job = Job.getInstance(conf);
                 job.setJarByClass(WordCount.class);
                 
                 job.setOutputKeyClass(Text.class);
                 job.setOutputValueClass(TxtAVG.class);
                 
                 job.setMapperClass(AvgMapper.class);
                 job.setCombinerClass(AvgReducer.class);
                 job.setReducerClass(AvgReducer.class);
                 
                 FileInputFormat.addInputPath(job, new Path(args[0]));
                 FileOutputFormat.setOutputPath(job, new Path(args[1]));
                 
                 job.waitForCompletion(true);
     }
 }

(三)实验结果
(1)创建存储计算源文件的目录
在这里插入图片描述
(2)把需要进行计算的文件上传到hdfs上,查询是否上传成功以及某个文件的内容:
在这里插入图片描述
(3)设置第一个文件形式
在这里插入图片描述
(4)设置第二个文件的形式
在这里插入图片描述
(5)经过combiner后得出的结果
在这里插入图片描述
(6)运行后,hdfs上的结果查询以及最终算出的平均数
在这里插入图片描述

结论

(1)计算键key与学生的学号有关的数据。开始并不知道怎么才能从学号提取关键的key,通过查询知道有两种方式,是split函数和StringTokenizer类,知道两者区别分别是:
①split函数用分割符拆分时, 如果是空字符串,就会输出文字串;StringTokenizer会把空字符串去掉。
②拆分方式:split 是使用正则表达式来拆分,
StringTokenizer是以文字串拆分。

(2)本来以为所谓的combiner形式仅是和reducer那边相同,开始只提取学号来计算,虽然能计算两个班级的平均分;但是第二步的reducer键值成为一个问题,查询网上使用两个mapreduce工作,但是有觉得很麻烦,而且对于两个job的设置不会。

(3)这次的平均值计算有两种方法:
①提取年纪即前四位数来作为key键,设map、combiner、reduce来计算,不过得设置三个的输入以及输出一一对应,否则会出错。
②自定义一个Writable,存储values的格式,这里采用的与课本的格式相同,mapreduce中只有map和reduce端。

(4)通过这次实验,何为hdfs文件系统以及与map、reduce、job的关系,还有就是combiner的作用。Combiner可以说是一个中介,把map传来的数据先进行初步处理,再传到reduce那边,否则如果是海量的数据,reduce的效率会非常低。Job相当一个启动器,把mapreduce程序和hdfs文件系统连接起来,即达到计算与存储分开。

(5)由于代码能力有限,用了很长时间才能实现这个计算,可见自己平时有多疏于代码,希望平时多敲代码。这次实验还有遗留两个问题:
①计算平均值,可能遇到小数问题,我虽然用了double类型,但不能达到我想要保留几位小数的要求;
②hadoop用的是key,value格式进行计算,传入的是这种格式,传出的也是,然后写到文件中就也是这种形式了。如何才能达到写入指定的数据,即如果不要key或是在value自定义设置的一些东西怎么取消,再存入呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值