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;
  }

 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章