MapReduce求年度最高气温值以及combiner的一点认识

    MapReduce编程我是初学,下面这个例子是参考《Hadoop权威指南》第二章中的气象数据集中求取年份气温最高值的一个示例入门程序,so,如果您是老道级的高手就不用往下看了。其实这个例子的原理和统计词频是一样的,这里重点想说的还是关于combiner的一点认识,不过索性就将代码的实现写了吧。

        MapReduce应用程序处理的数据是存放在HDFS(Hadoop distributed file system 即Hadoop分布式文件系统)中的,在将数据导入HDFS之前一般情况下我们都会对原始的数据进行预处理,主要是处于两方面的考虑:1> MapReduce程序对处理数量少的大型文件更容易更加高效,当在实际应用中如果你的输入集是由大量的小文件组成的,建议先对数据集合进行预处理,将其归并为数量相对较少的打文件,这样执行效率会更高。2> 原始数据集往往存在一些坏数据,这些数据不但对我们没有任何利用价值,而且有时还会影响程序的运行结果。基于此,由于气象数据集合就是由很多的小文件组成的,因此运行之前先将其进行预处理,一般采用各种脚本均可以实现,这里就不累赘了,只是说明预处理的必要性。

        气象数据记录是由一串的数字组成,不同的位代表不通的含义,其中年份和温度在一条记录中均有体现,气象数据可以在专门的网站上下载示例数据,这里图方便我自己造了几条数据,并保存在sample.txt文件夹中,它的基本形式如下:         

                                                     00670119909999919500515070049999999N9+00011+29999999999

         其中,红色标记的部分分别代表年份和温度,下面就结合图示来分析一下MapReduce的执行过程:

         

     如上图所示:我们可以知道整个MapReduce过程的大体流程为:HDFS数据集=》Map( key , value) => Reduce( key , Iterator<...> values) ,这里我们要注意到Map的输入和Reduce输入(即:Map的输出)的不同,以sample.txt文件作为输入为例,以行为单位Map看到的key是该行在文件中的偏移量,这是默认的,一般情况下我们不需要对key做什么处理,而value则对应着一行数据,Map的主要任务是对这行数据进行处理,这里我们就是要提取出年份year以及对应的气温temperature,而Map的输出则会像如图所示对应的key和value为:1950 , [0 , 22 , -11]  ,这是为什么呢?Map在处理完输出时系统会自动执行shuffle的阶段,即组合排序 , 1950 0 , 1950 22 , 1950 -11经过shuffle就会成为:1950 [0 , 22 , -11]的形式,Reduce接到的输入对应的value是Iterator类型的,就是对应的[0 , 22 , -11],然后进行max操作,就可以找出对应的年份的气温最大值。

实现代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.Path;  
  5. import org.apache.hadoop.io.IntWritable;  
  6. import org.apache.hadoop.io.LongWritable;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.mapreduce.Job;  
  9. import org.apache.hadoop.mapreduce.Mapper;  
  10. import org.apache.hadoop.mapreduce.Reducer;  
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  13.   
  14.   
  15. public class MaxTemperature {  
  16.       
  17.     static class MaxTemperatureMapper extends Mapper<LongWritable , Text , Text , IntWritable>{  
  18.           
  19.         public void map(LongWritable key , Text value , Context context) throws IOException , InterruptedException{  
  20.               
  21.             String line = value.toString();  
  22.             String year = line.substring(15 , 19);   // 代表年份  
  23.               
  24.             int airTemperature ;   // 代表气温值  
  25.               
  26.             if(line.charAt(37) == '+'){  
  27.                 airTemperature = Integer.parseInt(line.substring(3842));  
  28.             }else{  
  29.                 airTemperature = Integer.parseInt(line.substring(3742));  
  30.             }  
  31.               
  32.             context.write(new Text(year) , new IntWritable(airTemperature));  
  33.       
  34.         }  
  35.           
  36.     }  
  37.       
  38.     static class MapTemperatureReducer extends Reducer<Text , IntWritable, Text , IntWritable>{  
  39.           
  40.          public void reduce(Text key , Iterable<IntWritable> values , Context context) throws IOException , InterruptedException{  
  41.                
  42.   
  43.              int maxValues = Integer.MIN_VALUE ;  
  44.                
  45.              for(IntWritable value : values){  
  46.                    
  47.                  maxValues = Math.max(maxValues, value.get());  
  48.                    
  49.              }  
  50.   
  51.                
  52.              context.write(key, new IntWritable(maxValues));  
  53.               
  54.                
  55.          }  
  56.           
  57.     }  
  58.       
  59.       
  60.     public static void main(String[] args) throws Exception{  
  61.           
  62.       Configuration conf = new Configuration();  
  63.       conf.set("mapred.job.tracker","192.168.1.252:9001");  
  64.   
  65.       Job job = new Job(conf, "Max temperature");  
  66.       
  67.       job.setJarByClass(MaxTemperature.class);  
  68.   
  69.       job.setMapperClass(MaxTemperatureMapper.class);  
  70.   
  71.       job.setReducerClass(MapTemperatureReducer.class);  
  72.         
  73.   
  74.       job.setOutputKeyClass(Text.class);  
  75.   
  76.       job.setOutputValueClass(IntWritable.class);  
  77.   
  78.       FileInputFormat.addInputPath(job, new Path("hdfs://192.168.1.252:9000/user/root/input/sample.txt"));  
  79.   
  80.       FileOutputFormat.setOutputPath(job, new Path("hdfs://192.168.1.252:9000/user/root/output2"));  
  81.         
  82.   
  83.       System.exit(job.waitForCompletion(true) ? 0 : 1);  
  84.   
  85.           
  86.     }  
  87.   
  88. }  

下面再说一下combiner,Hadoop允许用户声明一个combiner,它运行在map的输出上,该函数的输出作为reduce函数的输入。我们以找最大值图示说明一下:

                              

可以这样理解,combiner和reducer是做的同样的工作,但你所要决定的是:对整个集合执行的操作,能否分解为对经过combiner后产生的新集合操作的结果相同,而combiner执行的操作和reducer执行的操作是相同的,即:局部处理对全局处理是否有影响, 举个例子来说:

求最大值:max(0 , 20 , 10 , 25 , 15 , 3 , 9 , 35)  =  max( max(0 , 20 , 10) , max(25 , 15) , max(3 , 9 , 35) ) = max(20 , 25 , 35) =  35 这个表达式描述了上面执行combiner的过程,我们都知道,max(0 , 20 , 10 , 25 , 15 , 3 , 9 , 35)和max( max(0 , 20 , 10) , max(25 , 15) , max(3 , 9 , 35) )是肯定相等的,那这个过程我们就可以采用combiner优化。

但是考虑一下求平均值:mean(0 , 20 , 10 , 25 , 15 , 3 , 9 , 35) = 14.625 , 而如果采用combiner的形式,则求均值过程变为:

mean(0 , 20 , 10 , 25 , 15 , 3 , 9 , 35) = mean( mean(0 , 20 , 10) , mean(25 , 15) , mean(3 , 9 , 35) ) = 15.23   ,显然是不相等的,这种情况下我们就不可以采用combiner的方式。

         combiner是用reducer接口来定义的,如果采用combiner就要在配置中做如下设置:

         conf.setCombinerClass( MaxTemperatureReducer.class ) ; 通常处理过程和Reducer一样。 

         上面就是对第二章学习的总结,纯属个人观点,理解的可能存在错误,加油,继续每天的学习!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值