MapReduce 并行编程

一、实验目的及要求

1、掌握MapReduce并行编程方法

2、掌握自定义数据类型

3、掌握自定义分区类和自定义排序类的使用

4、掌握最值求解并行化方法

二、实验原理与内容

假设有一个服务器每天都记录同一个网站的访问量数据,主要是该网站下所有页面中的最大访问量和最小访问量,数据存储在下面三个文件中。
在这里插入图片描述

数据格式如下(记录时不具体到天):
在这里插入图片描述

说明:第一列为某年某月的时间信息,第二列为该月内某天观测到的最大访问量,第三列为该月内同一天观测到的最小访问量。

程序设计要求如下:

最后输出网站每个月内的最大值、最小值,一个月一行数据。

如图中2017-07最大值为900,最小值为100;2017-08最大值为560,最小值为200

输出格式如下

2017-08 560 200

2017-07 900 100

必须自定义一个数据类型,包含某天观测到的最大最小访问量。

要求自定义分区函数,2017年的数据全部规约到一个reducer处理,2018年的数据全部规约到另一个reducer处理。

要求同一年的数据按月份降序排序。如

2017-08 560 200

2017-07 900 100

完成本次实验需要有一定的设计代码思维,因为有两个年份,先按照年月份进行降序排序,然后引用Partitioner函数把年份分成两份文件输出。最后排序出每个月份的最大销量和最小销量进行输出。

三、代码实现:

1、 创建一个类MyWritable,定义一个最大值和最小值



public class MyWritable implements Writable{
 private int maxAccess;
 private int minAccess;
 @Override
 public void readFields(DataInput in) throws IOException {
  // TODO Auto-generated method stub
  maxAccess=in.readInt();
  minAccess=in.readInt();
 }

 @Override
 public void write(DataOutput out) throws IOException {
  // TODO Auto-generated method stub
  out.writeInt(maxAccess);
  out.writeInt(minAccess);
 }

 @Override
 public String toString() {
  return maxAccess + " " + minAccess;
 }
 
 public int getMaxAccess() {
  return maxAccess;
 }

 public int getMinAccess() {
  return minAccess;
 }

 public void setMaxAccess(int maxAccess) {
  this.maxAccess = maxAccess;
 }

 public void setMinAccess(int minAccess) {
  this.minAccess = minAccess;
 }
}



2、创建一个yearMonthOrder类 比较年月份大小,降序排。


public class yearMonthOrder extends WritableComparator{
 public yearMonthOrder() {
  // TODO Auto-generated constructor stub
  super(Text.class,true);
 }
 
 @Override
 public int compare(WritableComparable a, WritableComparable b) {
  // TODO Auto-generated method stub
  Text v1=(Text) a;
  Text v2=(Text) b;
  //比较V1和V2的大小,降序排。
  return -super.compare(v1, v2);
 }
}

3、创建一个MyPartitioner类,引用Partitioner 函数进行排序


public class MyPartitioner extends Partitioner<Text, MyWritable>{

  @Override
  public int getPartition(Text key, MyWritable value, int arg2) {
   return Integer.parseInt(key.toString().substring(0, 4))%arg2;
   
  }
  
 }

4、创建一个Mapper类


public class MyMapper extends Mapper<LongWritable, Text, Text, MyWritable> {
 MyWritable MW=new MyWritable();
 
 //在map函数中将年月作为key值
 public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException {
   String[] serverAccess = ivalue.toString().split(" ");
   MW.setMaxAccess(Integer.parseInt(serverAccess[1]));
   MW.setMinAccess(Integer.parseInt(serverAccess[2]));
   context.write(new Text(serverAccess[0]),MW);
 }

}

5、创建MyReduce,在reduce函数中比较每个月的销量,按照从高到低排序

public class MyReducer extends Reducer<Text, MyWritable, Text, MyWritable> {
  private MyWritable jieguo = new MyWritable();
  public void reduce(Text _key, Iterable<MyWritable> values, Context context)
    throws IOException, InterruptedException {
   // process values
   boolean mark=true;
   
   //在reduce函数中比较每个月的销量,按照从高到低排序。
   for (MyWritable val : values) {
    if(mark){
     jieguo.setMaxAccess(val.getMaxAccess());
     jieguo.setMinAccess(val.getMinAccess());
     mark=false;
    }else{
     if(val.getMaxAccess()>jieguo.getMaxAccess()){
      jieguo.setMaxAccess(val.getMaxAccess());
     }
     if(val.getMinAccess()<jieguo.getMinAccess()){
      jieguo.setMinAccess(val.getMinAccess());
     }
    }
   }
   context.write(_key, jieguo);
  }

 }

6、创建一个Driver类,进行数据处理

public class MyDriver {

  public static void main(String[] args) throws Exception {
   Configuration conf = new Configuration();
   //修改key和value之间的分隔符为空格
       conf.set("mapred.textoutputformat.separator", " "); 
   Job job = Job.getInstance(conf, "JobName");
   job.setJarByClass(shiyan3.MyDriver.class);
   // TODO: specify a mapper
   job.setMapperClass(MyMapper.class);
   // TODO: specify a reducer
   job.setReducerClass(MyReducer.class);

   // TODO: specify output types
   job.setOutputKeyClass(Text.class);
   job.setOutputValueClass(MyWritable.class);
   
   //1、自定义Partition类,因为一年有2个年 ,因此需要2个分区,指定Partition类,以及partition的数量。
   job.setNumReduceTasks(2);
   job.setPartitionerClass(MyPartitioner.class);
   
   job.setSortComparatorClass(yearMonthOrder.class);

   // TODO: specify input and output DIRECTORIES (not files)
   FileInputFormat.setInputPaths(job, new Path("hdfs://localhost:9000/shiyan3/input"));
   FileOutputFormat.setOutputPath(job, new Path("hdfs://localhost:9000/shiyan3/output"));

   if (!job.waitForCompletion(true))
    return;
  }

 }

猜你喜欢

转载自blog.csdn.net/weixin_44001568/article/details/106163531