2012-11-18 5 views
5

Chcę użyć Apache Avro do serializowania moich danych, mój klient jest napisany w C++, a mój serwer jest napisany w Javie.Jak korzystać z Apache avro GenericRecord dla danych dynamicznych?

  1. Moje kod serwera java wygląda następująco:

    Schema scm = new Schema.Parser().parse("....shcema String....."); 
    ByteArrayInputStream inputStream = new ByteArrayInputStream(record.array()); 
    Decoder coder = new DecoderFactory().directBinaryDecoder(inputStream, null); 
    GenericDatumReader<GenericRecord> reDatumReader = new GenericDatumReader<GenericRecord>(scm); 
    try { 
        GenericRecord result = (GenericRecord)reDatumReader.read(null, coder); 
          //here! the result "name", "num_groups" is empty! 
        System.out.println(result.get("name")+" "+result.get("num_groups")); 
    } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
    } 
    
  2. A mój kod klienta:

    std::string schemaDescript ="....shcema String....."; 
    
    std::stringstream rsStream(schemaDescript); 
    avro::ValidSchema rSchema; 
    avro::compileJsonSchema(rsStream, rSchema); 
    avro::EncoderPtr encoder = avro::binaryEncoder(); 
    std::auto_ptr<avro::OutputStream> oStream = avro::memoryOutputStream(); 
    encoder->init(*oStream); 
    avro::GenericDatum rData(rSchema); 
    avro::GenericRecord sReord = rData.value<avro::GenericRecord>(); 
    sReord.setFieldAt(0, avro::GenericDatum("i am nice")); 
    sReord.setFieldAt(1, avro::GenericDatum(1)); 
    sReord.setFieldAt(2, avro::GenericDatum(12)); 
    sReord.setFieldAt(3, avro::GenericDatum(13)); 
    
    avro::GenericWriter gwriter(rSchema, encoder); 
    gwriter.write(rData); 
    oStream->flush(); 
    
    std::auto_ptr<avro::InputStream> inSt = avro::memoryInputStream(*oStream); 
    avro::StreamReader instReader(*inSt); 
    
    size_t outputLen = oStream->byteCount(); 
    uint8_t* theByteData = new uint8_t[outputLen]; 
    instReader.hasMore(); 
    instReader.readBytes(theByteData, outputLen); 
    

mogę wysłać theByteData do serwera, kod działa (bez wyjątku), ale wynik jest pusty, czy ktoś może mi powiedzieć, co jest nie tak?

A dlaczego w Javie otrzymujemy wartość kluczem: result.get("name"); ale w C++ otrzymujemy wartość z indeksem: record.fieldAt(0).value<string>(). Jeśli nie mogę uzyskać wartości za pomocą klucza łańcucha, jak dopasować indeks do klucza łańcucha?

+0

Dzięki dominikh, edytowany moje pytanie. – user1833610

+0

3 lata później, jakieś wieści? –

Odpowiedz

1

Tego samego dnia miałem ten sam problem i znalazłem rozwiązanie w pliku Avro Test Cpp ("DataFileTests.cc") z funkcją "testWriteGeneric".

Na przykład:

mój plik schematu (cpx.json):

{ 
    "type": "record", 
    "name": "cpx", 
    "fields" : [ 
    {"name": "re", "type": "double"}, 
    {"name": "im", "type" : "int"} 
    ] 
} 

Moja pliku cpp:

typedef std::pair<avro::ValidSchema, avro::GenericDatum> Pair; 

int main(int ac, char **av) 
{ 

    // encode 
    std::ifstream ifs(cpx.json); 
    avro::ValidSchema schema; 
    avro::compileJsonSchema(ifs, schema); 

    // I create a pair of validSchema and GenericDatum 
    Pair p(schema, avro::GenericDatum()); 

    avro::GenericDatum &Data = p.second; 
    Data = avro::GenericDatum(schema); 
    avro::GenericRecord &sReord = Data.value<avro::GenericRecord>(); 

    // I set my values 
    sReord.setFieldAt(sReord.fieldIndex("re"), avro::GenericDatum(42.5)); 
    sReord.setFieldAt(sReord.fieldIndex("im"), avro::GenericDatum(24)); 


    // I create a DataFileWriter and i write my pair of ValidSchema and GenericValue 
    avro::DataFileWriter<Pair> dataFileWriter("test.bin", schema); 
    dataFileWriter.write(p); 
    dataFileWriter.close(); 
} 
0

Są 2 problemy z kodem klienckim w następujących sprawozdaniach

avro::GenericRecord sReord = rData.value<avro::GenericRecord>(); 
sReord.setFieldAt(0, avro::GenericDatum("i am nice")); 

Drugie polecenie spowoduje wywołanie avro::GenericDatum(bool), a nie GenericDatum(const std::string&) zgodnie z przeznaczeniem. Z tego powodu pole łańcuchowe pozostaje puste, a zatem gdy spróbujesz go odczytać, pusty ciąg zostanie zwrócony. Tak, zastępując powyżej oświadczenie o następujące powinny pracować

std::string s("i am nice"); 
sReord.setFieldAt(0, avro::GenericDatum(s)); 

W pierwszym piśmie, srecord powinny zostać uznane jako punkt odniesienia, jak to, co jest zwracane przez rData.value(). Brak wzięcia za punkt odniesienia powoduje jedynie zastąpienie go nową kopią, a zatem zapisana w nim wartość nie jest zapisywana w strumieniu bazowym. Tak powinno być

avro::GenericRecord& sReord = rData.value<avro::GenericRecord>(); 

Ponadto, nie trzeba GenericWriter i może napisać sam obiekt za pomocą kodera

avro::encode(*encoder, rData);