【问题标题】:Avro backward compatibility doesn't work as expectedAvro 向后兼容性无法按预期工作
【发布时间】:2021-11-14 06:33:41
【问题描述】:

我有两个 Avro 模式 V1 和 V2,它们在 spark 中读取如下:

import org.apache.spark.sql.avro.functions._

val jsonFormatSchema = new String(Files.readAllBytes(Paths.get("./examples/src/main/resources/V1.avsc")))

val df = spark
  .readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "host1:port1,host2:port2")
  .option("subscribe", "topic1")
  .load()

val output = df
  .select(from_avro($"value", jsonFormatSchema) as $"avroFields")

V1 有两个字段“一”和“二”

{
  "name": "test",
  "namespace": "foo.bar",
  "type": "record",
  "fields": [
    {
      "name": "one",
      "type": [
        "null",
        "string"
      ],
      "default": null
    },
    {
      "name": "two",
      "type": [
        "null",
        "string"
      ],
      "default": null
    }
  ]
}

带有新字段的 V2:“三”

{
  "name": "test",
  "namespace": "foo.bar",
  "type": "record",
  "fields": [
    {
      "name": "one",
      "type": [
        "null",
        "string"
      ],
      "default": null
    },
    {
      "name": "two",
      "type": [
        "null",
        "string"
      ],
      "default": null
    },
    {
      "name": "three",
      "type": [
        "null",
        "string"
      ],
      "default": null
    }
  ]
}

场景:writer 使用 V1 写入,Reader 使用 V2 解码 avro 记录。我的期望是看到字段 3 填充了默认值为 null。但我在 spark 工作中遇到了以下异常。

我在这里遗漏了什么吗?我的理解是avro支持向后兼容。

Exception in thread "main" java.io.EOFException
  at org.apache.avro.io.BinaryDecoder.ensureBounds(BinaryDecoder.java:473)
  at org.apache.avro.io.BinaryDecoder.readInt(BinaryDecoder.java:128)
  at org.apache.avro.io.BinaryDecoder.readIndex(BinaryDecoder.java:423)
  at org.apache.avro.io.ResolvingDecoder.doAction(ResolvingDecoder.java:290)
  at org.apache.avro.io.parsing.Parser.advance(Parser.java:88)
  at org.apache.avro.io.ResolvingDecoder.readIndex(ResolvingDecoder.java:267)
  at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:179)
  at org.apache.avro.specific.SpecificDatumReader.readField(SpecificDatumReader.java:116)
  at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:222)
  at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:175)
  at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:153)
  at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:145)

【问题讨论】:

  • 您如何阅读您的 avro 文件?您可以在您的问题中添加Reader 代码吗?谢谢!

标签: scala apache-spark avro spark-avro


【解决方案1】:

您总是必须使用写入的 exact 架构来解码 Avro。这是因为 Avro 使用未标记的数据更紧凑,并且要求编写器架构在解码时存在。

因此,当您使用 V2 架构进行阅读时,它会查找字段 three(或者可能是该字段的空标记)并引发错误。

您可以做的是将解码后的数据(使用 writer 模式解码)映射到 reader 模式,Java 有一个 API:SpecificDatumReader(Schema writer, Schema reader)

Protocol Buffers 或 Thrift 做你想做的事,它们是标记格式。 Avro 期望架构与数据一起传播,例如在 Avro 文件中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多