Пътеводител за Apache Avro

1. Общ преглед

Сериализацията на данни е техника за преобразуване на данни в двоичен или текстов формат. Налични са множество системи за тази цел. Apache Avro е една от тези системи за сериализация на данни.

Avro е езиково независима, базирана на схеми библиотека за сериализация на данни . Той използва схема за извършване на сериализация и десериализация. Освен това Avro използва JSON формат, за да определи структурата на данните, което я прави по-мощна.

В този урок ще разгледаме повече за настройката на Avro, API на Java за извършване на сериализация и сравнение на Avro с други системи за сериализация на данни.

Ще се съсредоточим предимно върху създаването на схема, която е в основата на цялата система.

2. Apache Avro

Avro е езиково независима библиотека за сериализация. За целта Avro използва схема, която е един от основните компоненти. Той съхранява схемата във файл за по-нататъшна обработка на данни .

Avro е най-подходящ за обработка на големи данни. Той е доста популярен в света на Hadoop и Kafka заради по-бързата му обработка.

Avro създава файл с данни, където съхранява данни заедно със схема в раздела си с метаданни. Преди всичко той осигурява богата структура от данни, което го прави по-популярен от други подобни решения.

За да използваме Avro за сериализация, трябва да следваме стъпките, споменати по-долу.

3. Посочване на проблема

Нека започнем с дефинирането на клас, наречен AvroHttRequest , който ще използваме за нашите примери. Класът съдържа както примитивни, така и сложни атрибути на типа:

class AvroHttpRequest { private long requestTime; private ClientIdentifier clientIdentifier; private List employeeNames; private Active active; } 

Тук requestTime е примитивна стойност. ClientIdentifier е друг клас, който представлява сложен тип. Имаме и workerName, което отново е сложен тип. Активно е изброяване, за да се опише дали даден списък със служители е активен или не.

Нашата цел е да сериализираме и десериализираме класа AvroHttRequest с помощта на Apache Avro.

4. Типове данни на Avro

Преди да продължим по-нататък, нека обсъдим типовете данни, поддържани от Avro.

Avro поддържа два вида данни:

  • Примитивен тип: Avro поддържа всички примитивни типове. Използваме примитивно име на тип, за да дефинираме тип на дадено поле. Например стойност, която съдържа String, трябва да бъде декларирана като {“type”: “string”} в Schema
  • Комплексен тип: Avro поддържа шест вида сложни типове: записи, изброявания, масиви, карти, обединения и фиксирани

Например в нашата декларация за проблем ClientIdentifier е запис.

В този случай схемата за ClientIdentifier трябва да изглежда така:

{ "type":"record", "name":"ClientIdentifier", "namespace":"com.baeldung.avro", "fields":[ { "name":"hostName", "type":"string" }, { "name":"ipAddress", "type":"string" } ] }

5. Използване на Avro

Като начало, нека добавим зависимостите Maven, които са ни необходими, към нашия файл pom.xml .

Трябва да включим следните зависимости:

  • Apache Avro - основни компоненти
  • Компилатор - Apache Avro Compilers за Avro IDL и Avro Specific Java APIT
  • Инструменти - който включва инструменти и помощни програми на Apache Avro
  • Apache Avro Maven Plugin за проекти на Maven

Използваме версия 1.8.2 за този урок.

Винаги обаче се препоръчва да намерите най-новата версия на Maven Central:

 org.apache.avro avro-compiler 1.8.2   org.apache.avro avro-maven-plugin 1.8.2 

След добавяне на зависимости maven, следващите стъпки ще бъдат:

  • Създаване на схема
  • Четене на схемата в нашата програма
  • Сериализиране на нашите данни с помощта на Avro
  • Накрая десериализирайте данните

6. Създаване на схема

Avro описва своята схема, използвайки JSON формат. Има основно четири атрибута за дадена схема на Avro:

  • Тип - който описва типа на схемата, независимо дали е сложен тип или примитивна стойност
  • Пространство от имена - което описва пространството от имена, към което принадлежи дадената схема
  • Име - името на схемата
  • Полета - което разказва за полетата, свързани с дадена схема. Полетата могат да бъдат както от примитивен, така и от сложен тип .

Един от начините за създаване на схемата е да се напише представяне на JSON, както видяхме в предишните раздели.

Можем също да създадем схема, използвайки SchemaBuilder, което безспорно е по-добър и ефективен начин за създаването й.

6.1. Помощна програма SchemaBuilder

Класът org.apache.avro.SchemaBuilder е полезен за създаване на схемата.

Първо, нека създадем схемата за ClientIdentifier:

Schema clientIdentifier = SchemaBuilder.record("ClientIdentifier") .namespace("com.baeldung.avro") .fields().requiredString("hostName").requiredString("ipAddress") .endRecord();

Сега, нека използваме това за създаване на схема avroHttpRequest :

Schema avroHttpRequest = SchemaBuilder.record("AvroHttpRequest") .namespace("com.baeldung.avro") .fields().requiredLong("requestTime") .name("clientIdentifier") .type(clientIdentifier) .noDefault() .name("employeeNames") .type() .array() .items() .stringType() .arrayDefault(null) .name("active") .type() .enumeration("Active") .symbols("YES","NO") .noDefault() .endRecord();

Тук е важно да се отбележи, че сме присвоили clientIdentifier като тип за полето clientIdentifier . В този случай clientIdentifier, използван за дефиниране на тип, е същата схема, която създадохме преди.

По-късно можем да приложим метода toString , за да получим JSON структурата на Schema .

Файловете на схемата се записват с помощта на разширението .avsc . Нека запазим нашата генерирана схема във файла “src / main / resources / avroHttpRequest-schema.avsc” .

7. Четене на схемата

Четенето на схема е горе-долу създаването на Avro класове за дадената схема . След като Avro класовете са създадени, можем да ги използваме за сериализиране и десериализиране на обекти.

Има два начина за създаване на класове Avro:

  • Програмно генериране на класове Avro: Класовете могат да се генерират с помощта на SchemaCompiler . Има няколко API, които можем да използваме за генериране на Java класове. Можем да намерим кода за класове за генериране на GitHub.
  • Използване на Maven за генериране на класове

Имаме един плъгин maven, който върши добре работата. Трябва да включим приставката и да стартираме mvn clean install .

Нека добавим приставката към нашия файл pom.xml :

 org.apache.avro avro-maven-plugin ${avro.version}   schemas generate-sources  schema protocol idl-protocol   ${project.basedir}/src/main/resources/ ${project.basedir}/src/main/java/     

8. Сериализация и десериализация с Avro

Като приключихме с генерирането на схемата, нека продължим да изследваме частта за сериализация.

Има два формата за сериализация на данни, които Avro поддържа: JSON формат и двоичен формат.

Първо ще се съсредоточим върху JSON формата и след това ще обсъдим двоичния формат.

Преди да продължим по-нататък, трябва да преминем през няколко ключови интерфейса. Можем да използваме интерфейсите и класовете по-долу за сериализация:

DatumWriter: We should use this to write data on a given Schema. We'll be using the SpecificDatumWriter implementation in our example, however, DatumWriter has other implementations as well. Other implementations are GenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.

Encoder: Encoder is used or defining the format as previously mentioned. EncoderFactory provides two types of encoders, binary encoder, and JSON encoder.

DatumReader: Single interface for de-serialization. Again, it got multiple implementations, but we'll be using SpecificDatumReader in our example. Other implementations are- GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.

Decoder: Decoder is used while de-serializing the data. Decoderfactory provides two types of decoders: binary decoder and JSON decoder.

Next, let's see how serialization and de-serialization happen in Avro.

8.1. Serialization

We'll take the example of AvroHttpRequest class and try to serialize it using Avro.

First of all, let's serialize it in JSON format:

public byte[] serealizeAvroHttpRequestJSON( AvroHttpRequest request) { DatumWriter writer = new SpecificDatumWriter( AvroHttpRequest.class); byte[] data = new byte[0]; ByteArrayOutputStream stream = new ByteArrayOutputStream(); Encoder jsonEncoder = null; try { jsonEncoder = EncoderFactory.get().jsonEncoder( AvroHttpRequest.getClassSchema(), stream); writer.write(request, jsonEncoder); jsonEncoder.flush(); data = stream.toByteArray(); } catch (IOException e) { logger.error("Serialization error:" + e.getMessage()); } return data; } 

Let's have a look at a test case for this method:

@Test public void whenSerialized_UsingJSONEncoder_ObjectGetsSerialized(){ byte[] data = serealizer.serealizeAvroHttpRequestJSON(request); assertTrue(Objects.nonNull(data)); assertTrue(data.length > 0); }

Here we've used the jsonEncoder method and passing the schema to it.

If we wanted to use a binary encoder, we need to replace the jsonEncoder() method with binaryEncoder():

Encoder jsonEncoder = EncoderFactory.get().binaryEncoder(stream,null);

8.2. Deserialization

To do this, we'll be using the above-mentioned DatumReader and Decoder interfaces.

As we used EncoderFactory to get an Encoder, similarly we'll use DecoderFactory to get a Decoder object.

Let's de-serialize the data using JSON format:

public AvroHttpRequest deSerealizeAvroHttpRequestJSON(byte[] data) { DatumReader reader = new SpecificDatumReader(AvroHttpRequest.class); Decoder decoder = null; try { decoder = DecoderFactory.get().jsonDecoder( AvroHttpRequest.getClassSchema(), new String(data)); return reader.read(null, decoder); } catch (IOException e) { logger.error("Deserialization error:" + e.getMessage()); } } 

And let's see the test case:

@Test public void whenDeserializeUsingJSONDecoder_thenActualAndExpectedObjectsAreEqual(){ byte[] data = serealizer.serealizeAvroHttpRequestJSON(request); AvroHttpRequest actualRequest = deSerealizer .deSerealizeAvroHttpRequestJSON(data); assertEquals(actualRequest,request); assertTrue(actualRequest.getRequestTime() .equals(request.getRequestTime())); }

Similarly, we can use a binary decoder:

Decoder decoder = DecoderFactory.get().binaryDecoder(data, null);

9. Conclusion

Apache Avro е особено полезен при работа с големи данни. Той предлага сериализация на данни в двоичен, както и JSON формат, който може да се използва според случая на употреба.

Процесът на сериализация на Avro е по-бърз и също така е космически ефективен. Avro не съхранява информация за типа поле с всяко поле; вместо това създава метаданни в схема.

Не на последно място Avro има страхотна подвързия с широк спектър от езици за програмиране, което му дава предимство.

Както винаги, кодът може да бъде намерен в GitHub.