使用"默认"在avro架构中

时间:2018-02-26 09:59:50

标签: java hadoop serialization apache-kafka avro

根据" 默认"的定义Avro docs中的属性:"此字段的默认值,用于读取缺少此字段的实例(可选)。"

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

但事实并非如此。请考虑以下student架构:

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

架构说:如果"年龄"字段丢失,然后将值视为-1。同样地," name"字段。

现在,如果我尝试构建Student模型,请使用以下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编译器从学生模式自动生成)

2 个答案:

答案 0 :(得分:2)

我认为对默认值有一些错过的理解,所以希望我的解释也会对其他人有所帮助。当字段不存在时,默认值可用于提供默认值,但这实际上是在实例化avro对象时(在您调用datumReader.read的情况下)但它不允许使用不同的模式读取数据这就是&#34; schema registry&#34;的概念。对这种情况很有用。

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

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));

正如您所看到的,我正在指定用于&#34;写&#34; json输入不包含字段&#34; name&#34;但是(考虑到您的模式包含默认值)当您打印记录时,您将看到具有默认值的名称

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

以防万一,可能或可能不知道,&#34; null&#34;实际上不是null值是一个值为&#34; null&#34;的字符串。

答案 1 :(得分:0)

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

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

}

然后如果您添加 {"age":70} 并检索记录,您将获得以下信息:

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