mapreduce编程(二)- 大象书中求每一年的最高温度

书上的例子是为了取出一年当中气温最高的值,那么将年份和气温做了一个复合的key. 

1 通过设置了partitioner来进行分区。因为分区是按照年份来进行,所以同年的数据就可以分区到一个reducer中。

2 自定义key比较器,按照年份升序,温度值降序。这样map输出的所有kv对就是按照年份升序,温度值降序排列的。

3 自定义分组比较器,所有同一年的数据属于同一个组,那么在reduce输出的时候,只需要取第一个value就能达到输出一年最高气温的目的。 

代码:

[java]  view plain copy
  1. package temperature;  
  2. import java.io.DataInput;  
  3. import java.io.DataOutput;  
  4. import java.io.IOException;  
  5. import java.util.StringTokenizer;  
  6. import org.apache.hadoop.conf.Configuration;  
  7. import org.apache.hadoop.fs.Path;  
  8. import org.apache.hadoop.io.IntWritable;  
  9. import org.apache.hadoop.io.LongWritable;  
  10. import org.apache.hadoop.io.NullWritable;  
  11. import org.apache.hadoop.io.Text;  
  12. import org.apache.hadoop.io.WritableComparable;  
  13. import org.apache.hadoop.io.WritableComparator;  
  14. import org.apache.hadoop.mapreduce.Job;  
  15. import org.apache.hadoop.mapreduce.Mapper;  
  16. import org.apache.hadoop.mapreduce.Partitioner;  
  17. import org.apache.hadoop.mapreduce.Reducer;  
  18. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  19. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  20. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  21. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  22. public class Temperature {  
  23.     // 自己定义的key类应该实现WritableComparable接口  
  24.     public static class IntPair implements WritableComparable<IntPair> {  
  25.         int first;  
  26.         int second;  
  27.         /** 
  28.          * Set the left and right values. 
  29.          */  
  30.         public void set(int left, int right) {  
  31.             first = left;  
  32.             second = right;  
  33.         }  
  34.         public int getFirst() {  
  35.             return first;  
  36.         }  
  37.         public int getSecond() {  
  38.             return second;  
  39.         }  
  40.         @Override  
  41.         // 反序列化  
  42.         public void readFields(DataInput in) throws IOException {  
  43.             // TODO Auto-generated method stub  
  44.             first = in.readInt();  
  45.             second = in.readInt();  
  46.         }  
  47.         @Override  
  48.         // 序列化  
  49.         public void write(DataOutput out) throws IOException {  
  50.             // TODO Auto-generated method stub  
  51.             out.writeInt(first);  
  52.             out.writeInt(second);  
  53.         }  
  54.         @Override  
  55.         // key的比较  
  56.         public int compareTo(IntPair o) {  
  57.             // TODO Auto-generated method stub  
  58.             if (first != o.first) {  
  59.                 return first < o.first ? -1 : 1;  
  60.             } else if (second != o.second) {  
  61.                 return second < o.second ? -1 : 1;  
  62.             } else {  
  63.                 return 0;  
  64.             }  
  65.         }  
  66.         // 新定义类应该重写的两个方法  
  67.         @Override  
  68.         public int hashCode() {  
  69.             return first * 157 + second;  
  70.         }  
  71.         @Override  
  72.         public boolean equals(Object right) {  
  73.             if (right == null)  
  74.                 return false;  
  75.             if (this == right)  
  76.                 return true;  
  77.             if (right instanceof IntPair) {  
  78.                 IntPair r = (IntPair) right;  
  79.                 return r.first == first && r.second == second;  
  80.             } else {  
  81.                 return false;  
  82.             }  
  83.         }  
  84.     }  
  85.     /** 
  86.      * 分区函数类。根据first确定Partition。 
  87.      */  
  88.     public static class FirstPartitioner extends  
  89.             Partitioner<IntPair, NullWritable> {  
  90.         @Override  
  91.         public int getPartition(IntPair key, NullWritable value,  
  92.                 int numPartitions) {  
  93.             return Math.abs(key.getFirst() * 127) % numPartitions;  
  94.         }  
  95.     }  
  96.     /** 
  97.      * key比较函数类。first升序,second降序。 
  98.      */  
  99.     public static class KeyComparator extends WritableComparator {  
  100.         protected KeyComparator() {  
  101.             super(IntPair.classtrue);  
  102.         }  
  103.         @Override  
  104.         public int compare(WritableComparable w1, WritableComparable w2) {  
  105.             IntPair ip1 = (IntPair) w1;  
  106.             IntPair ip2 = (IntPair) w2;  
  107.             int l = ip1.getFirst();  
  108.             int r = ip2.getFirst();  
  109.             int cmp = (l == r ? 0 : (l < r ? -1 : 1));  
  110.             if (cmp != 0) {  
  111.                 return cmp;  
  112.             }  
  113.             l = ip1.getSecond();  
  114.             r = ip2.getSecond();  
  115.             return l == r ? 0 : (l < r ? 1 : -1); // reverse  
  116.         }  
  117.     }  
  118.     /** 
  119.      * 分组函数类。属于同一个组的value会放到同一个迭代器中,而比较是否是同一组需要使用GroupingComparator比较器。 
  120.      */  
  121.     // 第二种方法,继承WritableComparator  
  122.     public static class GroupingComparator extends WritableComparator {  
  123.         protected GroupingComparator() {  
  124.             super(IntPair.classtrue);  
  125.         }  
  126.         @Override  
  127.         // Compare two WritableComparables.  
  128.         public int compare(WritableComparable w1, WritableComparable w2) {  
  129.             IntPair ip1 = (IntPair) w1;  
  130.             IntPair ip2 = (IntPair) w2;  
  131.             int l = ip1.getFirst();  
  132.             int r = ip2.getFirst();  
  133.             return l == r ? 0 : (l < r ? -1 : 1);  
  134.         }  
  135.     }  
  136.     // 自定义map  
  137.     public static class Map extends  
  138.             Mapper<LongWritable, Text, IntPair, NullWritable> {  
  139.         private final IntPair intkey = new IntPair();  
  140.         public void map(LongWritable key, Text value, Context context)  
  141.                 throws IOException, InterruptedException {  
  142.             String line = value.toString();  
  143.             StringTokenizer tokenizer = new StringTokenizer(line);  
  144.             int left = 0;  
  145.             int right = 0;  
  146.             if (tokenizer.hasMoreTokens()) {  
  147.                 left = Integer.parseInt(tokenizer.nextToken());  
  148.                 if (tokenizer.hasMoreTokens())  
  149.                     right = Integer.parseInt(tokenizer.nextToken());  
  150.                 intkey.set(left, right);  
  151.                 context.write(intkey, NullWritable.get());  
  152.             }  
  153.         }  
  154.     }  
  155.     // 自定义reduce  
  156.     //  
  157.     public static class Reduce extends  
  158.             Reducer<IntPair, NullWritable, IntWritable, IntWritable> {  
  159.         private final IntWritable left = new IntWritable();  
  160.         private final IntWritable right = new IntWritable();  
  161.         public void reduce(IntPair key, Iterable<NullWritable> values,  
  162.                 Context context) throws IOException, InterruptedException {  
  163.             left.set(key.getFirst());  
  164.             right.set(key.getSecond());  
  165.             context.write(left, right);  
  166.         }  
  167.     }  
  168.     /** 
  169.      * @param args 
  170.      */  
  171.     public static void main(String[] args) throws IOException,  
  172.             InterruptedException, ClassNotFoundException {  
  173.         // TODO Auto-generated method stub  
  174.         // 读取hadoop配置  
  175.         Configuration conf = new Configuration();  
  176.         // 实例化一道作业  
  177.         Job job = new Job(conf, "temperature");  
  178.         job.setJarByClass(Temperature.class);  
  179.         // Mapper类型  
  180.         job.setMapperClass(Map.class);  
  181.         // 不再需要Combiner类型,因为Combiner的输出类型<Text,  
  182.         // IntWritable>对Reduce的输入类型<IntPair, IntWritable>不适用  
  183.         // job.setCombinerClass(Reduce.class);  
  184.         // Reducer类型  
  185.         job.setReducerClass(Reduce.class);  
  186.         // 分区函数  
  187.         job.setPartitionerClass(FirstPartitioner.class);  
  188.         // key比较函数  
  189.         job.setSortComparatorClass(KeyComparator.class);  
  190.         // 分组函数  
  191.         job.setGroupingComparatorClass(GroupingComparator.class);  
  192.         // map 输出Key的类型  
  193.         job.setMapOutputKeyClass(IntPair.class);  
  194.         // map输出Value的类型  
  195.         job.setMapOutputValueClass(NullWritable.class);  
  196.         // rduce输出Key的类型,是Text,因为使用的OutputFormatClass是TextOutputFormat  
  197.         job.setOutputKeyClass(IntWritable.class);  
  198.         // rduce输出Value的类型  
  199.         job.setOutputValueClass(IntWritable.class);  
  200.         // 将输入的数据集分割成小数据块splites,同时提供一个RecordReder的实现。  
  201.         job.setInputFormatClass(TextInputFormat.class);  
  202.         // 提供一个RecordWriter的实现,负责数据输出。  
  203.         job.setOutputFormatClass(TextOutputFormat.class);  
  204.         // 输入hdfs路径  
  205.         FileInputFormat.setInputPaths(job, new Path(args[0]));  
  206.         // 输出hdfs路径  
  207.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  
  208.         // 提交job  
  209.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  210.     }  
  211. }  

来源:http://blog.csdn.net/heyutao007/article/details/5890165

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值