gpt4 book ai didi

java - 如果字段顺序更改,Avro 模式不兼容

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:49:40 26 4
gpt4 key购买 nike

场景——客户端使用 Avro Reflect Datum Writer 序列化 POJO,并将 GenericRecord 写入文件。通过反射得到的schema是这样的(注意A、B、D、C的顺序)——

{
"namespace": "storage.management.example.schema",

"type": "record",
"doc": "Example schema for testing",
"name": "Event",
"fields": [
....
....
{ "name": "A", "type": "string" },
{ "name": "B", "type": "string" },
{ "name": "D", "type": "string" },
{ "name": "C", "type": "string" },
....
....
]
}

代理读取文件并使用默认模式(注意顺序 - A、B、C、D)反序列化记录的子集(保证客户端具有这些字段)

{
"namespace": "storage.management.example.schema",
"type": "record",
"doc": "Example schema for testing",
"name": "Event",
"fields": [
{ "name": "A", "type": "string" },
{ "name": "B", "type": "string" },
{ "name": "C", "type": "string" },
{ "name": "D", "type": "string" }
]
}

问题:使用上述子集模式进行反序列化会导致以下异常 -

Caused by: java.io.IOException: Invalid int encoding
at org.apache.avro.io.BinaryDecoder.readInt(BinaryDecoder.java:145)
at org.apache.avro.io.BinaryDecoder.readString(BinaryDecoder.java:259)
at org.apache.avro.io.ResolvingDecoder.readString(ResolvingDecoder.java:201)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:430)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:422)
at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:180)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
at org.apache.avro.generic.GenericDatumReader.readField(GenericDatumReader.java:240)
at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:230)

但是,如果子集模式也按照 A、B、D、C 的顺序指定字段,则反序列化成功。(与客户端模式相同)

这种行为是预期的吗?我虽然 Avro 只依赖于字段名称来构建记录而不是排序。

对此有任何修复吗?不同的客户端可能有不同的顺序,我无法强制排序,因为模式是通过反射生成的。

最佳答案

这不一定是预期的行为。当我开始使用 Avro 时,您可能会犯同样的错误。

Avro 能够拥有不同版本的模式(例如,用一个模式写入但读入另一个模式)但是很容易错过的一件事(至少我自己)是您必须拥有编写消息的确切模式尝试阅读时。

您阅读的有关 Avro 的文档和信息,至少在表面层面上,并没有说得很清楚。通常他们专注于“向后兼容”。公平地说,在某种意义上是这样,但通常当人们看到这个短语时,他们会认为它的意思有点不同。通常我们认为这意味着您可以使用新架构处理旧消息,而不是使用新架构处理旧消息和旧消息的架构。

举个例子,看这个伪代码

Schema myUnsortedSchema has C B A order
Schema myAlphabeticalSchema has A B C order

Writer writer uses myUnsortedSchema
Reader badReader uses myAlphabeticalSchema only

writer writes message
badReader reads message

错误!不确定错误消息的确切含义,但问题是 badReader 不仅尝试读入 myAlphabeticalSchema,而且还读取消息,就好像它是由 myAlphabeticalSchema。解决方案是有一种方法可以为它提供两种模式,一种是编写消息的模式,另一种是要读入的模式(如何取决于语言)。

Reader goodReader reads messages written with myUnsortedSchema into myAlphabeticalSchema

goodReader reads message

没有错误!这是正确的用法。

如果您使用的是 goodReader 之类的方法,则此行为是意外的,但如果您使用的是 badReader 之类的方法,则此行为是预期的。


Schema Registry 等一些服务通过将一些元数据附加到消息字节的前面来帮助确定哪个模式写入了消息(当然在读取之前将它们剥离)。这超出了问题的范围,但可以帮助解决这样的问题。

关于java - 如果字段顺序更改,Avro 模式不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45852910/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com