2016-04-10 6 views
7

Ich habe zwei ähnliche Schemas, wo nur ein verschachteltes Feld ändert (es heißt onefield in schema1 und anotherfield in schema2).Verschmelzen Sie zwei Avro Schemas programmatisch

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 
     } 
    ] 
} 

Ich bin in der Lage zu programmatisch beiden Schemata zu verschmelzen mit 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); 
} 

und es verwendet, konvertieren ein Eingabe json in eine avro oder json Darstellung:

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

Dieser Code zeigt die erwartete Ausgabe: {"metadata":{"onefield":null,"anotherfield":null}}. Das Problem ist, dass ich das zusammengeführte Schema nicht sehen kann. Wenn ich ein einfaches System.out.println(mergedSchema) bekomme ich die folgende Ausnahme:

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) 

ich es die Avro Unschärferelation nennen :). Es sieht so aus, als ob avro mit dem zusammengeführten Schema arbeiten kann, aber es schlägt fehl, wenn es versucht, das Schema zu JSON zu serialisieren. Die Zusammenführung funktioniert mit einfacheren Schemas, daher klingt es wie ein Fehler in avro 1.8.0 für mich.

Wissen Sie, was passieren könnte oder wie Sie es lösen können? Jede Problemumgehung (zB Alternative Schema Serializer) ist willkommen.

+0

Es scheint auch in früheren Versionen von avro (1.7.6) zu geschehen http://mail-archives.apache.org/mod_mbox/avro-user/201406.mbox/%[email protected] nabble.com% 3E –

Antwort

1

fand ich das gleiche Problem mit der util Klasse Schwein ... eigentlich gibt es 2 Bugs hier

  • AVRO serialisiert Daten durch GenericDatumWriter ein ungültiges Schema generiert ungültige Schemata
  • Die Sparschwein util-Klasse erlaubt Dies funktioniert einwandfrei für komplexere Szenarien, weil es

den gleichen Namen/Namensraum für alle fusionierten Felder (den ursprünglichen Namen Instanz hält) mit 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); 

Von Ihrem Beispiel, erhalte ich die folgende Ausgabe

{ 
    "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 
    } 
    ] 
} 

Hoffentlich andere helfen.

+0

Dank @lake. Ich kann es nicht versuchen, aber es sieht wirklich gut aus. –