Gids voor Apache Avro

1. Overzicht

Dataserialisatie is een techniek om gegevens om te zetten in binaire of tekstindeling. Hiervoor zijn meerdere systemen beschikbaar. Apache Avro is een van die dataserialisatiesystemen.

Avro is een taalonafhankelijke, op schema's gebaseerde gegevensserialisatiebibliotheek. Het gebruikt een schema om serialisatie en deserialisatie uit te voeren. Bovendien gebruikt Avro een JSON-formaat om de datastructuur te specificeren, waardoor het krachtiger wordt.

In deze zelfstudie zullen we meer onderzoeken over de installatie van Avro, de Java API om serialisatie uit te voeren en een vergelijking van Avro met andere gegevensserialisatiesystemen.

We zullen ons voornamelijk concentreren op het maken van schema's, dat de basis vormt van het hele systeem.

2. Apache Avro

Avro is een taalonafhankelijke serialisatiebibliotheek. Om dit te doen, gebruikt Avro een schema dat een van de kerncomponenten is. Het slaat het schema op in een bestand voor verdere gegevensverwerking.

Avro is het meest geschikt voor Big Data-verwerking. Het is behoorlijk populair in de Hadoop- en Kafka-wereld vanwege de snellere verwerking.

Avro maakt een gegevensbestand waarin het gegevens samen met het schema bewaart in de metagegevenssectie. Bovendien biedt het een rijke datastructuur waardoor het populairder is dan andere vergelijkbare oplossingen.

Om Avro te gebruiken voor serialisatie, moeten we de onderstaande stappen volgen.

3. Probleemstelling

Laten we beginnen met het definiëren van een klasse genaamd AvroHttRequest die we zullen gebruiken voor onze voorbeelden. De klasse bevat zowel primitieve als complexe typekenmerken:

klasse AvroHttpRequest {privé lange requestTime; privé ClientIdentifier clientIdentifier; privélijst employeeNames; privé Actief actief; } 

Hier, requestTime is een primitieve waarde. ClientIdentifier is een andere klasse die een complex type vertegenwoordigt. We hebben ook Naam werknemer wat weer een complex type is. Actief is een opsomming om te beschrijven of de gegeven lijst met werknemers actief is of niet.

Ons doel is om het AvroHttRequest klasse met behulp van Apache Avro.

4. Avro-gegevenstypen

Laten we, voordat we verder gaan, de gegevenstypen bespreken die door Avro worden ondersteund.

Avro ondersteunt twee soorten gegevens:

  • Primitief type: Avro ondersteunt alle primitieve typen. We gebruiken primitieve typenaam om een ​​type van een bepaald veld te definiëren. Bijvoorbeeld een waarde die een Draad moet worden gedeclareerd als {"type": "string"} in Schema
  • Complex type: Avro ondersteunt zes soorten complexe typen: records, enums, arrays, kaarten, unions en fixed

In onze probleemstelling bijvoorbeeld, ClientIdentifier is een record.

In dat geval schema voor ClientIdentifier zou eruit moeten zien:

{"type": "record", "naam": "ClientIdentifier", "naamruimte": "com.baeldung.avro", "velden": [{"naam": "hostnaam", "type": "string" }, {"name": "ipAddress", "type": "string"}]}

5. Avro gebruiken

Laten we om te beginnen de Maven-afhankelijkheden die we nodig hebben toevoegen aan onze pom.xml het dossier.

We moeten de volgende afhankelijkheden opnemen:

  • Apache Avro - kerncomponenten
  • Compiler - Apache Avro-compilers voor Avro IDL en Avro-specifieke Java APIT
  • Tools - inclusief Apache Avro-opdrachtregelhulpprogramma's en hulpprogramma's
  • Apache Avro Maven-plug-in voor Maven-projecten

We gebruiken versie 1.8.2 voor deze tutorial.

Het is echter altijd aan te raden om de nieuwste versie op Maven Central te vinden:

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

Na het toevoegen van maven-afhankelijkheden, zijn de volgende stappen:

  • Schema maken
  • Het schema in ons programma lezen
  • Serialisatie van onze gegevens met behulp van Avro
  • Maak ten slotte de serialisering van de gegevens ongedaan

6. Schema maken

Avro beschrijft zijn schema met behulp van een JSON-indeling. Er zijn hoofdzakelijk vier attributen voor een bepaald Avro-schema:

  • Type- die het type schema beschrijft, of het nu een complex type is of een primitieve waarde
  • Naamruimte die de naamruimte beschrijft waartoe het gegeven schema behoort
  • Naam - de naam van het schema
  • Veld- die vertelt over de velden die zijn gekoppeld aan een bepaald schema. Velden kunnen zowel van primitief als complex type zijn.

Een manier om het schema te maken, is door de JSON-weergave te schrijven, zoals we in de vorige secties hebben gezien.

We kunnen ook een schema maken met SchemaBuilder wat ontegensprekelijk een betere en efficiënte manier is om het te creëren.

6.1. SchemaBuilder Nut

De klas org.apache.avro.SchemaBuilder is handig voor het maken van het schema.

Laten we eerst het schema maken voor ClientIdentifier:

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

Laten we dit nu gebruiken om een avroHttpRequest schema:

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

Het is belangrijk op te merken dat we hebben toegewezen clientIdentifier als het type voor de clientIdentifier veld. In dit geval, clientIdentifier gebruikt om type te definiëren is hetzelfde schema dat we eerder hebben gemaakt.

Later kunnen we de toString methode om de JSON structuur van Schema.

Schemabestanden worden opgeslagen met de extensie .avsc. Laten we ons gegenereerde schema opslaan in het "Src / main / resources / avroHttpRequest-schema.avsc" het dossier.

7. Lezen van het schema

Het lezen van een schema gaat min of meer over Avro-klassen maken voor het gegeven schema. Zodra Avro-klassen zijn gemaakt, kunnen we ze gebruiken om objecten te serialiseren en deserialiseren.

Er zijn twee manieren om Avro-klassen te maken:

  • Programmatisch Avro-klassen genereren: Klassen kunnen worden gegenereerd met SchemaCompiler. Er zijn een aantal API's die we kunnen gebruiken om Java-klassen te genereren. We kunnen de code voor generatieklassen vinden op GitHub.
  • Maven gebruiken om klassen te genereren

We hebben één maven-plug-in die het werk goed doet. We moeten de plug-in opnemen en uitvoeren mvn schone installatie.

Laten we de plug-in toevoegen aan onze pom.xml het dossier:

 org.apache.avro avro-maven-plugin $ {avro.version} schema's genereren-bronnen schemaprotocol idl-protocol $ {project.basedir} / src / main / resources / $ {project.basedir} / src / main / java / 

8. Serialisatie en deserialisering met Avro

Nu we klaar zijn met het genereren van het schema, gaan we verder met het verkennen van het serialisatiegedeelte.

Er zijn twee gegevensserialisatie-indelingen die Avro ondersteunt: JSON-indeling en Binair-indeling.

Eerst concentreren we ons op het JSON-formaat en vervolgens bespreken we het binaire formaat.

Voordat we verder gaan, moeten we enkele belangrijke interfaces doorlopen. We kunnen de onderstaande interfaces en klassen gebruiken voor serialisering:

DatumSchrijver: We zouden dit moeten gebruiken om gegevens op een bepaald schema te schrijven. We gebruiken de SpecificDatumWriter implementatie in ons voorbeeld, echter DatumWriter heeft ook andere implementaties. Andere implementaties zijn GenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.

Encoder: Encoder wordt gebruikt of definieert het formaat zoals eerder vermeld. EncoderFactory biedt twee soorten encoders, binaire encoder en JSON-encoder.

DatumReader: Enkele interface voor de-serialisering. Nogmaals, het heeft meerdere implementaties, maar we zullen het gebruiken SpecificDatumReader in ons voorbeeld. Andere implementaties zijn- GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.

Decoder: Decoder wordt gebruikt bij het deserialiseren van de gegevens. Decoderfabriek biedt twee soorten decoders: binaire decoder en JSON-decoder.

Laten we vervolgens eens kijken hoe serialisatie en deserialisatie plaatsvinden in Avro.

8.1. Serialisatie

We nemen het voorbeeld van AvroHttpRequest class en probeer het te serialiseren met Avro.

Laten we allereerst het serialiseren in JSON-indeling:

openbare byte [] serealizeAvroHttpRequestJSON (AvroHttpRequest-verzoek) {DatumWriter-schrijver = nieuwe SpecificDatumWriter (AvroHttpRequest.class); byte [] data = nieuwe byte [0]; ByteArrayOutputStream stream = nieuwe ByteArrayOutputStream (); Encoder jsonEncoder = null; probeer {jsonEncoder = EncoderFactory.get (). jsonEncoder (AvroHttpRequest.getClassSchema (), stream); writer.write (verzoek, jsonEncoder); jsonEncoder.flush (); data = stream.toByteArray (); } catch (IOException e) {logger.error ("Serialisatiefout:" + e.getMessage ()); } gegevens retourneren; } 

Laten we eens kijken naar een testcase voor deze methode:

@Test openbare leegte whenSerialized_UsingJSONEncoder_ObjectGetsSerialized () {byte [] data = serealizer.serealizeAvroHttpRequestJSON (verzoek); assertTrue (Objects.nonNull (data)); assertTrue (data.length> 0); }

Hier hebben we de jsonEncoder methode en het schema eraan doorgeven.

Als we een binaire encoder willen gebruiken, moeten we de jsonEncoder () methode met binaryEncoder ():

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

8.2. Deserialisatie

Om dit te doen, gebruiken we de bovengenoemde DatumReader en Decoder interfaces.

Zoals we gebruikten EncoderFactory om een Encoder, op dezelfde manier zullen we gebruiken DecoderFactory om een Decoder voorwerp.

Laten we de gegevens deserialiseren met behulp van het JSON-formaat:

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

En laten we de testcase bekijken:

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

Evenzo kunnen we een binaire decoder gebruiken:

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

9. Conclusie

Apache Avro is vooral handig bij het omgaan met big data. Het biedt dataserialisatie in zowel binaire als JSON-indeling die kan worden gebruikt volgens het gebruiksscenario.

Het Avro-serialisatieproces is sneller en ook ruimtebesparend. Avro bewaart de veldtype-informatie niet bij elk veld; in plaats daarvan creëert het metadata in een schema.

Last but not least heeft Avro een geweldige binding met een breed scala aan programmeertalen, wat het een voorsprong geeft.

Zoals altijd is de code te vinden op GitHub.