AVRO 模式可选字段不兼容
Posted
技术标签:
【中文标题】AVRO 模式可选字段不兼容【英文标题】:AVRO schema optional fields are not compatible 【发布时间】:2022-01-02 11:12:34 【问题描述】:在Confluent documentation 中,他们写道,删除和添加可选的 AVRO 字段可保持完整的 AVRO 兼容性。我需要通过删除可选字段和添加新的可选字段来更新 AVRO 模式。但是 Confluent 架构注册表响应错误 409,即新架构与旧架构不兼容。
我正在删除以下字段(在 avsc 语法中):
"name" : "eligibility",
"type" : [
"type" : "array",
"items" : "Scope"
, "null" ]
并添加这些字段:
"name" : "partyDataExt",
"type" : [
"type" : "record",
"name" : "PartyDataExt",
"fields" : [
"name" : "dayOfDeath",
"type" : [
"type" : "int",
"logicalType" : "date"
, "null" ]
,
"name" : "identified",
"type" : [ "boolean", "null" ]
]
, "null" ]
和
"name" : "identificationDocument",
"type" : [ "null", "Document" ]
问题:可选的 AVRO 字段究竟是什么意思?是union null, MyType
,还是default
参数的存在,或者两者兼而有之,还是别的什么?
在删除“资格”字段的情况下,如果该字段具有"default":null
会有所帮助。这也有助于添加的“identificationDocument”字段,但不适用于“partyDataExt”字段。
当我在“identificationDocument”的定义中切换"null"
和"Document"
元素时,添加default
参数也无济于事。看来"null"
必须是"type"
数组中的第一个元素。
【问题讨论】:
根据Avro specification,联合字段的默认值对应联合中的first模式。 @ChinHuang 不幸的是,这不足以让 Confluent 模式注册表接受模式更改作为兼容。"default":null
字段参数似乎也是必要的。但这只是一个反复试验的结果,文档很模糊。
【参考方案1】:
首先,您需要了解 Apache Avro。
阅读器架构中的default
字段用于schema evolution:
default:该字段的默认值,仅在读取时使用 缺少用于模式演变目的的字段的实例。这 默认值的存在不会使该字段在 编码时间。 [...] Avro 对字段进行编码,即使其值相等 到它的默认值。
另外,"null" goes first 在一个联合中:
请注意,当为记录字段指定默认值时 type是union,默认值的类型必须匹配第一个 联合的元素。因此,对于包含“null”的联合,“null” 通常首先列出,因为此类联合的默认值为 通常为空。
在 Apache Avro 文档中没有“可选”字段之类的东西,但 Confluent 指的是具有默认值的字段,这可能就像
"fields": [
"name": "field",
"type": "string",
"default": "default"
]
您也可以使用联合和“null”(首先),但您不必这样做。
Avro 就是这样,因此您可以使用带有未在 writer 架构中的额外字段的架构读取数据。不在阅读模式中的字段会被忽略,Confluent 指的是“已删除字段”。
对于 Confluent Avro,它们具有与 Apache Avro 不同的兼容性规则(和不同的序列化格式),但这些都记录在您引用的“Compatibility Types”中。
【讨论】:
谢谢。我对 Confluent avro 兼容性规则感兴趣。 “可选”可以有两种含义:字段可以没有值(null),或者您不需要指定字段但值仍然存在(默认)。经过大量的实验后,我才意识到default
是模式演变所需要的,并且您向我证实了这一点。当我需要一个可以删除或添加到新 avro 版本的可为空字段时,我需要 union null
和 default null
。 IMO,规范和文档在这方面含糊不清。
您似乎误解了 Avro:“null”是一个值,并且像任何其他值一样被编码。编码字段不可能没有值。 “默认”只对读者模式有意义。对于 Avro,您始终需要一个 writer 架构(以了解数据是如何编码的)和一个 reader 架构,它指示您感兴趣的字段。在那里,您可以将一个字段标记为具有默认值,当它不存在于writers 架构,否则只会出现错误。
从技术上讲,“null”与其他任何值一样,但从逻辑上讲,“null”用于表示字段没有值。为了允许字段包含“null”,您必须使用union null
。这一切都清楚了。对我来说,default
参数是有问题的。你写的关于写入者和读取者模式的内容是有道理的,但棘手的部分是模式注册表。正如我所看到的,“向后”和“向前”模式兼容性是关于谁是模式的所有者(消费者与生产者),而不是关于读者和作者。例如。删除非可选字段不是向前兼容的更改。
Confluent 模式注册表仅用于将编写器模式传输到读取器。 “向后”和“向前”的东西是 Confluent 的发明。在“向后兼容性”中,docs.confluent.io/platform/current/schema-registry/…> Confluent 写道:BACKWARD
兼容性意味着使用新模式的消费者可以读取使用最后一个模式生成的数据。“新模式”在这里是读者,“最后一个模式”作者。 “新”和“最后”会误导恕我直言,因为这取决于 Confluent Registry 看到模式的顺序。
@OneCricketeer:不,无论如何您都需要编写器模式,否则 Avro 消息将无法读取。 writer 模式是必不可少的信息,并且因为 that 的编码方式不同,两种格式(Avro 单对象编码和 Confluent Avro)不兼容。不过,您是对的,两者都使用 Avro 二进制编码。以上是关于AVRO 模式可选字段不兼容的主要内容,如果未能解决你的问题,请参考以下文章
在 oozie 工作流中读取 avro 数据文件时出错 - 类与新地图 API 模式不兼容
是否可以在 Avro 模式中有一个可选字段(即该字段根本不会出现在 .json 文件中)?