簡體   English   中英

avro文件中存儲的org.apache.kafka.connect.data.Decimal如何轉換為python類型?

[英]How can a org.apache.kafka.connect.data.Decimal stored in an avro file be converted to a python type?

我正在嘗試使用Python解釋DebeziumKafka中存儲的Avro記錄

           {
              "name": "id",
              "type": {
                "type": "bytes",
                "scale": 0,
                "precision": 64,
                "connect.version": 1,
                "connect.parameters": {
                  "scale": "0"
                },
                "connect.name": "org.apache.kafka.connect.data.Decimal",
                "logicalType": "decimal"
              }
            }

我不確定這對應於哪個 Python 3 原始類型。 這個值如何反序列化?

提前致謝!

如果你看

https://insight.io/github.com/apache/kafka/blob/trunk/connect/api/src/main/java/org/apache/kafka/connect/data/Decimal.java

public static byte[] fromLogical(Schema schema, BigDecimal value) {
    if (value.scale() != scale(schema))
        throw new DataException("BigDecimal has mismatching scale value for given Decimal schema");
    return value.unscaledValue().toByteArray();
}

如您所見,它使用 BigDecimal,相當於 Python 中的Decimal

Java 的 BigDecimal 的 python 是什么?

因此,在這種情況下,您應該尋找 Decimal。

第 2 部分 - 反序列化

關於反序列化,我需要反饋來更新答案。 到目前為止,您如何在其他領域做到這一點?

org.apache.kafka.connect.data.Decimal是未縮放整數的 base64 編碼字節表示。 為了將此值轉換為Decimal ,您需要將 base64 字符串解碼為字節,獲取整數,然后通過parameters.scale值對其進行縮放。

這個架構:

{
  "type": "bytes",
  "name": "org.apache.kafka.connect.data.Decimal",
  "version": 1,
  "parameters": {
    "scale": "9",
    "connect.decimal.precision": "38"
  },
  "field": "amount"
}

可以使用以下代碼段進行轉換(在Pyfiddle嘗試):

ctx = decimal.Context()
ctx.prec = 38  # connect.decimal.precision = 38
result = ctx.create_decimal(
    int.from_bytes(base64.b64decode("GZ6ZFQvYpA=="), byteorder='big')
) / 10 ** 9  # scale = 9

當我對負數使用其他答案時,它會給出錯誤的結果。 例如 -20.62 數字被 debezium 轉換為“+CA=”到 kafka

我從下面的鏈接中找到了解決方案,然后像這樣更改。

import decimal
import base64
def big_decimal_to_decimal(big_decimal, scale, precision):
    bytes_val = base64.decodebytes(big_decimal.encode())
    bval = "".join("{0:08b}".format(c) for c in bytes_val)
    intval = int(bval, 2)
    if bytes_val[0] & 0x70 != 0:
        intval -= int('1' + '00' * len(bytes_val), 16)
    return intval/(10**scale)

鏈接: 將 base64 編碼字節數組解碼為(負)十進制值(Java 到 Python)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM