2017-08-22 82 views
5

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

我创建使用的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文件保存在数据目录中。

回答

0

你可以试试这个创建领域,也许它的笨拙:

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

} 
0

从旧模式复制等领域的新的,你需要做的每个字段作为@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; 
}