根据" 默认"的定义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编译器从学生模式自动生成)
答案 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}