Hadoop / MapReduce:读取和编写从DDL生成的类

时间:2010-05-16 21:48:47

标签: hadoop mapreduce ddl

有人可以通过使用DDL生成的类来读取和写入数据的基本工作流程吗?

我使用DDL定义了一些类似结构的记录。例如:

  class Customer {
     ustring FirstName;
     ustring LastName;
     ustring CardNo;
     long LastPurchase;
  }

我编译了这个以获得一个Customer类并将其包含在我的项目中。我可以很容易地看到如何将它用作映射器和缩减器的输入和输出(生成的类实现Writable),但不是如何将其读取和写入文件。

org.apache.hadoop.record 包的JavaDoc讨论了以二进制,CSV或XML格式序列化这些记录。我该怎么做呢?假设我的reducer生成IntWritable键和Customer值。使用什么OutputFormat以CSV格式写入结果?如果我想对它们进行分析,我将使用什么InputFormat来读取后面的结果文件?

1 个答案:

答案 0 :(得分:1)

好的,所以我想我已经弄明白了。我不确定这是否是最直接的方式,所以如果你知道更简单的工作流程,请纠正我。

从DDL生成的每个类都实现了Record接口,因此提供了两种方法:

序列化(RecordOutput out)用于写入 反序列化(RecordInput in)以便阅读

RecordOutput RecordInput org.apache.hadoop.record 包中提供的实用程序接口。有一些实现(例如 XMLRecordOutput BinaryRecordOutput CSVRecordOutput

据我所知,您必须实现自己的 OutputFormat InputFormat 类才能使用它们。这很容易做到。

例如,我在原始问题中谈到的OutputFormat(以CSV格式写入Integer键和Customer值的那个)将实现如下:


  private static class CustomerOutputFormat 
    extends TextOutputFormat<IntWritable, Customer> 
  {

    public RecordWriter<IntWritable, Customer> getRecordWriter(FileSystem ignored,
      JobConf job,
      String name,
      Progressable progress)
    throws IOException {
      Path file = FileOutputFormat.getTaskOutputPath(job, name);
      FileSystem fs = file.getFileSystem(job);
      FSDataOutputStream fileOut = fs.create(file, progress);
      return new CustomerRecordWriter(fileOut);
    }   

    protected static class CustomerRecordWriter 
      implements RecordWriter<IntWritable, Customer> 
    {

      protected DataOutputStream outStream ;

      public AnchorRecordWriter(DataOutputStream out) {
        this.outStream = out ; 
      }

      public synchronized void write(IntWritable key, Customer value) throws IOException {

        CsvRecordOutput csvOutput = new CsvRecordOutput(outStream);
        csvOutput.writeInteger(key.get(), "id") ;
        value.serialize(csvOutput) ; 
      }

      public synchronized void close(Reporter reporter) throws IOException {
        outStream.close();
      }
    }
  }

创建InputFormat大致相同。因为csv格式是每行一个条目,我们可以在内部使用LineRecordReader完成大部分工作。



private static class CustomerInputFormat extends FileInputFormat<IntWritable, Customer> {

  public RecordReader<IntWritable, Customer> getRecordReader(
    InputSplit genericSplit, 
    JobConf job,
    Reporter reporter)
  throws IOException {

    reporter.setStatus(genericSplit.toString());
    return new CustomerRecordReader(job, (FileSplit) genericSplit);
  }

  private class CustomerRecordReader implements RecordReader<IntWritable, Customer> {

    private LineRecordReader lrr ;

    public CustomerRecordReader(Configuration job, FileSplit split) 
    throws IOException{
      this.lrr = new LineRecordReader(job, split);    
    }

    public IntWritable createKey() {
      return new IntWritable();
    }

    public Customer createValue() {
      return new Customer();
    }

    public synchronized boolean next(IntWritable key, Customer value)
    throws IOException {

      LongWritable offset = new LongWritable() ;
      Text line = new Text() ;

      if (!lrr.next(offset, line))
        return false ;

      CsvRecordInput cri = new CsvRecordInput(new      
        ByteArrayInputStream(line.toString().getBytes())) ;
      key.set(cri.readInt("id")) ;
      value.deserialize(cri) ;

      return true ;
    }

    public float getProgress() {
      return lrr.getProgress() ;
    }

    public synchronized long getPos() throws IOException {
      return lrr.getPos() ;
    }

    public synchronized void close() throws IOException {
      lrr.close();
    }
  }
}