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 Sí Sí
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 2026. Tots els drets reservats