WordCount
Exemplo de Programação Java - MapReduce
__________________________________________________
__________________________________________________
Problema: Contar a frequência das palavras constantes dos arquivos de entrada: sample1.txt e sample2.txt
Workflow
Mapper: divide cada registro (linha) em palavras
input: <offset, linha>
output: <palavra, 1>
Reducer: soma a contagem feita para cada palavra
input: <palavra, (1, 1, ...)>
output: <palavra, contagem>
input: <offset, linha>
output: <palavra, 1>
Reducer: soma a contagem feita para cada palavra
input: <palavra, (1, 1, ...)>
output: <palavra, contagem>
Compile o arquivo WordCount.java e crie o .jar (arquivo java interpretável - executável do java):
$ javac -d . -cp `hadoop classpath` WordCount.java
$ jar cf wc.jar WordCount*.class
Assumindo que o diretório /user/emilia/wordcount/input é o diretório de input no HDFS.
Copie os arquivos de entrada do programa para o diretório do hdfs:
Verifique se a cópia foi feita com sucesso:
$ hdfs dfs -ls /user/emilia/wordcount/input/
/user/emilia/wordcount/input/sample1.txt
/user/emilia/wordcount/input/sample2.txt
Execute o programa:$ hadoop jar wc.jar WordCount emilia
Verifique a saída do programa:$ hdfs dfs -cat /user/emilia/wordcount/output/part-r-00000
/user/emilia/wordcount/input/sample2.txt
Walk-through
A aplicação WordCount é direta e simples.
MAP
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);
}
}
throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
A implementação do Mapper, via método map, processa uma linha de cada vez.
Ele então divide a linha em tokens separados por whitespaces, utilizando o tipo StringTokenizer, e emite um par key-value < <palavra>, 1>.
Ele então divide a linha em tokens separados por whitespaces, utilizando o tipo StringTokenizer, e emite um par key-value < <palavra>, 1>.
O output do primeiro arquivo o map é:
< I, 1>
< love, 1>
< Big, 1>
< Data, 1>
< You, 1>
< love, 1>
< it, 1>
< too, 1>
< Best, 1>
< Regards, 1>
O output do segundo arquivo o map é:< I, 1>
< love, 1>
< Hello, 1>
< World, 1>
< You, 1>
< love, 1>
< it, 1>
< too, 1>
< Kind, 1>
< Regards, 1>
COMBINER
O programa WordCount especifica um Combiner na fase de Map: job.setCombinerClass(IntSumReducer.class)
Portanto, a saída de cada Map é passada pelo combiner local (que utiliza o mesmo que o Reducer na configuração do job) para agregação local, após ser ordenada pelas chaves.
Portanto, a saída de cada Map é passada pelo combiner local (que utiliza o mesmo que o Reducer na configuração do job) para agregação local, após ser ordenada pelas chaves.
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);
}
O output do Combiner para o primeiro arquivo é:< Best, 1>
< Big, 1>
< Data, 1>
< I, 1>
< it, 1>
< love, 2>
< Regards, 1>
< too, 1>
< You, 1>
REDUCE
A implementação do Reducer, via método reduce, soma os valores que são cada ocorrência de palavras (keys) contadas.
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);
}
}
O método main especifica várias características do job, tais como os caminhos de input/output, tipos do par key/value, formatos de input/output etc.
Ele chama a função job.waitForCompletion para submeter o job e monitorar o seu progresso.
Ele chama a função job.waitForCompletion para submeter o job e monitorar o seu progresso.