python-将avro字节逻辑类型decimal反序列化为decimal

python-将avro字节逻辑类型decimal反序列化为decimal,python,binary,deserialization,avro,apache-kafka-connect,Python,Binary,Deserialization,Avro,Apache Kafka Connect,我正在尝试使用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(

我正在尝试使用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”

我在下面发布了此列的元数据以及字节值(预期实际值都是1000的倍数,小于25000)。该文件是使用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
字节值:

 {
                            "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
期望值:

 {
                            "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的库

请参阅以下链接:

由于某些原因,fastavro软件包在同一个文件上作为默认软件包工作。 我最后使用了下面的代码。仍然不确定是否有办法直接使用avro库来解决这个问题,或者对上面问题中发布的输出进行反序列化

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

为此,您需要使用
fastavro
库。
avro
avro-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')
例:

参考文献:


我现在意识到我不能使用fastavro,因为我需要在AWS上部署,因此只能使用纯Python编写的库。在这种情况下,我认为目前唯一的选择可能是使用fastavro并删除Cython部分。该库同时具有Python和Cython实现,因此如果您删除Cython部分,您应该是lef使用一个纯python解决方案将不会有问题。谢谢。删除cpython部分效果很好。@oli5679您能分享一下您的解决方案吗?