MapReduce编程实战之“高级特性”

来源:互联网 发布:第一次扣的体验知乎 编辑:程序博客网 时间:2024/06/06 00:34

本篇介绍MapReduce的一些高级特性,如计数器、数据集的排序和连接。计数器是一种收集作业统计信息的有效手段,排序是MapReduce的核心技术,MapReduce也能够执行大型数据集间的“”连接(join)操作。


计数器


计数器是一种收集作业统计信息的有效手段,用于质量控制或应用级统计。计数器还可用于辅助诊断系统故障。对于大型分布式系统来说,获取计数器比分析日志文件容易的多。


示例一:气温缺失及不规则数据计数器


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.io.IOException;  
  2. import java.util.Iterator;  
  3.   
  4. import org.apache.hadoop.conf.Configured;  
  5. import org.apache.hadoop.io.*;  
  6. import org.apache.hadoop.mapred.JobClient;  
  7. import org.apache.hadoop.mapred.JobConf;  
  8. import org.apache.hadoop.mapred.MapReduceBase;  
  9. import org.apache.hadoop.mapred.Mapper;  
  10. import org.apache.hadoop.mapred.OutputCollector;  
  11. import org.apache.hadoop.mapred.Reducer;  
  12. import org.apache.hadoop.mapred.Reporter;  
  13. import org.apache.hadoop.util.Tool;  
  14. import org.apache.hadoop.util.ToolRunner;  
  15.   
  16. //统计最高气温的作业,也统计气温值缺少的记录,不规范的记录  
  17. public class MaxTemperatureWithCounters extends Configured implements Tool {  
  18.   
  19.     enum Temperature {  
  20.         MiSSING, MALFORMED  
  21.     }  
  22.   
  23.     static class MaxTemeratureMapperWithCounters extends MapReduceBase implements  
  24.             Mapper<LongWritable, Text, Text, IntWritable> {  
  25.   
  26.         private NcdcRecordParser parser = new NcdcRecordParser();  
  27.   
  28.         @Override  
  29.         public void map(LongWritable key, Text value,  
  30.                 OutputCollector<Text, IntWritable> output, Reporter reporter)  
  31.                 throws IOException {  
  32.             parser.parse(value);  
  33.             if (parser.isValidTemperature()) {  
  34.                 int airTemperature = parser.getAirTemperature();  
  35.                 output.collect(new Text(parser.getYear()), new IntWritable(  
  36.                         airTemperature));  
  37.             } else if (parser.isMa1formedTemperature()) {  
  38.                 reporter.incrCounter(Temperature.MALFORMED, 1);  
  39.             } else if (parser.IsMissingTemperature()) {  
  40.                 reporter.incrCounter(Temperature.MALFORMED, 1);  
  41.             }  
  42.   
  43.         }  
  44.   
  45.     }  
  46.   
  47.     static class MaxTemperatureReduceWithCounters extends MapReduceBase implements  
  48.             Reducer<Text, IntWritable, Text, IntWritable> {  
  49.         public void reduce(Text key, Iterator<IntWritable> values,  
  50.                 OutputCollector<Text, IntWritable> output, Reporter reporter)  
  51.                 throws IOException {  
  52.             int maxValue = Integer.MIN_VALUE;  
  53.             while (values.hasNext()) {  
  54.                 maxValue = Math.max(maxValue, values.next().get());  
  55.             }  
  56.             output.collect(key, new IntWritable(maxValue));  
  57.   
  58.         }  
  59.     }  
  60.   
  61.     @Override  
  62.     public int run(String[] args) throws Exception {  
  63.         args = new String[] { "/test/input/t""/test/output/t" }; // 给定输入输出路径  
  64.         JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);  
  65.         if (conf == null) {  
  66.             return -1;  
  67.         }  
  68.         conf.setOutputKeyClass(Text.class);  
  69.         conf.setOutputValueClass(IntWritable.class);  
  70.         conf.setMapperClass(MaxTemeratureMapperWithCounters.class);  
  71.         conf.setCombinerClass(MaxTemperatureReduceWithCounters.class);  
  72.         conf.setReducerClass(MaxTemperatureReduceWithCounters.class);  
  73.         JobClient.runJob(conf);  
  74.         return 0;  
  75.     }  
  76.   
  77.     public static void main(String[] args) throws Exception {  
  78.         int exitCode = ToolRunner.run(new MaxTemperatureWithCounters(), args);  
  79.         System.exit(exitCode);  
  80.     }  
  81. }  

示例二:统计气温信息缺失记录所占比例


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import org.apache.hadoop.conf.*;  
  2. import org.apache.hadoop.mapred.*;  
  3. import org.apache.hadoop.util.*;  
  4. //统计气温缺失记录所占比例  
  5.   
  6. public class MissingTemperatureFields extends Configured implements Tool {  
  7.   
  8.     @Override  
  9.     public int run(String[] args) throws Exception {  
  10.         String jobID = args[0];  
  11.         JobClient jobClient = new JobClient(new JobConf(getConf()));  
  12.         RunningJob job = jobClient.getJob(JobID.forName(jobID));  
  13.         if (job == null) {  
  14.             System.err.printf("No job with ID %s found.\n", jobID);  
  15.             return -1;  
  16.         }  
  17.         if (!job.isComplete()) {  
  18.             System.err.printf("Job %s is not complete.\n", jobID);  
  19.             return -1;  
  20.         }  
  21.         Counters counters = job.getCounters();  
  22.         long missing = counters  
  23.                 .getCounter(MaxTemperatureWithCounters.Temperature.MiSSING);  
  24.         long total = counters.findCounter(  
  25.                 "org.apache.hadoop.mapred.Task$Counter""MAP_INPUT_RECORDS")  
  26.                 .getCounter();  
  27.         System.out.printf("Records with missing temperature fields:%.2f%%\n",  
  28.                 100.0 * missing / total);  
  29.         return 0;  
  30.     }  
  31.   
  32.     public static void main(String[] args) throws Exception {  
  33.         int exitCode = ToolRunner.run(new MissingTemperatureFields(), args);  
  34.         System.exit(exitCode);  
  35.     }  
  36. }  

hadoop jar xx.jar MissingTemperatureFields job_1400072670556_0001


排序


排序是MapReduce的核心技术。尽管应用本身可能并不需要对数据排序,但仍可能使用MapReduce的排序功能来组织数据。下面将讨论几种不同的数据集排序方法,以及如何控制MapReduce的排序。


实例一、数据准备:将天气数据转成顺序文件格式


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.*;  
  4. import org.apache.hadoop.io.*;  
  5. import org.apache.hadoop.io.SequenceFile.CompressionType;  
  6. import org.apache.hadoop.io.compress.GzipCodec;  
  7. import org.apache.hadoop.mapred.*;  
  8. import org.apache.hadoop.util.*;  
  9.   
  10. public class SortDataPreprocessor extends Configured implements Tool {  
  11.     static class CleanerMapper extends MapReduceBase implements  
  12.             Mapper<LongWritable, Text, IntWritable, Text> {  
  13.   
  14.         private NcdcRecordParser parser = new NcdcRecordParser();  
  15.   
  16.         @Override  
  17.         public void map(LongWritable key, Text value,  
  18.                 OutputCollector<IntWritable, Text> output, Reporter reporter)  
  19.                 throws IOException {  
  20.             parser.parse(value);  
  21.             if (parser.isValidTemperature()) {  
  22.                 output.collect(new IntWritable(parser.getAirTemperature()),  
  23.                         value);  
  24.             }  
  25.         }  
  26.     }  
  27.   
  28.     @Override  
  29.     public int run(String[] args) throws Exception {  
  30.         args = new String[] { "/test/input/t""/test/input/seq" };  
  31.         JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);  
  32.         if (conf == null) {  
  33.             return -1;  
  34.         }  
  35.         conf.setMapperClass(CleanerMapper.class);  
  36.         conf.setOutputKeyClass(IntWritable.class);  
  37.         conf.setOutputValueClass(Text.class);  
  38.         conf.setNumReduceTasks(0);  
  39.         conf.setOutputFormat(SequenceFileOutputFormat.class);  
  40.         SequenceFileOutputFormat.setCompressOutput(conf, true);  
  41.         SequenceFileOutputFormat  
  42.                 .setOutputCompressorClass(conf, GzipCodec.class);  
  43.         SequenceFileOutputFormat.setOutputCompressionType(conf,  
  44.                 CompressionType.BLOCK);  
  45.         JobClient.runJob(conf);  
  46.         return 0;  
  47.     }  
  48.   
  49.     public static void main(String[] args) throws Exception {  
  50.         int exitCode = ToolRunner.run(new SortDataPreprocessor(), args);  
  51.         System.exit(exitCode);  
  52.     }  
  53. }  

示例二、部分排序


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import org.apache.hadoop.conf.*;  
  2. import org.apache.hadoop.io.*;  
  3. import org.apache.hadoop.io.SequenceFile.CompressionType;  
  4. import org.apache.hadoop.io.compress.GzipCodec;  
  5. import org.apache.hadoop.mapred.*;  
  6. import org.apache.hadoop.util.*;  
  7.   
  8. public class SortByTemperatureUsingHashPartitioner extends Configured implements  
  9.         Tool {  
  10.   
  11.     @Override  
  12.     public int run(String[] args) throws Exception {  
  13.         args = new String[] { "/test/input/seq""/test/output/t" };  
  14.         JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);  
  15.         if (conf == null) {  
  16.             return -1;  
  17.         }  
  18.         conf.setInputFormat(SequenceFileInputFormat.class);  
  19.         conf.setOutputKeyClass(IntWritable.class);  
  20.         conf.setOutputFormat(SequenceFileOutputFormat.class);  
  21.         conf.setNumReduceTasks(5);//设置5个reduce任务,输出5个文件  
  22.         SequenceFileOutputFormat.setCompressOutput(conf, true);  
  23.         SequenceFileOutputFormat  
  24.                 .setOutputCompressorClass(conf, GzipCodec.class);  
  25.         SequenceFileOutputFormat.setOutputCompressionType(conf,  
  26.                 CompressionType.BLOCK);  
  27.         JobClient.runJob(conf);  
  28.         return 0;  
  29.     }  
  30.   
  31.     public static void main(String[] args) throws Exception {  
  32.         int exitCode = ToolRunner.run(  
  33.                 new SortByTemperatureUsingHashPartitioner(), args);  
  34.         System.exit(exitCode);  
  35.     }  
  36.   
  37. }  

hadoop jar test.jar SortByTemperatureUsingHashPartitioner -D mapred.reduce.tasks=30

产生多个已经排好序的小文件。


连接


MapReduce能够执行大型数据集间的“”连接(join)操作,但是从头编写相关代码来执行连接比较麻烦。也可以考虑使用一个更高级的框架,如Pig、Hive或Casading等,它们都将连接操作视为整个实现的核心部分。


本章的代码用到的基础工具类


其他章节也可能用到:)


JobBuilder


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import org.apache.hadoop.conf.Configuration;  
  2. import org.apache.hadoop.fs.Path;  
  3. import org.apache.hadoop.mapred.FileInputFormat;  
  4. import org.apache.hadoop.mapred.FileOutputFormat;  
  5. import org.apache.hadoop.mapred.JobConf;  
  6. import org.apache.hadoop.util.Tool;  
  7.   
  8. public class JobBuilder {  
  9.   
  10.     public static JobConf parseInputAndOutput(Tool tool, Configuration conf,  
  11.             String[] args) {  
  12.         if (args.length != 2) {  
  13.             printUsage(tool, "<input><output>");  
  14.             return null;  
  15.         }  
  16.         JobConf jobConf = new JobConf(conf, tool.getClass());  
  17.         FileInputFormat.addInputPath(jobConf, new Path(args[0]));  
  18.         FileOutputFormat.setOutputPath(jobConf, new Path(args[1]));  
  19.         return jobConf;  
  20.     }  
  21.   
  22.     public static void printUsage(Tool tool, String extraArgsUsage) {  
  23.         System.err.printf("Usage:%s [genericOptions] %s\n\n", tool.getClass()  
  24.                 .getSimpleName(), extraArgsUsage);  
  25.     }  
  26. }  

NcdcRecordParser

 

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import org.apache.hadoop.io.Text;  
  2.   
  3. public class NcdcRecordParser {  
  4.     private static final int MISSING_TEMPERATURE = 9999;  
  5.   
  6.     private String year;  
  7.     private int airTemperature;  
  8.     private String quality;  
  9.   
  10.     public void parse(String record) {  
  11.         year = record.substring(1519);  
  12.         String airTemperatureString;  
  13.         // Remove leading plus sign as parseInt doesn't like them  
  14.         if (record.charAt(87) == '+') {  
  15.             airTemperatureString = record.substring(8892);  
  16.         } else {  
  17.             airTemperatureString = record.substring(8792);  
  18.         }  
  19.         airTemperature = Integer.parseInt(airTemperatureString);  
  20.         quality = record.substring(9293);  
  21.     }  
  22.   
  23.     public void parse(Text record) {  
  24.         parse(record.toString());  
  25.     }  
  26.   
  27.     public boolean isValidTemperature() {  
  28.         return airTemperature != MISSING_TEMPERATURE  
  29.                 && quality.matches("[01459]");  
  30.     }  
  31.   
  32.     public boolean isMa1formedTemperature() {  
  33.         return !quality.matches("[01459]");  
  34.     }  
  35.   
  36.     public boolean IsMissingTemperature() {  
  37.         return airTemperature == MISSING_TEMPERATURE;  
  38.     }  
  39.   
  40.     public String getYear() {  
  41.         return year;  
  42.     }  
  43.   
  44.     public int getAirTemperature() {  
  45.         return airTemperature;  
  46.     }  
  47. }  

这一篇是《Hadoop权威指南》第八章的学习笔记,好久没看Hadoop,工作中也没使用,前不久学习的东西,忘记了很多。学以致用是非常重要的,没用应用的学习,最终会忘记大部分,感兴趣的就需要多多温习了。
0 0
原创粉丝点击