2012-11-18 12 views
5

Ich möchte mit Apache Avro meine Daten serialisieren, mein Client ist in C++ geschrieben und mein Server ist in Java geschrieben.Wie verwende ich Apache avro GenericRecord für dynamische Daten?

  1. Mein Server Java-Code sieht wie folgt aus:

    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. Und mein Client-Code:

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

ich die theByteData an den Server senden, funktioniert der Code (keine Ausnahme), aber das Ergebnis ist leer, kann mir jemand sagen, was los ist?

Und warum in Java wir Wert mit Schlüssel erhalten: result.get("name"); aber in C++ bekommen wir den Wert mit dem Index: record.fieldAt(0).value<string>(). Wenn ich mit dem Zeichenfolgenschlüssel keinen Wert erhalten kann, wie wird der Index dem Zeichenfolgenschlüssel zugeordnet?

+0

Dank schreiben dominikh, bearbeitet meine Frage. – user1833610

+0

3 Jahre später, irgendwelche Neuigkeiten? –

Antwort

1

Ich hatte das gleiche Problem heute Morgen und ich fand eine Lösung in der Avro Test Cpp-Datei ("DataFileTests.cc") mit der "testWriteGeneric" -Funktion.

Zum Beispiel:

Meine Schemadatei (cpx.json):

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

Meine CPP-Datei:

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

Es gibt zwei Probleme mit dem Client-Code in folgenden Aussagen

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

Zweite Anweisung führt zu einem Aufruf an avro::GenericDatum(bool) und nicht GenericDatum(const std::string&) wie vorgesehen. Aus diesem Grund bleibt das Feld string leer und wenn Sie versuchen, es zu lesen, wird leere Zeichenfolge zurückgegeben. Also, mit folgenden obigen Aussage ersetzt

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

In erster Anweisung funktionieren soll, sollte SRecord als Referenz erklärt werden, wie das ist, was von rData.value() zurückgegeben wird. Wenn Sie sie nicht als Referenz verwenden, ersetzen Sie sie einfach durch eine neue Kopie, und somit wird jeder darin geschriebene Wert nicht in den zugrunde liegenden Stream geschrieben. So sollte es

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

auch sein, die Sie nicht benötigen GenericWriter und kann mit Encoder-Objekt selbst als

avro::encode(*encoder, rData); 
Verwandte Themen