Как десериализовать файлы avro

Я хотел бы прочитать папку hdfs, содержащую файлы avro с spark. Затем я хотел бы десериализовать события avro, содержащиеся в этих файлах. Я хотел бы сделать это без библиотеки com.databrics (или любой другой, позволяющей легко это сделать).

Проблема в том, что у меня проблемы с десериализацией.

Я предполагаю, что мой файл avro сжат с помощью snappy, потому что в начале файла (сразу после схемы) у меня есть

avro.codecsnappy

написано. Затем следуют читаемые или нечитаемые символы.

Моя первая попытка десериализации события avro следующая:

public static String deserialize(String message) throws IOException {
    Schema.Parser schemaParser = new Schema.Parser();
    Schema avroSchema = schemaParser.parse(defaultFlumeAvroSchema);

    DatumReader<GenericRecord> specificDatumReader = new SpecificDatumReader<GenericRecord>(avroSchema);
    
    byte[] messageBytes = message.getBytes();
    Decoder decoder = DecoderFactory.get().binaryDecoder(messageBytes, null);
    GenericRecord genericRecord = specificDatumReader.read(null, decoder);

    return genericRecord.toString();
}

Эта функция работает, когда я хочу десериализовать файл avro, в котором нет avro.codecsbappy. Когда это так, у меня есть ошибка:

Неправильные данные: отрицательная длина: -50

Поэтому я попробовал сделать это по-другому:

    private static void deserialize2(String path) throws IOException {
    DatumReader<GenericRecord> reader = new GenericDatumReader<>();
    DataFileReader<GenericRecord> fileReader =
            new DataFileReader<>(new File(path), reader);
    System.out.println(fileReader.getSchema().toString());

    GenericRecord record = new GenericData.Record(fileReader.getSchema());

    int numEvents = 0;
    while (fileReader.hasNext()) {
        fileReader.next(record);
        ByteBuffer body = (ByteBuffer) record.get("body");
        CharsetDecoder decoder = Charsets.UTF_8.newDecoder();
        System.out.println("Positon of the index " + body.position());
        System.out.println("Size of the array : " + body.array().length);
        String bodyStr = decoder.decode(body).toString();
        System.out.println("THE BODY STRING  ---> " bodyStr);
        numEvents++;
    }
    fileReader.close();
}

и возвращает следующий результат:

Положение индекса 0

Размер массива: 127482

СТРОКА ТЕЛА --- ›

Я вижу, что массив не пуст, а просто возвращает пустую строку.

Как я могу продолжить?


person Robert Reynolds    schedule 24.01.2019    source источник


Ответы (2)


Используйте это при преобразовании в строку:

String bodyStr = new String(body.array());
System.out.println("THE BODY STRING  ---> " + bodyStr);

Источник: https://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

person Viggo Lundén    schedule 24.01.2019
comment
Не комментируйте, как «Попробуй это, сделай это». Пожалуйста, объясните проблему и способы ее решения. - person Deepak Kumar; 24.01.2019
comment
он не компилируется, конструктор String не принимает byteBuffer как параметр - person Robert Reynolds; 24.01.2019
comment
к сожалению результат тот же. - person Robert Reynolds; 24.01.2019
comment
Перед запуском я бы попытался проверить, body.hasArray() не false. - person Giovanni; 24.01.2019
comment
Я сделал, это было правдой. - person Robert Reynolds; 24.01.2019

Что ж, похоже, вы на правильном пути. Однако ваш ByteBuffer может не иметь правильного массива byte[] для декодирования, поэтому давайте попробуем вместо этого следующее:

byte[] bytes = new byte[body.remaining()];
buffer.get(bytes);
String result = new String(bytes, "UTF-8"); // Maybe you need to change charset

Это должно сработать, вы показали в своем вопросе, что ByteBuffer содержит фактические данные, как указано в примере кода, вам, возможно, придется изменить кодировку.

Список кодировок: https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html

Также полезно: https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html

person Giovanni    schedule 24.01.2019
comment
Жаль, что строка просто пуста? Или в нем есть странные персонажи? - person Giovanni; 24.01.2019
comment
0 символов, так тупо, что раньше не проверял. С другой стороны, я думаю, что моя десериализация с помощью метода deserialize2 просто не работает, потому что я удалил часть мгновенного сжатия, и она также не работает, что неожиданно. - person Robert Reynolds; 24.01.2019