Introducció

La serialització és el procés de convertir un objecte en una seqüència de bytes per emmagatzemar-lo o transmetre'l a través d'una xarxa. En el context de Hadoop, la serialització és crucial per a l'emmagatzematge i la transmissió eficient de dades entre nodes del clúster. Aquest mòdul cobreix els conceptes bàsics de la serialització de dades en Hadoop, les seves eines i biblioteques, i com optimitzar el procés per a un rendiment millor.

Conceptes clau

  1. Serialització: Conversió d'objectes en una seqüència de bytes.
  2. Deserialització: Conversió de la seqüència de bytes en objectes.
  3. Eficàcia: La serialització ha de ser ràpida i generar una sortida compacta.
  4. Compatibilitat: La serialització ha de ser compatible amb versions anteriors i futures.

Eines i biblioteques de serialització en Hadoop

Writable Interface

Hadoop utilitza la interfície Writable per a la serialització de dades. Aquesta interfície defineix dos mètodes:

  • write(DataOutput out): Escriu l'objecte en un flux de sortida.
  • readFields(DataInput in): Llegeix els camps de l'objecte des d'un flux d'entrada.

Exemple de codi

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;

public class CustomWritable implements Writable {
    private int id;
    private String name;

    // Constructor per defecte
    public CustomWritable() {}

    // Constructor amb paràmetres
    public CustomWritable(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(id);
        out.writeUTF(name);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        id = in.readInt();
        name = in.readUTF();
    }

    @Override
    public String toString() {
        return id + "\t" + name;
    }
}

Avro

Apache Avro és un sistema de serialització de dades que proporciona un format de dades compacte, ràpid i compatible amb versions anteriors. Avro utilitza esquemes per definir l'estructura de les dades.

Exemple de codi

  1. Definició de l'esquema Avro (schema.avsc)
{
  "type": "record",
  "name": "User",
  "fields": [
    {"name": "id", "type": "int"},
    {"name": "name", "type": "string"}
  ]
}
  1. Serialització i deserialització amb Avro
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class AvroExample {
    public static void main(String[] args) throws IOException {
        // Carregar l'esquema
        Schema schema = new Schema.Parser().parse(new File("schema.avsc"));

        // Crear un registre genèric
        GenericRecord user = new GenericData.Record(schema);
        user.put("id", 1);
        user.put("name", "John Doe");

        // Serialitzar el registre
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DatumWriter<GenericRecord> writer = new SpecificDatumWriter<>(schema);
        Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
        writer.write(user, encoder);
        encoder.flush();
        out.close();

        // Deserialitzar el registre
        DatumReader<GenericRecord> reader = new SpecificDatumReader<>(schema);
        Decoder decoder = DecoderFactory.get().binaryDecoder(out.toByteArray(), null);
        GenericRecord result = reader.read(null, decoder);

        System.out.println(result);
    }
}

Protocol Buffers

Protocol Buffers (protobuf) és una altra eina de serialització desenvolupada per Google. És similar a Avro però utilitza un llenguatge de definició d'interfícies (IDL) per definir l'esquema.

Exemple de codi

  1. Definició de l'esquema protobuf (user.proto)
syntax = "proto3";

message User {
  int32 id = 1;
  string name = 2;
}
  1. Serialització i deserialització amb Protocol Buffers
import com.example.UserProtos.User;

public class ProtobufExample {
    public static void main(String[] args) throws IOException {
        // Crear un objecte User
        User user = User.newBuilder()
                .setId(1)
                .setName("John Doe")
                .build();

        // Serialitzar l'objecte
        byte[] serializedData = user.toByteArray();

        // Deserialitzar l'objecte
        User deserializedUser = User.parseFrom(serializedData);

        System.out.println(deserializedUser);
    }
}

Comparació de biblioteques de serialització

Característica Writable Avro Protocol Buffers
Esquema No
Compatibilitat Manual Automàtica Automàtica
Velocitat Alta Mitjana Alta
Facilitat d'ús Baixa Alta Alta
Suport de llenguatges Java Multi-llenguatge Multi-llenguatge

Exercicis pràctics

Exercici 1: Crear una classe Writable

  1. Crea una classe EmployeeWritable que implementi la interfície Writable.
  2. Defineix els camps id (int) i name (String).
  3. Implementa els mètodes write i readFields.

Solució

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;

public class EmployeeWritable implements Writable {
    private int id;
    private String name;

    public EmployeeWritable() {}

    public EmployeeWritable(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(id);
        out.writeUTF(name);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        id = in.readInt();
        name = in.readUTF();
    }

    @Override
    public String toString() {
        return id + "\t" + name;
    }
}

Exercici 2: Serialitzar i deserialitzar amb Avro

  1. Defineix un esquema Avro per a un objecte Product amb els camps id (int) i name (String).
  2. Escriu un programa Java per serialitzar i deserialitzar un objecte Product utilitzant Avro.

Solució

  1. Definició de l'esquema Avro (product.avsc)
{
  "type": "record",
  "name": "Product",
  "fields": [
    {"name": "id", "type": "int"},
    {"name": "name", "type": "string"}
  ]
}
  1. Serialització i deserialització amb Avro
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

public class AvroProductExample {
    public static void main(String[] args) throws IOException {
        // Carregar l'esquema
        Schema schema = new Schema.Parser().parse(new File("product.avsc"));

        // Crear un registre genèric
        GenericRecord product = new GenericData.Record(schema);
        product.put("id", 101);
        product.put("name", "Laptop");

        // Serialitzar el registre
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DatumWriter<GenericRecord> writer = new SpecificDatumWriter<>(schema);
        Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
        writer.write(product, encoder);
        encoder.flush();
        out.close();

        // Deserialitzar el registre
        DatumReader<GenericRecord> reader = new SpecificDatumReader<>(schema);
        Decoder decoder = DecoderFactory.get().binaryDecoder(out.toByteArray(), null);
        GenericRecord result = reader.read(null, decoder);

        System.out.println(result);
    }
}

Conclusió

La serialització de dades és un component essencial en Hadoop per a l'emmagatzematge i la transmissió eficient de dades. Hem explorat diverses eines i biblioteques de serialització, com Writable, Avro i Protocol Buffers, i hem vist com utilitzar-les amb exemples pràctics. La comprensió d'aquests conceptes i eines permetrà als desenvolupadors optimitzar el rendiment de les seves aplicacions Hadoop i assegurar la compatibilitat de dades a llarg termini.

© Copyright 2024. Tots els drets reservats