Python3 Apache Avro 1.8.2别名不生效问题咨询
Avro Python库别名未映射字段值的问题解析
问题背景
你写的Avro程序里,写入数据时用的是name字段,读取时想通过aliases: ["name"]让first_name继承原字段的值,但结果first_name全是默认的空字符串,完全没拿到"Alyssa"和"Ben"。先看你代码里的关键部分:
写入Schema
write_schema = avro.schema.parse(json.dumps({ "namespace": "example.avro", "type": "record", "name": "User", "fields": [ {"name": "name", "type": "string"}, {"name": "favorite_number", "type": ["int", "null"]}, {"name": "favorite_color", "type": ["string", "null"]} ] }))
读取Schema
read_schema = avro.schema.parse(json.dumps({ "namespace": "example.avro", "type": "record", "name": "User", "fields": [ {"name": "first_name", "type": "string", "default": "", "aliases": ["name"]}, {"name": "favorite_number", "type": ["int", "null"]}, {"name": "favorite_color", "type": ["string", "null"]} ] }))
出错的读取逻辑
reader = DataFileReader(open("users.avro", "rb"), DatumReader(write_schema, read_schema))
Avro别名机制到底怎么工作?
Avro的aliases就是用来处理Schema演化时的字段名兼容的,核心逻辑很简单:
- 读取数据时,读取Schema里的字段如果有
aliases,Avro会拿着这些别名去写入Schema里找对应的字段名,找到就把值映射过来。 - 别名的匹配要求字段类型完全兼容(比如你这里
string对应string是没问题的)。
你的预期完全符合Avro规范——别名就是干这个用的,问题出在代码细节上!
你代码里的致命错误:DatumReader参数顺序搞反了
DatumReader的构造函数参数顺序是先读Schema,后写Schema,也就是:
DatumReader(read_schema=None, write_schema=None)
你把write_schema放在第一个位置,read_schema放第二个,导致库根本没机会用读取Schema里的别名去匹配写入Schema的字段,只能用first_name的默认值填空。
修正后的代码
只需要调换DatumReader的参数顺序:
reader = DataFileReader(open("users.avro", "rb"), DatumReader(read_schema, write_schema))
运行之后,users的内容就会变成你想要的:[{'favorite_color': None, 'favorite_number': 256, 'first_name': 'Alyssa'}, {'favorite_color': 'red', 'favorite_number': 7, 'first_name': 'Ben'}]
额外提醒
- 一定要保证读取Schema的字段类型和写入Schema对应字段的类型兼容,比如写入是
["int", "null"],读取就不能改成单纯的int(除非给读取字段加默认值)。 - 别名可以是多个,比如
aliases: ["name", "username"],只要写入Schema里有其中一个字段名,就能映射成功。
内容的提问来源于stack exchange,提问作者user2302244
相关产品推荐
相关产品推荐

