我有一个avro架构,其中包含以下字段之一
{
"name" : "currency",
"type" : ["null","bytes"],
"logicalType": "decimal",
"precision": 9,
"scale": 4
},
我运行了avro-tools jar来创建表示架构的java文件。这产生了类似于public java.nio.ByteBuffer currency;
在我的代码中,我将使用BigDecimal
类型中的货币值。
在创建此类的实例时,如何将BigDecimal
值转换为预期的ByteBuffer
?我可以使用ByteBuffer.toByteArray()
或者我是否需要做一些特别的事情以确保它与avro(以及可能正在读取数据的Impala等其他工具)兼容?
答案 0 :(得分:4)
让我们从免责声明开始。虽然"逻辑类型"部分出现在大约2014年的规范中,任何Avro Java版本都不支持它。
您可以决定声明符合规范的模式并将正确的字节推送到字段中,但Avro Java不会帮助您(就像您省略了逻辑类型相关字段一样)。
文档说明:
十进制逻辑类型注释Avro字节或固定类型。字节数组必须包含 big-endian字节顺序中未缩放整数值的二 - 补码表示。比例是固定的,并使用属性指定。
可以用Java翻译(从Avro 1.8.0-rc2粘贴的副本):
public ByteBuffer toBytes(BigDecimal value, Schema schema, LogicalType type)
{
int scale = ((LogicalTypes.Decimal) type).getScale();
if (scale != value.scale()) {
throw new AvroTypeException("Cannot encode decimal with scale " +
value.scale() + " as scale " + scale);
}
return ByteBuffer.wrap(value.unscaledValue().toByteArray());
}
你可以阅读BigDecimal& BigInteger的Javadoc检查value.unscaledValue().toByteArray()
是否符合规范。
以类似的方式,您可以使用以下代码反序列化字段:return new BigDecimal(new BigInteger(bytes), scale);
如序言中所述,如果您使用的是Avro 1.7,则不会免费提供任何内容。你必须编写自己的(de)序列化器,代码生成和反映不支持这种结构。使用它的唯一原因是遵守规范,并希望未来的Avro版本能让您的生活更轻松。
Avro 1.8.0-rc2包含一些支持逻辑类型和引入新逻辑类型的代码。似乎(de)序列化器是为所有逻辑类型提供的(请参阅Conversion
和Conversions
),并且转换已插入GenericData。这意味着当您询问字段的值时,您将收到BigDecimal
实例。如果正确注释字段,ReflectData似乎也能够产生预期的模式(但是AFAIK没有为逻辑类型创建专用注释)。
但是,我不清楚avro-compiler / codegen是否已更新为支持逻辑类型。