Возникли проблемы при записи avro в виде массива байтов и последующем чтении - PullRequest
0 голосов
/ 06 марта 2020

Я только начинаю работу с Avro и сталкиваюсь с проблемой генерации тестовых данных для процесса, который хочет прочитать эти данные в виде серии байтов.

Когда я смотрю на серию байтов, которые Я пишу, кажется, что мое первое поле, которое целое число искажается. Байты для 2-го и 3-го полей выглядят нормально.

Допустим, это моя схема avro

{
     "type": "record",
     "namespace": "com.foo",
     "name": "test",
     "version": "1",
     "fields": [
        {"name" : "code", "type" : "int", "default" : 1},
        { "name": "firstName", "type": "string", "doc": "firstName" },
        { "name": "lastName", "type": "string", "doc": "lastName" }
     ]
}

Вот мой код:

Schema avroSchema =
    SchemaBuilder.record("test").namespace("com.foo").
        fields().
            requiredInt("code").
            requiredString("firstName").
            requiredString("lastName").endRecord();
GenericRecord avroMessage = new GenericData.Record(avroSchema);
avroMessage.put("code", 7);
avroMessage.put("firstName", "robert");
avroMessage.put("lastName", "wong");

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Encoder encoder = EncoderFactory.get().binaryEncoder(baos, null);
DatumWriter<Object> datumWriter = new GenericDatumWriter<>(avroSchema);
datumWriter.write(avroMessage, encoder);
encoder.flush();
baos.close();
byte[] data = baos.toByteArray();

Integer  code = ByteBuffer.wrap(data).getInt();
System.out.println("code:" + code);


// Result is  code:235696751  -- not code:7 as expected.

Любая идея, что Я мог бы делать, что портит первое целочисленное поле?

1 Ответ

0 голосов
/ 10 марта 2020

Нашел root проблемы.

Первоначально я читал первый байт записанной записи avro как Int, но не выписывал этот Int отдельно, просто выписывал всю запись - - который содержит Int в качестве первого атрибута. Я ожидал, что мое первоначальное чтение целых чисел подхватит этот атрибут.

Но оказывается, что Avro Ints записываются с использованием некоторой формы сжатия (что-то вроде зигзагообразного целочисленного сжатия из того, что я могу разобрать ... но это своего рода побочный вопрос к основной проблеме). Таким образом, решение состоит в том, чтобы явно записать целое число ПЕРЕД записью полной записи Avro.

Некоторые основания для того, почему нам нужно это целое число в первую очередь:

The app I am using uses a home grown avro schema management 
approach where schemas are versioned, and the integer code 
tells you which version of the schema to use for deserialization.

Вот пересмотренный код:

Schema mainSchema =
    SchemaBuilder.record("test").namespace("com.foo").
        fields().
        requiredInt("code").
        requiredString("nickName").
        requiredString("lastName").endRecord();
GenericRecord avroMessage = new GenericData.Record(mainSchema);
avroMessage.put("code", 67);
avroMessage.put("nickName", "robert");
avroMessage.put("lastName", "smith");


ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try (DataOutputStream os = new DataOutputStream(baos)) {
  os.writeInt(1);  // Write out the integer code BEFORE the record
}

Encoder encoder = EncoderFactory.get().binaryEncoder(baos, null);
DatumWriter<Object> datumWriter = new GenericDatumWriter<>(mainSchema);
datumWriter.write(avroMessage, encoder);
encoder.flush();
baos.close();
byte[] data = baos.toByteArray();

ByteBuffer wrapped = ByteBuffer.wrap(data);
Integer theInt = wrapped.getInt();
byte[] event = new byte[wrapped.remaining()];
wrapped.get(event);

DatumReader<GenericRecord> reader = new GenericDatumReader<>(mainSchema);
BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(event, null);
GenericRecord record = reader.read(null, decoder);

System.out.println("theInt:" + theInt);   // should print 67
System.out.println("record:" + record);   // should print:    {"code": 0, "nickName": "", "lastName": ""}
...