簡體   English   中英

如何使用apache avro SchemaBuilder更新現有的avro模式?

[英]How do you update an existing avro schema using apache avro SchemaBuilder?

我正在測試一個新的架構注冊表,該架構可以加載和檢索不同類型的Avro架構。 在測試過程中,我需要創建一堆不同類型的Avro模式。 由於涉及許多排列,因此我決定以編程方式創建模式。 我正在使用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文件保存在數據目錄中。

您可以嘗試創建字段,這可能很笨拙:

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

}

要將字段從舊模式復制到新模式,您必須按照@xiping xing的建議對每個字段進行深度復制。

這是因為Schema類檢查該字段僅添加到架構一次,並且在您的情況下,這些字段已經添加到舊架構。

您可以在Avro 1.7.7此代碼段中看到他們如何使用標志:

@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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM