2016-04-10 16 views
7

У меня есть две аналогичные схемы, в которых изменяется только одно вложенное поле (это называется onefield в schema1 и anotherfield в схеме2).Объединить две схемы avro программно

SCHEMA1

{ 
    "type": "record", 
    "name": "event", 
    "namespace": "foo", 
    "fields": [ 
     { 
      "name": "metadata", 
      "type": { 
       "type": "record", 
       "name": "event", 
       "namespace": "foo.metadata", 
       "fields": [ 
        { 
         "name": "onefield", 
         "type": [ 
          "null", 
          "string" 
         ], 
         "default": null 
        } 
       ] 
      }, 
      "default": null 
     } 
    ] 
} 

SCHEMA2

{ 
    "type": "record", 
    "name": "event", 
    "namespace": "foo", 
    "fields": [ 
     { 
      "name": "metadata", 
      "type": { 
       "type": "record", 
       "name": "event", 
       "namespace": "foo.metadata", 
       "fields": [ 
        { 
         "name": "anotherfield", 
         "type": [ 
          "null", 
          "string" 
         ], 
         "default": null 
        } 
       ] 
      }, 
      "default": null 
     } 
    ] 
} 

Я могу программно объединить обе схемы с использованием Avro 1.8.0:

Schema s1 = new Schema.Parser().parse(schema1); 
Schema s2 = new Schema.Parser().parse(schema2); 
Schema[] schemas = {s1, s2}; 

Schema mergedSchema = null; 
for (Schema schema: schemas) { 
    mergedSchema = AvroStorageUtils.mergeSchema(mergedSchema, schema); 
} 

и использовать его для преобразованиявход JSON в AVRO или JSon представления:

JsonAvroConverter converter = new JsonAvroConverter(); 
try { 
    byte[] example = new String("{}").getBytes("UTF-8"); 
    byte[] avro = converter.convertToAvro(example, mergedSchema); 
    byte[] json = converter.convertToJson(avro, mergedSchema); 
    System.out.println(new String(json)); 
} catch (AvroConversionException e) { 
    e.printStackTrace(); 
} 

Этот код показывает ожидаемый результат: {"metadata":{"onefield":null,"anotherfield":null}}. Проблема в том, что я не могу видеть объединенную схему. Если бы я сделать простой System.out.println(mergedSchema) я получаю следующее исключение:

Exception in thread "main" org.apache.avro.SchemaParseException: Can't redefine: merged schema (generated by AvroStorage).merged 
    at org.apache.avro.Schema$Names.put(Schema.java:1127) 
    at org.apache.avro.Schema$NamedSchema.writeNameRef(Schema.java:561) 
    at org.apache.avro.Schema$RecordSchema.toJson(Schema.java:689) 
    at org.apache.avro.Schema$RecordSchema.fieldsToJson(Schema.java:715) 
    at org.apache.avro.Schema$RecordSchema.toJson(Schema.java:700) 
    at org.apache.avro.Schema.toString(Schema.java:323) 
    at org.apache.avro.Schema.toString(Schema.java:313) 
    at java.lang.String.valueOf(String.java:2982) 
    at java.lang.StringBuilder.append(StringBuilder.java:131) 

Я называю это Avro принцип неопределенности :). Похоже, что avro может работать с объединенной схемой, но он терпит неудачу, когда пытается преобразовать схему в JSON. Слияние работает с более простыми схемами, поэтому для меня это звучит как ошибка в avro 1.8.0.

Вы знаете, что может произойти или как его решить? Любое обходное решение (например: альтернативное Schema сериализаторы) приветствуется.

+0

Это похоже на предыдущие версии avro (1.7.6) тоже http://mail-archives.apache.org/mod_mbox/avro-user/201406.mbox/%[email protected] nabble.com% 3E –

ответ

1

я нашел тот же вопрос с классом UTIL свиньи ... на самом деле есть 2 ошибки здесь

  • AVRO позволяет сериализовать данные через GenericDatumWriter с неверным Schema
  • PiggyBank класса Util порождает недопустимые Схемы потому что он использует тот же имя/пространство имен для всех объединяемых полей (экземпляр сохранить оригинальное имя)

Это правильно работает для более сложных сценариев https://github.com/kite-sdk/kite/blob/master/kite-data/kite-data-core/src/main/java/org/kitesdk/data/spi/SchemaUtil.java#L511

Schema mergedSchema = SchemaUtil.merge(s1, s2); 

Из вашего примера, я получаю следующий результат

{ 
    "type": "record", 
    "name": "event", 
    "namespace": "foo", 
    "fields": [ 
    { 
     "name": "metadata", 
     "type": { 
     "type": "record", 
     "name": "event", 
     "namespace": "foo.metadata", 
     "fields": [ 
      { 
      "name": "onefield", 
      "type": [ 
       "null", 
       "string" 
      ], 
      "default": null 
      }, 
      { 
      "name": "anotherfield", 
      "type": [ 
       "null", 
       "string" 
      ], 
      "default": null 
      } 
     ] 
     }, 
     "default": null 
    } 
    ] 
} 

Надеюсь, это поможет другим.

+0

Спасибо @lake. Я не могу попробовать, но это выглядит очень хорошо. –

Смежные вопросы