Jornada de Descoberta de Dados do Deserto

HadoopBeginner
Pratique Agora

Introdução

Na vasta extensão de um deserto, um mercador solitário embarca numa jornada perigosa, procurando desvendar os mistérios escondidos sob as areias escaldantes. O objetivo do mercador é descobrir relíquias e artefatos antigos, desvendando os segredos de uma civilização há muito esquecida. No entanto, o enorme volume de dados enterrados no deserto apresenta um desafio formidável, exigindo o poder do Hadoop MapReduce para processar e analisar as informações de forma eficaz.

Implementando o Mapper

Nesta etapa, criaremos uma classe Mapper para processar os dados brutos obtidos das escavações no deserto. Nosso objetivo é extrair informações relevantes dos dados e prepará-los para análise posterior pelo Reducer.

Use o comando su - hadoop para mudar para o usuário hadoop e ir automaticamente para o diretório /home/hadoop. Neste momento, use o comando ls . para ver o arquivo de dados data*.txt. Em seguida, crie e preencha o arquivo ArtifactMapper.java nesse diretório de acordo com o código abaixo:

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

public class ArtifactMapper extends Mapper<LongWritable, Text, Text, LongWritable> {

    private final static LongWritable ONE = new LongWritable(1);
    private Text word = new Text();

    @Override
    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // Split the line into words
        String[] tokens = value.toString().split("\\s+");

        // Emit each word with a count of 1
        for (String token : tokens) {
            word.set(token);
            context.write(word, ONE);
        }
    }
}

Na classe ArtifactMapper, estendemos a classe Mapper fornecida pelo Hadoop. O método map é substituído para processar cada par chave-valor de entrada.

  1. A chave de entrada é um LongWritable que representa o deslocamento de bytes da linha de entrada, e o valor de entrada é um objeto Text contendo a linha de texto do arquivo de entrada.
  2. O método map divide a linha de entrada em palavras individuais usando o método split e a expressão regular "\\s+" para corresponder a um ou mais caracteres de espaço em branco.
  3. Para cada palavra, o método map cria um objeto Text e o emite como a chave, juntamente com um valor LongWritable constante de 1 como o valor, representando a contagem dessa palavra.

Implementando o Reducer

Nesta etapa, criaremos uma classe Reducer para agregar os dados emitidos pelo Mapper. O Reducer contará as ocorrências de cada palavra e produzirá a saída final.

Crie e preencha o arquivo ArtifactReducer.java no diretório /home/hadoop de acordo com o seguinte código:

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

public class ArtifactReducer extends Reducer<Text, LongWritable, Text, LongWritable> {

    @Override
    public void reduce(Text key, Iterable<LongWritable> values, Context context)
            throws IOException, InterruptedException {
        long sum = 0;
        for (LongWritable value : values) {
            sum += value.get();
        }
        context.write(key, new LongWritable(sum));
    }
}

Na classe ArtifactReducer, estendemos a classe Reducer fornecida pelo Hadoop. O método reduce é substituído para agregar os valores associados a cada chave.

  1. A chave de entrada é um objeto Text que representa a palavra, e os valores de entrada são um Iterable de objetos LongWritable que representam as contagens dessa palavra emitida pelos Mappers.
  2. O método reduce itera sobre os valores e calcula a soma de todas as contagens para a palavra fornecida.
  3. O método reduce então emite a palavra como a chave e a contagem total como o valor, usando context.write.

Criando o Driver

Nesta etapa, criaremos uma classe Driver para orquestrar o trabalho MapReduce. O Driver configurará o trabalho, especificará os caminhos de entrada e saída e enviará o trabalho para o cluster Hadoop.

Crie e preencha o arquivo ArtifactDriver.java no diretório /home/hadoop de acordo com o seguinte código:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
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;

public class ArtifactDriver {

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "Artifact Word Count");

        // Specify the job's jar file by class
        job.setJarByClass(ArtifactDriver.class);

        // Set the Mapper and Reducer classes
        job.setMapperClass(ArtifactMapper.class);
        job.setReducerClass(ArtifactReducer.class);

        // Set the output key and value types
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        // Set the input and output paths
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        // Submit the job and wait for completion
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

Na classe ArtifactDriver, criamos um trabalho MapReduce e o configuramos para executar nossas classes ArtifactMapper e ArtifactReducer.

  1. O método main cria um novo objeto Configuration e um objeto Job com um nome personalizado "Artifact Word Count".
  2. Os métodos setMapperClass e setReducerClass são usados para especificar as classes Mapper e Reducer a serem usadas no trabalho.
  3. Os métodos setOutputKeyClass e setOutputValueClass são usados para especificar os tipos de chave e valor de saída para o trabalho.
  4. O método FileInputFormat.addInputPath é usado para especificar o caminho de entrada para o trabalho, que é tomado como o primeiro argumento da linha de comando.
  5. O método FileOutputFormat.setOutputPath é usado para especificar o caminho de saída para o trabalho, que é tomado como o segundo argumento da linha de comando.
  6. O método job.waitForCompletion é chamado para enviar o trabalho e aguardar sua conclusão. O programa sai com um código de status de 0 se o trabalho for bem-sucedido ou 1 se falhar.

Compilando e Executando o Job

Nesta etapa, compilaremos as classes Java e executaremos o trabalho MapReduce no cluster Hadoop.

Primeiro, precisamos compilar as classes Java:

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:. *.java

Este comando compila as classes Java e coloca os arquivos .class compilados no diretório atual. A opção -classpath inclui os caminhos da biblioteca Hadoop, que são necessários para compilar o código que usa classes Hadoop. Os parâmetros -source e -target são usados para especificar as versões do código-fonte e bytecode Java de destino para corresponder à versão do Java no Hadoop.

Em seguida, empacotando um arquivo class com o comando jar:

jar -cvf Artifact.jar *.class

Finalmente, podemos executar o trabalho MapReduce, e todos os dados sobre o deserto já estão armazenados no diretório /input do HDFS:

hadoop jar Artifact.jar ArtifactDriver /input /output

Após executar o comando, você deverá ver logs indicando o progresso do trabalho MapReduce. Uma vez que o trabalho estiver completo, você pode encontrar os arquivos de saída no diretório /output do HDFS. E use o seguinte comando para visualizar o resultado:

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

Resumo

Parabéns! Você explorou com sucesso o processo de codificação de Mappers e Reducers para um trabalho Hadoop MapReduce. Guiado por um cenário envolvendo um mercador do deserto em busca de relíquias antigas, você aproveitou o poder do Hadoop MapReduce para analisar vastos dados do deserto. A implementação da classe ArtifactMapper extraiu dados relevantes, enquanto a classe ArtifactReducer agregou a saída do Mapper. Orquestrar o processo com a classe ArtifactDriver solidificou ainda mais sua compreensão. Ao longo do processo, a ênfase foi colocada nas melhores práticas, exemplos de código completos e verificações de validação. Essa experiência prática aprofundou sua compreensão do Hadoop MapReduce e destacou o design eficaz da experiência de aprendizado.