我有一个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 )兼容?
发布于 2016-01-19 19:38:20
让我们从免责声明开始。虽然“逻辑类型”部分出现在2014年前后的规范中,但还没有任何Avro Java版本支持它。
您可以决定声明符合规范的模式,并将正确的字节推入字段,但是Avro Java不会对您有所帮助(就像省略了与逻辑类型相关的字段一样)。
如何将BigDecimal值转换为预期的ByteBuffer
这些文件指出:
十进制逻辑类型注释Avro字节或固定类型。字节数组必须包含以大端字节顺序表示的未缩放的整数值的二补表示形式。刻度是固定的,并使用属性指定。
它可以用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,没有什么是免费的。您必须编写自己的(反)序列化程序,代码生成和反射不支持此结构。使用它的唯一原因是遵守规范,并希望将来的Avro版本将使您的生活更轻松。
Avro 1.8.0-rc2包含一些支持逻辑类型和引入新逻辑类型的代码。似乎所有逻辑类型(参见Conversion和Conversions)都提供了(反)序列化程序,并且转换已经插入到GenericData中。这意味着当您询问字段的值时,您将收到一个BigDecimal实例。如果您正确地注释字段,ReflectData似乎也能够生成预期的模式(但是AFAIK没有为逻辑类型创建专门的注释)。
然而,我不清楚avro编译器/ codegen是否已经被更新以支持逻辑类型。
https://stackoverflow.com/questions/34866793
复制相似问题