2012-11-18 12 views
5

Desidero utilizzare Apache Avro per serializzare i miei dati, il mio client è scritto in C++ e il mio server è scritto in Java.Come utilizzare apache avro GenericRecord per dati dinamici?

  1. Il mio codice Java server è simile al seguente:

    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. E il mio codice cliente:

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

mando il theByteData al server, il codice funziona (nessuna eccezione), ma il risultato è vuoto, qualcuno può dirmi cosa c'è che non va?

E perché in Java si ottiene valore con chiave: result.get("name"); ma in C++ otteniamo valore con indice: record.fieldAt(0).value<string>(). Se non riesco a ottenere il valore con la chiave stringa, come abbinare l'indice alla chiave stringa?

+0

Grazie alla dominikh, a cura mia domanda. – user1833610

+0

3 anni dopo, qualche notizia? –

risposta

1

Ho avuto lo stesso problema stamattina e ho trovato una soluzione nel file Cpp Avro Test ("DataFileTests.cc") con la funzione "testWriteGeneric".

Ad esempio:

mio file di schema (cpx.json):

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

Il mio file 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

Ci sono 2 problemi con il codice client in seguenti dichiarazioni

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

La seconda istruzione si tradurrà in una chiamata a avro::GenericDatum(bool) e non a GenericDatum(const std::string&) come previsto. A causa di ciò il campo stringa rimane vuoto e quindi quando tenterai di leggerlo, verrà restituita una stringa vuota. Così, in sostituzione di sopra dichiarazione con seguente dovrebbe funzionare

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

In prima dichiarazione, srecord dovrebbe essere dichiarato come riferimento in quanto questo è ciò che viene restituito da rData.value(). Non prendere come riferimento, basta sostituirlo con una nuova copia e quindi qualsiasi valore scritto in esso non viene effettivamente scritto nel flusso sottostante. Quindi, dovrebbe essere

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

Inoltre, non è necessario GenericWriter e possibile scrivere utilizzando Encoder oggetto stesso come

avro::encode(*encoder, rData); 
Problemi correlati