簡體   English   中英

python - 將avro字節邏輯類型十進制反序列化為十進制

[英]python - deserialise avro byte logical type decimal to decimal

我正在嘗試使用 python avro 庫(python 2)讀取 Avro 文件。 當我使用以下代碼時:

import avro.schema
from avro.datafile import DataFileReader, DataFileWriter
from avro.io import DatumReader, DatumWriter, BinaryDecoder
reader = DataFileReader(open("filename.avro", "rb"), DatumReader())
schema = reader.meta

然后它正確讀取每一列,除了保留為字節的列,而不是預期的十進制值。

如何將此列轉換為預期的十進制值? 我注意到文件的元數據將列標識為 'type' : 'bytes',但 'logicalType' :'decimal'

我在此列的元數據以及字節值(預期的實際值都是小於 25,000 的 1,000 的倍數)下方發布。該文件是使用 Kafka 創建的。

元數據:

 {
                            "name": "amount",
                            "type": {
                                "type": "bytes",
                                "scale": 8,
                                "precision": 20,
                                "connect.version": 1,
                                "connect.parameters": {
                                    "scale": "8",
                                    "connect.decimal.precision": "20"
                                },
                                "connect.name": "org.apache.kafka.connect.data.Decimal",
                                "logicalType": "decimal"
                            }
                        }

字節值:

'E\xd9d\xb8\x00'
'\x00\xe8\xd4\xa5\x10\x00'
'\x01\x17e\x92\xe0\x00'
'\x01\x17e\x92\xe0\x00'

預期值:

3,000.00
10,000.00
12,000.00
5,000.00

我需要在部署在 AWS 上的 Lambda 函數中使用它,因此不能使用 fast_avro 或其他使用 C 而不是純 Python 的庫。

請參閱以下鏈接: https : //pypi.org/project/fastavro/ https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-python-libraries.html

為此,您需要使用fastavro庫。 avroavro-python3庫在發布時都不支持邏輯類型。

您可以使用它來將字節字符串解碼為十進制。 這會將值填充到下一個最高字節結構,以便適合所有可能的值。

import struct
from decimal import Decimal

def decode_decimal(value, num_places):
    value_size = len(value)
    for fmt in ('>b', '>h', '>l', '>q'):
        fmt_size = struct.calcsize(fmt)
        if fmt_size >= value_size:
            padding = b'\x00' * (fmt_size - value_size)
            int_value = struct.unpack(fmt, padding + value)[0]
            scale = Decimal('1') / (10 ** num_places)
            return Decimal(int_value) * scale
    raise ValueError('Could not unpack value')

前任:

>>> decode_decimal(b'\x00\xe8\xd4\xa5\x10\x00', 8)
Decimal('10000.00000000')
>>> decode_decimal(b'\x01\x17e\x92\xe0\x00', 8)
Decimal('12000.00000000')
>>> decode_decimal(b'\xb2\xb4\xe7\x84', 4)  # Negative value
Decimal('-129676.7100')

參考:

https://avro.apache.org/docs/1.10.2/spec.html#Decimalhttps://docs.python.org/3/library/struct.html#format-characters

出於某種原因,fastavro 包在同一個文件上默認工作。 我最終使用了下面的代碼。 仍然不確定是否有辦法直接使用 avro 庫解決這個問題,或者反序列化上面問題中發布的輸出。

import fastavro
with open("filename.avro", 'rb') as fo: 
    for record in fastavro.reader(fo): 
        print(record) 

暫無
暫無

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

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