【问题标题】:How do you update an existing avro schema using apache avro SchemaBuilder?如何使用 apache avro SchemaBuilder 更新现有的 avro 架构?
【发布时间】:2017-08-22 12:40:40
【问题描述】:

我正在测试一个新的模式注册表,它可以加载和检索不同类型的 avro 模式。在测试的过程中,我需要创建一堆不同类型的 avro schemas。由于它涉及很多排列,我决定以编程方式创建模式。 我正在使用 apache avro SchemaBuilder 这样做。

我使用以下方法创建了 avro:

Schema oldSchema = SchemaBuilder
      .record("abc")
      .aliases("records")
      .fields()
      .name("field_null")
      .type("null")
      .noDefault()
      .endRecord();

这行得通。创建的 avro 看起来像:

{
 "type" : "record",
 "name" : "abc",
 "fields" : [ {
   "name" : "field_null",
   "type" : "null"
  } ],
  "aliases" : [ "records" ]
}

现在我想使用 apache avro 库创建一个新版本的架构,例如:

{
 "type" : "record",
 "name" : "abc",
 "fields" : [ {
   "name" : "field_null",
   "type" : "null"
  },
  {
   "name" : "new_field",
   "type" : "int",
   "default" : 10
  }
 ],
 "aliases" : [ "records" ]
}

为此,我尝试了:

Schema.Field field = new Schema.Field("new_field", SchemaBuilder.builder().intType(),
    "NewField", 10);

List<Schema.Field> fields = new ArrayList<>();
fields.add(field);
fields.addAll(oldSchema.getFields());

Schema record = Schema.createRecord(oldSchema.getName(),
    "Changes",
    oldSchema.getNamespace(),
    false,
    fields);

我明白了:

org.apache.avro.AvroRuntimeException: Field already used: field_null type:NULL pos:0

at org.apache.avro.Schema$RecordSchema.setFields(Schema.java:647)
at org.apache.avro.Schema$RecordSchema.<init>(Schema.java:618)
at org.apache.avro.Schema.createRecord(Schema.java:167)

我的问题是:

  1. 如何使用现有库添加新版本的架构?
  2. 我应该使用 avro schemaBuilder 创建架构还是创建自己的 POJO 来构建架构/将 avsc 文件保存在数据目录中。

【问题讨论】:

    标签: java apache avro


    【解决方案1】:

    你可以试试这个来创建字段,也许它很笨拙:

    Schema.Field field = new Schema.Field("new_field",SchemaBuilder.builder().intType(),
        "NewField", 10);
    
    List<Schema.Field> fields = new ArrayList<>();
    
    for (Schema.Field f : oldSchema.getFields()) {
    
       Schema.Field _field = new Schema.Field(f.name(), f.schema(), f.doc(), f.defaultValue());
      fields.add(_field);
    
    }
    

    【讨论】:

      【解决方案2】:

      要将旧模式中的字段复制到新模式中,您必须按照@xiping xing 的建议对每个字段进行深层复制。

      这是因为 Schema 类检查该字段是否仅添加到架构中一次,并且在您的情况下,这些字段已添加到旧架构中。

      您可以从Avro 1.7.7 看到他们如何在这个 sn-p 中使用标志:

      @Override
      public void setFields(List<Field> fields) {
        if (this.fields != null) {
          throw new AvroRuntimeException("Fields are already set");
        }
        int i = 0;
        fieldMap = new HashMap<String, Field>();
        LockableArrayList ff = new LockableArrayList();
        for (Field f : fields) {
          if (f.position != -1)
            throw new AvroRuntimeException("Field already used: " + f);
          f.position = i++;
          final Field existingField = fieldMap.put(f.name(), f);
          if (existingField != null) {
            throw new AvroRuntimeException(String.format(
                "Duplicate field %s in record %s: %s and %s.",
                f.name(), name, f, existingField));
          }
          ff.add(f);
        }
        this.fields = ff.lock();
        this.hashCode = NO_HASHCODE;
      }
      

      【讨论】:

        猜你喜欢
        • 2019-06-09
        • 1970-01-01
        • 1970-01-01
        • 2018-07-20
        • 1970-01-01
        • 2018-09-03
        • 1970-01-01
        • 2020-09-21
        • 1970-01-01
        相关资源
        最近更新 更多