使用GenericData.Record进行Avro Schema Evolution - Mapreduce进程

时间:2016-05-06 21:51:26

标签: java hadoop mapreduce apache-pig avro

我有一个mapreduce程序,它从avro数据中读取数据,处理它并输出avro数据。我有这个avro数据的架构,比方说4列。 我使用GenericData.Record来编写avro数据。

现在我使用具有5列的模式在此数据之上创建一个pig关系。第5列是新的,具有avsc文件中定义的默认值。 根据我的理解,我应该能够使用带有一个附加列的新模式读取旧数据(使用4列生成)。 相反,我收到一条错误消息,指出 - 尝试访问不存在的列。

我缺少什么?

Mapreduce驱动程序代码

Job job = Job.getInstance(getConf());  
job.setJarByClass(DeltaCaptureMRJobDriverWithSameSchema.class);
job.setJobName("CDC");
job.getConfiguration().setBoolean("mapreduce.input.fileinputformat.input.dir.recursive", true);

//This is required to use avro-1.7.6 and above
job.getConfiguration().set("mapreduce.job.user.classpath.first", "true");
FileInputFormat.addInputPaths(job, args[0]);
FileOutputFormat.setOutputPath(job, new Path(args[1]));

job.setInputFormatClass(AvroKeyInputFormat.class);
job.setMapperClass(DeltaCaptureMapperMultiPaths.class);
Schema schema = new Schema.Parser().parse(new File(args[2]));
AvroJob.setInputKeySchema(job, schema);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(AvroValue.class);
AvroJob.setMapOutputValueSchema(job, schema);

job.setOutputFormatClass(AvroKeyOutputFormat.class);
job.setReducerClass(DeltaCaptureReducerMultiPaths.class);
AvroJob.setOutputKeySchema(job, schema);
job.setOutputKeyClass(AvroKey.class);

return (job.waitForCompletion(true) ? 0 : 1);

映射器代码

public class DeltaCaptureMapperMultiPaths extends Mapper<AvroKey<GenericData.Record>, NullWritable, Text , AvroValue<GenericData.Record>> {

    private static final Logger LOG = Logger.getLogger(DeltaCaptureMapperMultiPaths.class);

    @Override
    public void map(AvroKey<GenericData.Record> key, NullWritable value, Context context) throws IOException, InterruptedException {
        try {
            System.out.println("Specific Record - " + key);
            System.out.println("Datum :: " + key.datum());
            System.out.println("Schema :: " + key.datum().getSchema());
            AvroValue<GenericData.Record> outValue = new AvroValue<GenericData.Record>(key.datum());
            System.out.println("Generic Record (out) - " + key.datum());
            context.write(new Text(key.datum().get("id") +""), outValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

减速机代码

public class DeltaCaptureReducerMultiPaths extends Reducer<Text, AvroValue<GenericData.Record>, AvroKey<GenericData.Record>, NullWritable> {

    @Override
    public void reduce(Text  key, Iterable<AvroValue<GenericData.Record>> values, Context context) throws IOException, InterruptedException {
        for(AvroValue<GenericData.Record> value : values) {
            AvroKey<GenericData.Record> outKey = new AvroKey<GenericData.Record>(value.datum());
            context.write(outKey, NullWritable.get());
        }
    }
}

让我们说MR输出到/ etl / out。现在,以下猪脚本失败了,我在开头描述了错误。

a= LOAD '/etl/out' USING org.apache.pig.builtin.AvroStorage('hdfs:///etl/test.avsc')
b = FOREACH a GENERATE $0,$1,$2,$3,$4;

hdfs:///etl/test.avsc中有5个字段(第5个是新的)。

1 个答案:

答案 0 :(得分:0)

正如所怀疑的那样,问题实际上与AvroStorage的使用方式有关。用法是: a = LOAD&#39; / etl / out&#39;使用org.apache.pig.builtin.AvroStorage(&#39; test&#39;,&#39; -schemafile file:///etl/test.avsc'),假设测试。 avsc位于本地文件系统中。保持avd在hdfs也应该工作,但我没有到处测试。我不确定为什么没有明确的文件!!!!