2016-01-19 57 views
4

我有一個Avro的模式,它包括以下的領域如何從ByteBuffer轉換爲Avro字節?

{ 
    "name" : "currency", 
    "type" : ["null","bytes"], 
    "logicalType": "decimal", 
    "precision": 9, 
    "scale": 4 
}, 

我跑的Avro工具罐子創建Java文件來表示的模式之一。這產生了如下屬性:public java.nio.ByteBuffer currency;

在我的代碼中的其他地方,我將使用BigDecimal類型的貨幣值。

當我創建此類的實例時,如何將BigDecimal的值轉換爲預期的ByteBuffer?我可以只使用ByteBuffer.toByteArray()還是需要做特別的事情才能確保它與avro(以及其他可能正在讀取數據的Impala等工具)兼容?

回答

4

讓我們從一個免責聲明開始。雖然2014年左右規範中出現了「邏輯類型」部分,但任何Avro Java版本都不支持該部分。

您可以決定聲明符合規範的模式,並將正確的字節推送到字段中,但Avro Java不會幫助您(它完全像是如果省略了與邏輯類型相關的字段)。

如何將BigDecimal值轉換爲預期的字節緩衝區

的文檔狀態:

十進制邏輯型詮釋的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,則無法免費獲得。您必須編寫自己的(de)序列化程序,代碼生成&反映不支持此構造。使用它的唯一理由是遵守規範,並希望未來的Avro版本能讓您的生活更輕鬆。

Avro 1.8.0-rc2包含一些代碼來支持邏輯類型並引入新的邏輯類型。看起來,(de)序列化器是爲所有邏輯類型提供的(請參閱ConversionConversions),並且已將轉換插入到GenericData中。這意味着當您詢問該字段的值時,您將收到一個BigDecimal實例。如果您正確註釋該字段(但AFAIK沒有爲邏輯類型創建專用註釋),ReflectData似乎也能夠生成預期的模式。

但是,我不清楚avro-compiler/codegen是否已更新爲支持邏輯類型。