有人可以通过使用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来读取后面的结果文件?
答案 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();
}
}
}