嗨,正在寻找 API 来使用我拥有的 Pojos 编写 parquest。我能够使用反射生成 avro 架构,然后使用 AvroSchemaConverter 创建镶木地板架构。此外,我无法找到将 Pojos 转换为 GenericRecords (avro) 的方法,否则我本可以使用 AvroParquetWriter 将 Pojos 写入镶木地板文件。有什么建议么 ?
3 回答
如果你想通过 avro 你有两个选择:
1) 让 avro 生成您的 pojos(请参阅此处的教程)。生成的 pojo 扩展了 SpecificRecord,然后可以与 AvroParquetWriter 一起使用。
2) 自己编写从 pojo 到 GenericRecord 的转换。您可以手动执行此操作,或者更通用的解决方案是使用反射。但是,当我尝试读取数据时,我遇到了这种方法的困难。根据提供的模式,avro 在类路径中找到了 pojo,并尝试实例化一个 SpecificRecord 而不是 GenericRecord。由于这个原因,我选择了选项 1。
Parquet 现在也支持直接写 pojo。这是 parquet github 页面上的拉取请求。但是,我认为这还不是正式版本的一部分。换句话说,我没有在 maven 中找到这段代码。
免责声明:以下代码是我赶时间时编写的。它效率不高,未来版本的镶木地板肯定会更直接地解决这个问题。话虽如此,这是一种轻量级的低效方法,可以满足您的需求。策略是 POJO -> AVRO -> PARQUET
- POJO -> AVRO:通过反射声明一个模式。根据模式声明作者和读者。在转换时将对象写入字节流并将其作为 avro 读回。
- AVRO -> Parquet:使用 parquet-me 项目中包含的 AvroParquetWriter。
private static final Schema avroSchema = ReflectData.AllowNull.get().getSchema(YOURCLASS.class);
private static final ReflectDatumWriter<YOURCLASS> reflectDatumWriter = new ReflectDatumWriter<>(avroSchema);
private static final GenericDatumReader<Object> genericRecordReader = new GenericDatumReader<>(avroSchema);
public GenericRecord toAvroGenericRecord() throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
reflectDatumWriter.write(this, EncoderFactory.get().directBinaryEncoder(bytes, null));
return (GenericRecord) genericRecordReader.read(null, DecoderFactory.get().binaryDecoder(bytes.toByteArray(), null));
}
还有一件事:parquet writers 目前似乎对空字段非常严格。在尝试写入镶木地板之前,请确保您的所有字段都不为空
我无法找到现有的解决方案,所以我自己实现了它。这是实现的链接:https ://gist.github.com/alexeygrigorev/eab72e40c6051e0163a6693054906d66
简而言之,它执行以下操作:
- 使用反射从 pojo 中获取 Avro 模式
- 使用模式和反射将 pojos 转换为
GenericRecord
对象 - 如果 pojo 包含其他 pojo 或 pojo 列表,则递归应用反射