Domínio da Serialização Mágica

HadoopBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como otimizar o processo de catalogação da vasta coleção de tomos mágicos na ilustre Academia Mágica. Através do poder do Hadoop MapReduce, você lidará com a serialização dos dados dos livros, garantindo um processamento e análise contínuos. Isso permitirá que você armazene e processe as informações dos livros de forma eficiente, atendendo, em última análise, melhor aos professores e alunos da academia.

Implementando a Interface Writable

Nesta etapa, criaremos uma classe Writable personalizada para representar os dados do livro. Esta classe implementará a interface Writable fornecida pelo Apache Hadoop, permitindo a serialização e desserialização eficientes de dados durante o processo MapReduce.

Primeiramente, você precisa usar o comando su - hadoop para se tornar um usuário hadoop e criar um novo arquivo Java chamado Book.java no diretório /home/hadoop com o seguinte conteúdo:

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

// A classe Book representa um livro com título, autor e ano de publicação.
// Ela implementa a interface Writable para a serialização do Hadoop.
public class Book implements Writable {
    // Campos privados para o título, autor e ano de publicação do livro.
    private String title;
    private String author;
    private int year;

    // Construtor padrão - necessário para criar uma nova instância para desserialização.
    public Book() {}

    // Construtor com parâmetros para inicializar os campos com os valores fornecidos.
    public Book(String title, String author, int year) {
        this.title = title;
        this.author = author;
        this.year = year;
    }

    // O método write serializa os campos do objeto para o DataOutput.
    public void write(DataOutput out) throws IOException {
        out.writeUTF(title); // Escreve o título como UTF-8
        out.writeUTF(author); // Escreve o autor como UTF-8
        out.writeInt(year); // Escreve o ano de publicação como um inteiro
    }

    // O método readFields desserializa os campos do objeto a partir do DataInput.
    public void readFields(DataInput in) throws IOException {
        title = in.readUTF(); // Lê o título como UTF-8
        author = in.readUTF(); // Lê o autor como UTF-8
        year = in.readInt(); // Lê o ano de publicação como um inteiro
    }

    // O método toString fornece uma representação em string do objeto,
    // que é útil para impressão e registro.
    @Override
    public String toString() {
        return "Title: " + title + ", Author: " + author + ", Year: " + year;
    }

    // Getters e setters são omitidos para brevidade, mas são necessários para acessar os campos.
}

Esta classe Book contém campos para o título, autor e ano de publicação do livro. O método write serializa os dados do livro para um fluxo de bytes, enquanto o método readFields desserializa os dados de um fluxo de bytes. Ambos os métodos são exigidos pela interface Writable.

Em seguida, você precisará compilar as classes Java usando os seguintes comandos:

## Compile the Java classes
javac -source 8 -target 8 -classpath $HADOOP_HOME/share/hadoop/common/hadoop-common-3.3.6.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:. Book.java

Implementando o Mapper e o Reducer

Nesta etapa, criaremos uma classe Mapper e uma classe Reducer para processar os dados do livro usando o paradigma MapReduce.

BookMapper Personalizado

Primeiro, crie um novo arquivo Java chamado BookMapper.java no diretório /home/hadoop com o seguinte conteúdo:

import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

// BookMapper estende a classe Mapper para processar arquivos de entrada de texto
// Os pares chave-valor de entrada são LongWritable (número da linha) e Text (conteúdo da linha)
// Os pares chave-valor de saída são Text (nome do autor) e Book (detalhes do livro)
public class BookMapper extends Mapper<LongWritable, Text, Text, Book> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // Divide a linha de entrada por vírgula
        String[] bookData = value.toString().split(",");
        // Extrai o título, autor e ano da linha de entrada
        String title = bookData[0];
        String author = bookData[1];
        int year = Integer.parseInt(bookData[2]);
        // Escreve o autor e os detalhes do livro para o contexto
        context.write(new Text(author), new Book(title, author, year));
    }
}

Esta classe BookMapper recebe uma linha de dados de entrada no formato "título,autor,ano" e emite um par chave-valor com o autor como chave e um objeto Book como valor.

BookReducer Personalizado

Em seguida, crie um novo arquivo Java chamado BookReducer.java no diretório /home/hadoop com o seguinte conteúdo:

import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

// BookReducer estende a classe Reducer para agregar detalhes do livro por autor
// Os pares chave-valor de entrada são Text (nome do autor) e Book (detalhes do livro)
// Os pares chave-valor de saída são Text (nome do autor) e Book (detalhes do livro agregados)
public class BookReducer extends Reducer<Text, Book, Text, Book> {
    @Override
    protected void reduce(Text key, Iterable<Book> values, Context context) throws IOException, InterruptedException {
        // Itera pelos livros do mesmo autor e escreve cada livro para o contexto
        for (Book book : values) {
            context.write(key, book);
        }
    }
}

Esta classe BookReducer simplesmente emite os pares chave-valor de entrada como estão, efetivamente agrupando os livros por autor.

Compilar os Arquivos

Finalmente, você precisará compilar as classes Java usando os seguintes comandos:

## Compile the Java classes
javac -source 8 -target 8 -classpath $HADOOP_HOME/share/hadoop/common/hadoop-common-3.3.6.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:. BookMapper.java BookReducer.java

Executando o Job MapReduce

Nesta etapa, criaremos uma classe Driver para executar o job MapReduce e processar os dados do livro.

BookDriver Personalizado

Primeiro, crie um novo arquivo Java chamado BookDriver.java no diretório /home/hadoop com o seguinte conteúdo:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

// BookDriver configura e submete o job MapReduce
public class BookDriver {
    public static void main(String[] args) throws Exception {
        // Cria uma nova configuração de job Hadoop
        Configuration conf = new Configuration();
        // Instancia um objeto Job com a configuração do job
        Job job = Job.getInstance(conf, "Processamento de Livros");
        // Especifica o arquivo jar do job por classe
        job.setJarByClass(BookDriver.class);
        // Define a classe Mapper
        job.setMapperClass(BookMapper.class);
        // Define a classe Reducer
        job.setReducerClass(BookReducer.class);
        // Define a classe de chave de saída para o job
        job.setOutputKeyClass(Text.class);
        // Define a classe de valor de saída para o job
        job.setOutputValueClass(Book.class);
        // Define o caminho de entrada do job
        FileInputFormat.addInputPath(job, new Path(args[0]));
        // Define o caminho de saída do job
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        // Sai com o status de conclusão do job
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

Esta classe BookDriver configura e executa o job MapReduce. Ela configura o job com as classes BookMapper e BookReducer, define os caminhos de entrada e saída e aguarda a conclusão do job.

Executando o Job

Para executar o job MapReduce, você precisará compilar as classes Java e criar um arquivo JAR. Você pode usar os seguintes comandos:

## Compile the Java classes
javac -source 8 -target 8 -classpath $HADOOP_HOME/share/hadoop/common/hadoop-common-3.3.6.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:. BookDriver.java

## Create a JAR file
jar -cvf book.jar *.class

Em seguida, você precisará criar um diretório de entrada e copiar alguns dados de exemplo do livro para ele. Você pode usar os seguintes comandos:

## Create an input directory
hdfs dfs -mkdir /input

## Copy sample data to the input directory
hdfs dfs -put ./data.txt /input

Finalmente, você pode executar o job MapReduce usando o seguinte comando:

hadoop jar book.jar BookDriver /input /output

Este comando executará a classe BookDriver, usando os dados de entrada de /input e gerando os resultados para /output. Você visualiza o resultado com o seguinte comando.

hdfs dfs -cat /output/part-r-00000

Resumo

Parabéns! Você dominou com sucesso a serialização no Hadoop MapReduce, navegando pela criação de classes Writable personalizadas. Através de um cenário envolvendo o Bibliotecário-Chefe de uma Academia Mágica gerenciando uma vasta coleção de livros, você criou uma classe Book implementando a interface Writable para serialização e desserialização de dados sem problemas. Criando uma classe BookMapper para extrair informações do livro e uma classe BookReducer para agrupar eficientemente os livros por autor, você orquestrou o processo com uma classe BookDriver. Isso envolveu tarefas como compilar classes Java, criar um arquivo JAR e executar o job no cluster Hadoop. Ao longo do processo, você adquiriu experiência inestimável em Hadoop MapReduce, aprimorando habilidades em classes Writable personalizadas, classes Mapper e Reducer e orquestrando jobs MapReduce para tarefas de processamento de dados em larga escala.