Guide d'Apache Avro

1. Vue d'ensemble

La sérialisation des données est une technique de conversion de données au format binaire ou texte. Il existe plusieurs systèmes disponibles à cet effet. Apache Avro est l'un de ces systèmes de sérialisation de données.

Avro est une bibliothèque de sérialisation de données basée sur des schémas et indépendante du langage . Il utilise un schéma pour effectuer la sérialisation et la désérialisation. De plus, Avro utilise un format JSON pour spécifier la structure de données qui la rend plus puissante.

Dans ce didacticiel, nous explorerons plus en détail la configuration d'Avro, l'API Java pour effectuer la sérialisation et une comparaison d'Avro avec d'autres systèmes de sérialisation de données.

Nous nous concentrerons principalement sur la création de schéma qui est la base de l'ensemble du système.

2. Apache Avro

Avro est une bibliothèque de sérialisation indépendante du langage. Pour ce faire, Avro utilise un schéma qui est l'un des composants principaux. Il stocke le schéma dans un fichier pour un traitement ultérieur des données .

Avro est la meilleure solution pour le traitement des Big Data. Il est très populaire dans le monde Hadoop et Kafka pour son traitement plus rapide.

Avro crée un fichier de données dans lequel il conserve les données avec le schéma dans sa section de métadonnées. Surtout, il fournit une structure de données riche qui le rend plus populaire que d'autres solutions similaires.

Pour utiliser Avro pour la sérialisation, nous devons suivre les étapes mentionnées ci-dessous.

3. Énoncé du problème

Commençons par définir une classe appelée AvroHttRequest que nous utiliserons pour nos exemples. La classe contient des attributs de type primitifs et complexes:

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

Ici, requestTime est une valeur primitive. ClientIdentifier est une autre classe qui représente un type complexe. Nous avons également employeeName qui est encore un type complexe. Active est une énumération pour décrire si la liste d'employés donnée est active ou non.

Notre objectif est de sérialiser et de désérialiser la classe AvroHttRequest à l' aide d'Apache Avro.

4. Types de données Avro

Avant de continuer, discutons des types de données pris en charge par Avro.

Avro prend en charge deux types de données:

  • Type primitif: Avro prend en charge tous les types primitifs. Nous utilisons le nom de type primitif pour définir un type d'un champ donné. Par exemple, une valeur qui contient une chaîne doit être déclarée comme {"type": "string"} dans Schema
  • Type complexe: Avro prend en charge six types de types complexes: enregistrements, énumérations, tableaux, cartes, unions et fixes

Par exemple, dans notre énoncé de problème, ClientIdentifier est un enregistrement.

Dans ce cas, le schéma de ClientIdentifier devrait ressembler à ceci :

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

5. Utilisation d'Avro

Pour commencer, ajoutons les dépendances Maven dont nous aurons besoin dans notre fichier pom.xml .

Nous devrions inclure les dépendances suivantes:

  • Apache Avro - composants de base
  • Compilateur - Compilateurs Apache Avro pour Avro IDL et Avro Specific Java APIT
  • Outils - qui comprend les outils et utilitaires de ligne de commande Apache Avro
  • Plugin Apache Avro Maven pour les projets Maven

Nous utilisons la version 1.8.2 pour ce tutoriel.

Cependant, il est toujours conseillé de trouver la dernière version sur Maven Central:

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

Après avoir ajouté les dépendances maven, les prochaines étapes seront:

  • Création de schéma
  • Lire le schéma dans notre programme
  • Sérialisation de nos données avec Avro
  • Enfin, désérialisez les données

6. Création de schéma

Avro décrit son schéma en utilisant un format JSON. Il existe principalement quatre attributs pour un schéma Avro donné:

  • Type - qui décrit le type de schéma, que ce soit son type complexe ou sa valeur primitive
  • Namespace - qui décrit l'espace de noms auquel appartient le schéma donné
  • Nom - le nom du schéma
  • Champs - qui raconte les champs associés à un schéma donné. Les champs peuvent être de type primitif ou complexe .

Une façon de créer le schéma consiste à écrire la représentation JSON, comme nous l'avons vu dans les sections précédentes.

Nous pouvons également créer un schéma à l'aide de SchemaBuilder, ce qui est indéniablement un moyen meilleur et efficace de le créer.

6.1. Utilitaire SchemaBuilder

La classe org.apache.avro.SchemaBuilder est utile pour créer le schéma.

Tout d'abord, créons le schéma pour ClientIdentifier:

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

Maintenant, utilisons ceci pour créer un schéma 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();

Il est important de noter ici que nous avons attribué clientIdentifier comme type pour le champ clientIdentifier . Dans ce cas, clientIdentifier utilisé pour définir le type est le même schéma que nous avons créé auparavant.

Plus tard, nous pouvons appliquer la méthode toString pour obtenir la structure JSON de Schema .

Les fichiers de schéma sont enregistrés à l'aide de l'extension .avsc . Sauvegardons notre schéma généré dans le fichier «src / main / resources / avroHttpRequest-schema.avsc» .

7. Lecture du schéma

La lecture d'un schéma consiste plus ou moins à créer des classes Avro pour le schéma donné . Une fois les classes Avro créées, nous pouvons les utiliser pour sérialiser et désérialiser des objets.

Il existe deux façons de créer des classes Avro:

  • Génération de classes Avro par programme: les classes peuvent être générées à l'aide de SchemaCompiler . Il existe quelques API que nous pouvons utiliser pour générer des classes Java. Nous pouvons trouver le code des classes de génération sur GitHub.
  • Utiliser Maven pour générer des classes

Nous avons un plugin maven qui fait bien le travail. Nous devons inclure le plugin et exécuter mvn clean install .

Ajoutons le plugin à notre fichier 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. Sérialisation et désérialisation avec Avro

Comme nous en avons terminé avec la génération du schéma, continuons à explorer la partie sérialisation.

Il existe deux formats de sérialisation de données pris en charge par Avro: le format JSON et le format binaire.

Tout d'abord, nous allons nous concentrer sur le format JSON, puis nous discuterons du format binaire.

Avant d'aller plus loin, nous devons passer par quelques interfaces clés. Nous pouvons utiliser les interfaces et les classes ci-dessous pour la sérialisation:

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 est particulièrement utile lorsqu'il s'agit de Big Data. Il offre une sérialisation des données au format binaire et JSON qui peut être utilisé selon le cas d'utilisation.

Le processus de sérialisation Avro est plus rapide et peu encombrant. Avro ne conserve pas les informations de type de champ avec chaque champ; à la place, il crée des métadonnées dans un schéma.

Enfin, Avro a une excellente reliure avec un large éventail de langages de programmation, ce qui lui donne un avantage.

Comme toujours, le code peut être trouvé sur GitHub.