MultipleOutputs(二)

       在使用Map-Reduce处理大量数据时,可能有些记录同别的记录不一样,比如这些记录是不符合规范的,可以简单丢弃这些数据。但是如果想保存这些出错的记录以分析错误的原因,这个时候就不太方便了,如果Hadoop提供一个分布式的日志系统就好了,直接使用API将这些错误的记录写入日志中。我先想到一个比较简单的方法,就是实现自己的partitioner,将错误的记录保存到最后一个分区文件中。代码如下所示:

 //将所有不正常的记录都保存到最后一个分区中

 public static class ErrorPartitioner implements Partitioner<Text, Text> {

  @Override
  public void configure(JobConf conf) {
  }

  @Override
  public int getPartition(Text key, Text value, int numPartitions) {

   if (key.toString().startsWith("error"))
   {
    //写到最后一个分区中
    return numPartitions-1;
   }
   else
   {
    //对于正常的记录直接使用HashPartitioner来指定分区
    return ((key.hashCode() & Integer.MAX_VALUE) % (numPartitions-1));
   }
  }
 }

       这种方法确实可堪使用,但是不够专业吧。后来在公司的高人指点下才知道MultipleOutputs这个类,写代码试了试。这种方法比之前自己写Partitioner更加方便灵活。使用步骤如下:

1、首先在给JobConf添加output文件,如下:

MultipleOutputs.addNamedOutput(conf, "Prefix1", TextOutputFormat.class, Text.class, IntWritable.class);
MultipleOutputs.addNamedOutput(conf, "Prefix2", TextOutputFormat.class, Text.class, IntWritable.class);
..............
JobClient.runJob(conf);

2、在map类或者reduce类中加入如下代码:

public static MultipleOutputs mos;

public void configure(JobConf job) {
 mos = new MultipleOutputs(job);
}

3、在map或者reduce方法中象下面这样使用之。
   if (key.toString().length() < 3)
   {
    mos.getCollector(file1, reporter).collect(
                  key,
                  new IntWritable(sum));
   }
   else
   {
    mos.getCollector(file2, reporter).collect(
                  key,
                  new IntWritable(sum));
   }

4、最后一定记得实现Mapper和Reducer类的close方法,在该方法中调用"mos.close();",否则不会有数据写入到文件中。
        生成的文件形如"Prefix1-m-00001",前缀自己可以设置。今天还学会判断记录所在的文件,有时候这个信息比较有用。一共有两种方法可以知道当前处理的记录所属的文件。

1、通过JobConf来获得。

        public void configure(JobConf job) {
            path = job.get("map.input.file");
        }

2、上面这种方法需要实现configure方法,更加便利的方法是:

String path = ((FileSplit) reporter.getInputSplit()).getPath().toString();

你可能感兴趣的:(MultipleOutputs(二))