我的所有程序都使用hadoop的新MR1接口(org.apache.hadoop.mapreduce)编写,所以我也想使用avro的新org.apache.avro.mapreduce。但它对我不起作用。
程序接收avro数据的输入并输出相同的数据。 我的程序背后的主要思想是将hadoop的Mapper和Reducer子类化为avro包装的键/值。 这是我的工作司机的一块:
AvroJob.setInputKeySchema(job, NetflowRecord.getClassSchema());
AvroJob.setOutputKeySchema(job, NetflowRecord.getClassSchema());
job.setMapperClass(MyAvroMap.class);
job.setReducerClass(MyAvroReduce.class);
job.setInputFormatClass(AvroKeyInputFormat.class);
job.setOutputFormatClass(AvroKeyOutputFormat.class);
job.setMapOutputKeyClass(AvroKey.class);
job.setMapOutputValueClass(AvroValue.class);
job.setOutputKeyClass(AvroKey.class);
job.setOutputValueClass(NullWritable.class);
MyAvroMap和MyAvroReduce子类的定义分别是
public static class MyAvroMap extends Mapper<AvroKey<NetflowRecord>, NullWritable,
AvroKey<CharSequence>, AvroValue<NetflowRecord>>{ ... }
public static class MyAvroReduce extends Reducer<AvroKey<CharSequence>, AvroValue<NetflowRecord>,
AvroKey<NetflowRecord>, NullWritable>{ ... }
有效的NetflowRecord是我的avro记录类。我得到了运行异常
java.lang.ClassCastException: class org.apache.avro.hadoop.io.AvroKey
通过阅读hadoop和avro的源代码, 我发现JobConf抛出异常以确保 map key是WritableComparable的子类,如下所示(hadoop1.2.1,line759)
WritableComparator.get(getMapOutputKeyClass().asSubclass(WritableComparable.class));
但avro显示AvroKey和AvroValue只是一个简单的包装器没有子类化hadoop的Writable *接口。
我相信,即使没有测试,我也可以使用旧的mapred接口,但它不是我想要的。 你能给我一些关于用纯org.apache.avro.mapreduce接口编程的例子或解释吗?
此致
贾敏
答案 0 :(得分:5)
经过艰苦搜索,借助此补丁https://issues.apache.org/jira/browse/AVRO-593, 我发现每个AvroKey和AvroValue包装器必须在作业配置中具有模式定义。 这就是我错过的。
这里我有两个选择:
如果MyAvroMap和MyAvroReduce保持不变,我必须为CharSequence定义一个模式,并使用AvroJob为Mapper输出声明此模式,例如
AvroJob.setMapOutputKeySchema(job,&lt;“defined-schema-for-charsequence”&gt;); AvroJob.setMapOutputValueSchema(job,NetflowRecord.getClassSchema());
通过将Mapper输出键/值更改为Text / AvroValue,我只需要为Mapper输出值添加模式声明,例如
job.setMapOutputKeyClass(Text.class); AvroJob.setMapOutputValueSchema(job,NetflowRecord.getClassSchema());
使用mapreduce API,我们不再需要继承AvroMapper和AvroReducer。 在这里,我在代码中实现了没有附加模式定义的option2。
贾敏