当前位置: 首页 > 知识库问答 >
问题:

在avro模式中使用“default”

牛兴安
2023-03-14

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

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

但事实似乎并非如此。考虑下面的<代码>学生<代码>模式:

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

模式表示:如果“年龄”字段丢失,则将值视为-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);

(学生类是由Avro编译器从学生模式自动生成的)

共有2个答案

洪高阳
2023-03-14

只是添加上面回答中已经说过的内容。如果一个字段不存在,那么它的类型与null联合。否则它只是一个拼写为null的字符串,它in.example模式:

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

}

然后,如果您添加{“age”:70}并检索记录,您将得到以下结果:

{"age":70,"name":null}
孟佑运
2023-03-14

我认为对默认值有一些理解失误,所以希望我的解释也能对其他人有所帮助。当字段不存在时,默认值用于给出默认值,但这基本上是在实例化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));

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

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

以防万一,可能知道也可能不知道,“null”实际上不是null值,而是一个值为“null”的字符串

 类似资料:
  • 我正在从Cloudera包裹中运行带有Spark 0.9.0的CDH 4.4。 我有一堆Avro文件是通过Pig的AvroStorage UDF创建的。我想在 Spark 中加载这些文件,使用通用记录或载入 Avro 文件的架构。到目前为止,我已经尝试过这个: 这适用于一个文件,但它不能扩展——我将所有数据加载到本地RAM中,然后从那里跨spark节点分发。

  • 我是AWS Glue的新手,很难完全理解AWS文档,但我正在努力解决以下用例: 我们有一个包含许多Avro文件的s3存储桶。我们决定使用Avro,因为它具有对数据架构更改的广泛支持,允许将新字段毫无问题地应用于旧数据。 有了AWS Glue,我知道每当模式发生变化时,爬虫就会创建一个新表。当我们的模式发生变化时,这导致爬虫程序按预期创建了许多新表,但并不像我们期望的那样。。。 最后,我们希望爬行器

  • 有没有办法从Apache spark生成无模式的avro?我可以看到一种使用apache avro库通过Java/Scala和融合avro生成它的方法。当我用下面的方式从Spark编写Avro时,它用模式创建了Avro。我想在没有模式的情况下创建,以减少最终数据集的大小。

  • 我有一个带有日期的简单POJO,在导入Google BigQuery之前,它将作为Avro存储在存储器中。日期转换为long,我试图使用@AvroSchema覆盖日期字段的模式生成,以便BigQuery了解字段的类型。 简单的POJO: 这最终得到以下AVRO-Schema: 这些似乎是错误的,应该是简单的{“name”:“tm”,“type”:“long”,“logicalType”:“time

  • 我有两个问题: > 我曾尝试使用模式V1编写记录,并使用模式V2读取记录,但出现以下错误: org.apache.avro。AvroTypeException:找到foo,应为foo 我使用avro-1.7.3和: 以下是这两种模式的示例(我也尝试过添加命名空间,但没有成功)。 架构V1: 架构V2: 提前谢谢。

  • 根据Avro模式规范(适用于接头):https://avro.apache.org/docs/current/spec.html 如上所述,Unions使用JSON数组表示。例如,["null","string"]声明一个模式,该模式可以是null或string。 ( 请注意,当为类型为联合的记录字段指定默认值时,默认值的类型必须与联合的第一个元素匹配。 因此,对于包含“null”的联合,通常首先