在 avro 架构中使用“默认”

问题描述 投票:0回答:3

根据 Avro docs 中“default”属性的定义:“此字段的默认值,在读取缺少此字段的实例时使用(可选)。”

这意味着如果缺少相应字段,则采用默认值。

但事实似乎并非如此。考虑以下

student
模式:

{
        "type": "record",
        "namespace": "com.example",
        "name": "Student",
        "fields": [{
                "name": "age",
                "type": "int",
                "default": -1
            },
            {
                "name": "name",
                "type": "string",
                "default": "null"
            }
        ]
    }

Schema 表示:如果缺少“age”字段,则将值视为 -1。对于“名称”字段也是如此。

现在,如果我尝试从以下 JSON 构建学生模型:

{"age":70}

我得到这个例外:

org.apache.avro.AvroTypeException: Expected string. Got END_OBJECT

    at org.apache.avro.io.JsonDecoder.error(JsonDecoder.java:698)
    at org.apache.avro.io.JsonDecoder.readString(JsonDecoder.java:227)

看起来默认设置没有按预期工作。那么,默认在这里到底扮演什么角色呢?

这是用于生成学生模型的代码:

Decoder decoder = DecoderFactory.get().jsonDecoder(Student.SCHEMA$, studentJson);
SpecificDatumReader<Student> datumReader = new SpecificDatumReader<>(Student.class);
return datumReader.read(null, decoder);

Student
类由 Avro 编译器根据学生模式自动生成)

java hadoop serialization apache-kafka avro
3个回答
4
投票

我认为对默认值存在一些误解,因此希望我的解释对其他人也有帮助。当字段不存在时,默认值对于给出默认值很有用,但这本质上是当您实例化 avro 对象时(在您的情况下调用

datumReader.read
),但它不允许使用不同的模式读取数据,这这就是为什么“模式注册表”的概念对于这种情况很有用。

以下代码有效并允许读取您的数据

Decoder decoder = DecoderFactory.get().jsonDecoder(Student.SCHEMA$, "{\"age\":70}");
SpecificDatumReader<Student> datumReader = new SpecificDatumReader<>(Student.class);

Schema expected = new Schema.Parser().parse("{\n" +
        "  \"type\": \"record\",\n" +
        "  \"namespace\": \"com.example\",\n" +
        "  \"name\": \"Student\",\n" +
        "  \"fields\": [{\n" +
        "    \"name\": \"age\",\n" +
        "    \"type\": \"int\",\n" +
        "    \"default\": -1\n" +
        "  }\n" +
        "  ]\n" +
        "}");

datumReader.setSchema(expected);
System.out.println(datumReader.read(null, decoder));

如您所见,我指定了用于“写入”json 输入的架构,该输入不包含“名称”字段,但是(考虑到您的架构包含默认值)当您打印记录时,您将看到名称你的默认值

{"age": 70, "name": "null"}

以防万一,可能知道也可能不知道,“null”并不是真正的空值,而是值为“null”的字符串。


1
投票

只是补充上面答案中已经说过的内容。为了使字段在不存在时为空。然后将其类型与 null 联合。否则它只是一个拼写为 null 的字符串。示例架构:

{
"name": "name",
"type": [
  "null",
  "string"
],
"default": null

}

然后如果您添加

{"age":70}
并检索记录,您将得到以下结果:

{"age":70,"name":null}

0
投票

default
字段供读者使用。作者必须提供所有字段。

© www.soinside.com 2019 - 2024. All rights reserved.