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.
- A chave de entrada é um
LongWritableque representa o deslocamento de bytes da linha de entrada, e o valor de entrada é um objetoTextcontendo a linha de texto do arquivo de entrada. - O método
mapdivide a linha de entrada em palavras individuais usando o métodosplite a expressão regular"\\s+"para corresponder a um ou mais caracteres de espaço em branco. - Para cada palavra, o método
mapcria um objetoTexte o emite como a chave, juntamente com um valorLongWritableconstante de1como 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.
- A chave de entrada é um objeto
Textque representa a palavra, e os valores de entrada são umIterablede objetosLongWritableque representam as contagens dessa palavra emitida pelosMappers. - O método
reduceitera sobre os valores e calcula a soma de todas as contagens para a palavra fornecida. - O método
reduceentão emite a palavra como a chave e a contagem total como o valor, usandocontext.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.
- O método
maincria um novo objetoConfiguratione um objetoJobcom um nome personalizado "Artifact Word Count". - Os métodos
setMapperClassesetReducerClasssão usados para especificar as classesMappereReducera serem usadas no trabalho. - Os métodos
setOutputKeyClassesetOutputValueClasssão usados para especificar os tipos de chave e valor de saída para o trabalho. - 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. - 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. - 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.



