[Hadoop编程实践]一个实用、清晰的MapReduce程序

今天写的日志合并MapReduce程序,重新梳理了一遍写一个MapReduce Job的要点:

1. 参数获取。

我一般都会在参数中包含这几项:输入文件路径、工作路径(.finish文件所在的目录)、输出文件路径(结果数据所在的路径,在实际工程中,一般和工作路径不同)。还有一个wait/submit参数,用来说明Job是通过waitForCompletion还是submit的方式提交,waitForCompletion在测试和调试时用,submit在生产环境中用。

2. 参数检查

各种参数的格式检查,通不过就直接退出,这一步要严格。

3. 创建Job

4. 设定mapper、reducer

可能还需要设定partitioner,sort comparator, grouping comparator,因任务的复杂程度而定。

5. 设定输入和工作路径

注意FileOutputFormat.setOutputPath(job, new Path(workingDir));设置的是workingDir,在实践中一般都将workingDir和最终数据的outputDir分开。主要是因为workingDir得到的数据都是part-00000这样的形式,不能自己命名。所以一般会在最后reducer中自己用FileWriter去创建结果数据文件,不用context.write.

6. 设定输入和输出文件格式

7. 设置配置项

为了在mapper、reducer以及Job的其他worker之间共享一些简单的数据,可以使用JobConf. 如果要共享复杂、量大的数据,可以使用DistributedCache。在最近的实践中,有用序列化文件+DistributedCache在各个Job worker之间共享HashMap,List以及其他自定义数据结构的经验,可行。

8. 提交Job

 

代码如下,敬请批评。

  1 import java.io.IOException;
  2 import java.util.regex.Matcher;
  3 import java.util.regex.Pattern;
  4 
  5 import org.apache.hadoop.conf.Configuration;
  6 import org.apache.hadoop.fs.Path;
  7 import org.apache.hadoop.mapred.JobConf;
  8 import org.apache.hadoop.mapreduce.Job;
  9 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
 10 import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
 11 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
 12 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
 13 import org.apache.hadoop.util.GenericOptionsParser;
 14 
 15 import com.hadoop.compression.lzo.LzopCodec;
 16 
 17 /**
 18  * MapReduce job to combine all hourly logs from different data-collection servers
 19  * @author lsyang, 20130507
 20  */
 21 public class HourlyLogCombine {
 22     private static String RAW_FILE_PREFIX = "post_";
 23     private static String RAW_FILE_POSTFIX = ".log";
 24     
 25     public static String JOB_CONF_DATE = "HourlyLogCombine.Date";
 26     public static String JOB_CONF_HOUR = "HourlyLogCombine.Hour";
 27     public static String JOB_CONF_OUTDIR = "HourlyLogCombine.OutDir";
 28     
 29     private static void showHelpAndExit(String info) {
 30         System.err.println("Usage: HourlyLogCombine <Date: yyyyMMdd> <Hour: hh> " +
 31                 "<RowLogDir, e.g. /user/click_tracker/appbi/data/raw/> " +
 32                 "<workingDir, e.g. /user/click_tracker/appbi/working/>" +
 33                 "<CombineLogDir, e.g. /user/click_tracker/appbi/data/hourly_combine/>" +
 34                 "<wait or submit>");
 35         if(info != null && !info.isEmpty()) {
 36             System.err.println("Error: " + info);
 37         }
 38         System.exit(0);
 39     }
 40     
 41     private static void checkDate(String date) {
 42         String regex = "^(20\\d\\d)(0\\d|1[012])(0[1-9]|[12][0-9]|3[01])$";
 43         Pattern pattern = Pattern.compile(regex);
 44         Matcher matcher = pattern.matcher(date);
 45         if (!matcher.find()) {
 46             showHelpAndExit("wrong date format.");
 47         }
 48     }
 49 
 50     private static void checkHour(String hour) {
 51         String regex = "^[0-1]\\d|2[0-3]$";
 52         Pattern pattern = Pattern.compile(regex);
 53         Matcher matcher = pattern.matcher(hour);
 54         if (!matcher.find()) {
 55             showHelpAndExit("wrong hour format.");
 56         }
 57     }
 58     
 59     private static boolean checkWaitOrSubmit(String waitORsubmit) {
 60         if (waitORsubmit.equalsIgnoreCase("wait")) {
 61             return true;
 62         } else if (waitORsubmit.equalsIgnoreCase("submit")) {
 63             return false;
 64         } else {
 65             showHelpAndExit("wait or submit: please check the spelling.");
 66             return false;
 67         }
 68     }
 69     
 70     public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
 71         // get the application-specific arguments
 72         Configuration conf = new Configuration();
 73         String[] params = new GenericOptionsParser(conf, args).getRemainingArgs();
 74         if(params.length != 6) {
 75             showHelpAndExit("6 params needed.");
 76         }
 77         
 78         // parameters
 79         String date = params[0];
 80         String hour = params[1];
 81         String rawLogHome = params[2];
 82         String workingHome = params[3];
 83         String combinedLogHome = params[4];
 84         String waitORsubmit = params[5];
 85         if (!rawLogHome.endsWith("/")) rawLogHome += "/";
 86         if(!combinedLogHome.endsWith("/")) combinedLogHome += "/";
 87         
 88         // check parameters
 89         checkDate(date);
 90         checkHour(hour);
 91         boolean wait = checkWaitOrSubmit(waitORsubmit);
 92         
 93         // get input files
 94         String inputFiles = rawLogHome + "*/" + date + "/" + RAW_FILE_PREFIX + date + "_" + hour + RAW_FILE_POSTFIX;
 95         // get working dir, where the .finish file resides
 96         String workingDir = workingHome + date + "/" + hour + "/";
 97         // get output dir, where the combined log file resides
 98         String outDir = combinedLogHome + date + "/";
 99         
100         // create a mapreduce job
101         Job job = new Job(conf, "HourlyLogCombine");
102         job.setJarByClass(HourlyLogCombine.class);
103         
104         // set mapper, partitioner and reducer
105         job.setMapperClass(HourlyLogCombineMapper.class);
106         job.setPartitionerClass(HourlyLogCombinePartitioner.class);
107         job.setReducerClass(HourlyLogCombineReducer.class);
108         
109         // set input and output dir
110         FileInputFormat.addInputPath(job, new Path(inputFiles));
111         FileOutputFormat.setOutputPath(job, new Path(workingDir));
112         
113         // set input and output file format
114         job.setInputFormatClass(TextInputFormat.class);
115         job.setOutputFormatClass(TextOutputFormat.class);
116         TextOutputFormat.setCompressOutput(job, true);
117         TextOutputFormat.setOutputCompressorClass(job, LzopCodec.class);
118         
119         // set configurations
120         JobConf jobConf = (JobConf)job.getConfiguration();
121         jobConf.set(JOB_CONF_DATE, date);
122         jobConf.set(JOB_CONF_HOUR, hour);
123         jobConf.set(JOB_CONF_OUTDIR, outDir);
124         
125         // run the job
126         if (wait) {
127             job.waitForCompletion(true);
128         } else {
129             job.submit();
130         }
131     }
132 }

 

posted on 2013-05-07 18:36  静静的三娃  阅读(1978)  评论(3编辑  收藏  举报

导航