MapReduce - Combiners
Um combinador, também conhecido como semi-reducer, é uma classe opcional que opera aceitando as entradas da classe Map e depois passando os pares de valores-chave de saída para a classe Reducer.
A principal função de um Combiner é resumir os registros de saída do mapa com a mesma tecla. A saída (coleção de valores-chave) do combinador será enviada pela rede para a tarefa do Redutor real como entrada.
Combiner
A classe Combiner é usada entre a classe Map e a classe Reduce para reduzir o volume de transferência de dados entre Map e Reduce. Normalmente, a saída da tarefa de mapa é grande e os dados transferidos para a tarefa de redução são altos.
O seguinte diagrama de tarefas MapReduce mostra a FASE DO COMBINADOR.
Como funciona o combinador?
Aqui está um breve resumo de como o MapReduce Combiner funciona -
Um combinador não possui uma interface predefinida e deve implementar o método reduz () da interface do Redutor.
Um combinador opera em cada chave de saída do mapa. Ela deve ter os mesmos tipos de valores-chave de saída da classe Reducer.
Um combinador pode produzir informações resumidas de um grande conjunto de dados porque substitui a saída do mapa original.
Embora o Combiner seja opcional, ele ajuda a segregar os dados em vários grupos para a fase de Redução, o que facilita o processamento.
Implementação do Combinador MapReduce
O exemplo a seguir fornece uma ideia teórica sobre combinadores. Vamos supor que temos o seguinte arquivo de texto de entrada denominadoinput.txt para MapReduce.
What do you mean by Object
What do you know about Java
What is Java Virtual Machine
How Java enabled High Performance
As fases importantes do programa MapReduce com Combiner são discutidas abaixo.
Leitor de registro
Esta é a primeira fase do MapReduce em que o leitor de registros lê todas as linhas do arquivo de texto de entrada como texto e produz a saída como pares de valores-chave.
Input - Texto linha por linha do arquivo de entrada.
Output- Forma os pares de valores-chave. A seguir está o conjunto de pares de valores-chave esperados.
<1, What do you mean by Object>
<2, What do you know about Java>
<3, What is Java Virtual Machine>
<4, How Java enabled High Performance>
Fase do Mapa
A fase de mapa obtém a entrada do leitor de registro, processa-a e produz a saída como outro conjunto de pares de valores-chave.
Input - O par de valores-chave a seguir é a entrada obtida do leitor de registros.
<1, What do you mean by Object>
<2, What do you know about Java>
<3, What is Java Virtual Machine>
<4, How Java enabled High Performance>
A fase de Mapa lê cada par de valor-chave, divide cada palavra do valor usando StringTokenizer, trata cada palavra como chave e a contagem dessa palavra como valor. O fragmento de código a seguir mostra a classe Mapper e a função do mapa.
public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens())
{
word.set(itr.nextToken());
context.write(word, one);
}
}
}
Output - A saída esperada é a seguinte -
<What,1> <do,1> <you,1> <mean,1> <by,1> <Object,1>
<What,1> <do,1> <you,1> <know,1> <about,1> <Java,1>
<What,1> <is,1> <Java,1> <Virtual,1> <Machine,1>
<How,1> <Java,1> <enabled,1> <High,1> <Performance,1>
Fase Combinador
A fase Combiner pega cada par de valores-chave da fase de Mapa, processa e produz a saída como key-value collection pares.
Input - O seguinte par de valores-chave é a entrada obtida da fase de Mapa.
<What,1> <do,1> <you,1> <mean,1> <by,1> <Object,1>
<What,1> <do,1> <you,1> <know,1> <about,1> <Java,1>
<What,1> <is,1> <Java,1> <Virtual,1> <Machine,1>
<How,1> <Java,1> <enabled,1> <High,1> <Performance,1>
A fase Combiner lê cada par de valor-chave, combina as palavras comuns como chave e os valores como coleção. Normalmente, o código e a operação de um Combiner são semelhantes aos de um Redutor. A seguir está o trecho de código para a declaração das classes Mapper, Combiner e Reducer.
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
Output - A saída esperada é a seguinte -
<What,1,1,1> <do,1,1> <you,1,1> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,1,1,1>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>
Fase Redutora
A fase Redutor pega cada par de coleção de valor-chave da fase Combiner, processa-o e passa a saída como pares de valor-chave. Observe que a funcionalidade do Combiner é igual à do Redutor.
Input - O seguinte par de valores-chave é a entrada retirada da fase Combiner.
<What,1,1,1> <do,1,1> <you,1,1> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,1,1,1>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>
A fase Redutor lê cada par de valor-chave. A seguir está o trecho de código para o Combiner.
public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable>
{
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException
{
int sum = 0;
for (IntWritable val : values)
{
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
Output - A saída esperada da fase do Redutor é a seguinte -
<What,3> <do,2> <you,2> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,3>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>
Gravador
Esta é a última fase do MapReduce, onde o gravador grava cada par de valores-chave da fase Redutor e envia a saída como texto.
Input - Cada par de valores-chave da fase Redutor junto com o formato de saída.
Output- Fornece os pares de valores-chave em formato de texto. A seguir está a saída esperada.
What 3
do 2
you 2
mean 1
by 1
Object 1
know 1
about 1
Java 3
is 1
Virtual 1
Machine 1
How 1
enabled 1
High 1
Performance 1
Programa Exemplo
O seguinte bloco de código conta o número de palavras em um programa.
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCount {
public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens())
{
word.set(itr.nextToken());
context.write(word, one);
}
}
}
public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable>
{
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException
{
int sum = 0;
for (IntWritable val : values)
{
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception
{
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
Salve o programa acima como WordCount.java. A compilação e execução do programa são fornecidas abaixo.
Compilação e execução
Suponhamos que estejamos no diretório inicial do usuário Hadoop (por exemplo, / home / hadoop).
Siga as etapas fornecidas a seguir para compilar e executar o programa acima.
Step 1 - Use o seguinte comando para criar um diretório para armazenar as classes java compiladas.
$ mkdir units
Step 2- Baixe Hadoop-core-1.2.1.jar, que é usado para compilar e executar o programa MapReduce. Você pode baixar o jar em mvnrepository.com .
Vamos supor que a pasta baixada seja / home / hadoop /.
Step 3 - Use os seguintes comandos para compilar o WordCount.java programa e para criar um jar para o programa.
$ javac -classpath hadoop-core-1.2.1.jar -d units WordCount.java
$ jar -cvf units.jar -C units/ .
Step 4 - Use o seguinte comando para criar um diretório de entrada no HDFS.
$HADOOP_HOME/bin/hadoop fs -mkdir input_dir
Step 5 - Use o seguinte comando para copiar o arquivo de entrada chamado input.txt no diretório de entrada do HDFS.
$HADOOP_HOME/bin/hadoop fs -put /home/hadoop/input.txt input_dir
Step 6 - Use o seguinte comando para verificar os arquivos no diretório de entrada.
$HADOOP_HOME/bin/hadoop fs -ls input_dir/
Step 7 - Use o seguinte comando para executar o aplicativo de contagem de palavras, obtendo arquivos de entrada do diretório de entrada.
$HADOOP_HOME/bin/hadoop jar units.jar hadoop.ProcessUnits input_dir output_dir
Espere um pouco até que o arquivo seja executado. Após a execução, a saída contém várias divisões de entrada, tarefas de mapa e tarefas de redutor.
Step 8 - Use o seguinte comando para verificar os arquivos resultantes na pasta de saída.
$HADOOP_HOME/bin/hadoop fs -ls output_dir/
Step 9 - Use o seguinte comando para ver a saída em Part-00000Arquivo. Este arquivo é gerado pelo HDFS.
$HADOOP_HOME/bin/hadoop fs -cat output_dir/part-00000
A seguir está a saída gerada pelo programa MapReduce.
What 3
do 2
you 2
mean 1
by 1
Object 1
know 1
about 1
Java 3
is 1
Virtual 1
Machine 1
How 1
enabled 1
High 1
Performance 1