2016-01-12 31 views
6

mam ten Avro schematuAvro schematu nie honoruje wsteczną zgodnością

{ 
"namespace": "xx.xxxx.xxxxx.xxxxx", 
"type": "record", 
"name": "MyPayLoad", 
"fields": [ 
    {"name": "filed1", "type": "string"}, 
    {"name": "filed2",  "type": "long"}, 
    {"name": "filed3", "type": "boolean"}, 
    { 
      "name" : "metrics", 
      "type": 
      { 
      "type" : "array", 
      "items": 
      { 
       "name": "MyRecord", 
       "type": "record", 
       "fields" : 
        [       
         {"name": "min", "type": "long"}, 
         {"name": "max", "type": "long"}, 
         {"name": "sum", "type": "long"}, 
         {"name": "count", "type": "long"} 
        ] 
      } 
      } 
    } 
    ] 
} 

Oto kod, który używamy do analizowania danych

public static final MyPayLoad parseBinaryPayload(byte[] payload) { 
     DatumReader<MyPayLoad> payloadReader = new SpecificDatumReader<>(MyPayLoad.class); 
     Decoder decoder = DecoderFactory.get().binaryDecoder(payload, null); 
     MyPayLoad myPayLoad = null; 
     try { 
      myPayLoad = payloadReader.read(null, decoder); 
     } catch (IOException e) { 
      logger.log(Level.SEVERE, e.getMessage(), e); 
     } 

     return myPayLoad; 
    } 

teraz chcę dodać jeszcze jedno pole int schemat, więc schemat wygląda mniej niż:

{ 
"namespace": "xx.xxxx.xxxxx.xxxxx", 
"type": "record", 
"name": "MyPayLoad", 
"fields": [ 
    {"name": "filed1", "type": "string"}, 
    {"name": "filed2",  "type": "long"}, 
    {"name": "filed3", "type": "boolean"}, 
    { 
      "name" : "metrics", 
      "type": 
      { 
      "type" : "array", 
      "items": 
      { 
       "name": "MyRecord", 
       "type": "record", 
       "fields" : 
        [       
         {"name": "min", "type": "long"}, 
         {"name": "max", "type": "long"}, 
         {"name": "sum", "type": "long"}, 
         {"name": "count", "type": "long"} 
        ] 
      } 
      } 
    } 
    {"name": "agentType", "type": ["null", "string"], "default": "APP_AGENT"} 
    ] 
} 

Uwaga: zdefiniowane jest także pole wyboru, a także wartość domyślna. Problemem jest to, że jeśli otrzymamy dane, które zostało napisane z wykorzystaniem starszego schematu otrzymuję ten błąd

java.io.EOFException: null 
    at org.apache.avro.io.BinaryDecoder.ensureBounds(BinaryDecoder.java:473) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.io.BinaryDecoder.readInt(BinaryDecoder.java:128) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.io.BinaryDecoder.readIndex(BinaryDecoder.java:423) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.io.ResolvingDecoder.doAction(ResolvingDecoder.java:229) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.io.parsing.Parser.advance(Parser.java:88) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.io.ResolvingDecoder.readIndex(ResolvingDecoder.java:206) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:177) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:148) ~[avro-1.7.4.jar:1.7.4] 
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:139) ~[avro-1.7.4.jar:1.7.4] 
    at com.appdynamics.blitz.shared.util.XXXXXXXXXXXXX.parseBinaryPayload(BlitzAvroSharedUtil.java:38) ~[blitz-shared.jar:na] 

Co zrozumiałem z this dokumencie, że powinno to być wstecznie kompatybilne, ale jakoś nie wydaje się być walizka. Masz pojęcie, co robię źle?

Odpowiedz

0

Możliwe są dwa problemy, które widzę na schemacie

  1. Wartość domyślna dla mnie zawsze wydaje się mieć pracę za nieważną określić to trzeba ustawić

"default": null

  1. Również w swoim schemacie zapomniałeś dodać (separator pól) między tablicą a nowym polem. Stąd też spróbować zmienić swój schemat jak

    { "namespace": "xx.xxxx.xxxxx.xxxxx", "type": "record", "name": "MyPayLoad", "fields": [ {"name": "filed1", "type": "string"}, {"name": "filed2", "type": "long"}, {"name": "filed3", "type": "boolean"}, { "name" : "metrics", "type": { "type" : "array", "items": { "name": "MyRecord", "type": "record", "fields" : [ {"name": "min", "type": "long"}, {"name": "max", "type": "long"}, {"name": "sum", "type": "long"}, {"name": "count", "type": "long"} ] } } }, {"name": "agentType", "type": ["null", "string"], "default":null} ] }

2

wreszcie dostałem tę pracę. Muszę dać obu schematów w SpecificDatumReader Więc zmodyfikował parsowanie jak to gdzie i przekazywane zarówno starego i nowego schematu w czytniku i to działało jak czar

public static final MyPayLoad parseBinaryPayload(byte[] payload) { 
     DatumReader<MyPayLoad> payloadReader = new SpecificDatumReader<>(SCHEMA_V1, SCHEMA_V2); 
     Decoder decoder = DecoderFactory.get().binaryDecoder(payload, null); 
     MyPayLoad myPayLoad = null; 
     try { 
      myPayLoad = payloadReader.read(null, decoder); 
     } catch (IOException e) { 
      logger.log(Level.SEVERE, e.getMessage(), e); 
     } 

     return myPayLoad; 
    } 
0

Jestem stoi dokładnie tej sytuacji. Dane zapisywane przez starszy schemat kończy się niepowodzeniem podczas próby odczytania go za pomocą nowszego schematu. Nowszy schemat ma tylko jedno dodatkowe pole z połączeniem i domyślnym zestawem. "type": ["null", "string"], "doc": "", "default": null

Pomimo ustawienia domyślnego, wartość null nie zostanie automatycznie uzupełniona podczas odczytu. Zarówno pisarz, jak i schematy czytnika muszą być dostarczone podczas czytania. Moje rozumienie było avro kompatybilne wstecz i powinno być w stanie obsługiwać nowsze kolumny bez potrzeby stosowania starszego schematu.