Criando nosso WordCount para Hadoop

Introdução

Setup do Projeto no Maven

Precisamos criar um novo projeto no maven, o qual usaremos para configurar e codificar o nosso Job no Hadoop.

Podemos criar o projeto do maven via IDE (Eclipse, IntelliJ, NetBeans e etc..)

Dentro do Eclipse clique com o direto no lado esquerdo do seu projeto e escolha New -> Project…

Na popup que aparecerá escolha Maven Project

Na próxima tela você ira escolher a localização do projeto e irá clicar em Next.

Na tela seguinte você irá escolher o Group Id, Artifact Id, Version e Package.

Ou via linha de comando como o exemplo abaixo:

Em ambos os métodos, temos de remover as classes desnecessárias (App.java e AppTest) e fazer as configurações das dependências no arquivo pom.xml conforme abaixo:

Classe Driver

Vamos criar a classe Driver, ela será responsável por executar o nosso programa Hadoop, tratando os parâmetros de entrada, definindo qual será as classes de Map e de Reducer, e o tratamento de saída.

Abaixo demonstro um exemplo de implementação completa. Dentro dela mantive os comentários de código que nos ajudarão a compreende-la.

Como mostrado nos comentários esperamos dois parâmetros, que serão passados através da linha de comando, da seguinte forma:

Acima nós informamos qual o tipo de entrada que esperamos, que foi definido como sendo a classe FileInputFormat. Veja abaixo exemplos de objetos InputFormat

TextInputFormat – Default, lê cada linha terminada com “\n” como sendo um valor.

FileInputFormat – Classe abstrata usada para InputFormats baseados em arquivos.

KeyValueTextInputFormat – Determina linhas por meio de um separador (tabpor padrão)

Veja que em nosso código, definimos o uso do TextInputFormat, então cada arquivo do nosso diretório de entrada, será tratado linha a linha para a nossa classe mapper.

Classe Mapper

Vamos implementar a classe Mapper do pacote org.apache.hadoop.mapreduce. Esse classe utiliza o conceito de Generics para determinar qual são os parametros de entrada e saida da seguinte forma:

Como podemos ver, q classe mapper precisa de quatros classes como parametrização, sendo a chave e valor de entrada e a chave e valor de saida.

A chave e o valor de entrada, são os valores recebidos através do processamento do arquivo. Como definimos o uso o TextInputFormat em nossa classe driver, cada value será do tipo texto e conterá uma linha de texto dos arquivos encontrados no diretório de entrada.

A chave e o valor de saída, são os valores que serão agrupados e repassados ao Reducer pra serem processados.

O método map que deverá ser implementado, sendo que ele receberá os mesmo tipos parametrizados na definição da classe.

E o resultado será enviado ao Job, através do comando que deveremos incluir dentro da nossa classe Mapper.

O par1 deverá ser do tipo que definirmos na parametrização da classe como KEYOUT, e o par2 será do tipo definido como VALUEOUT.

Veja agora abaixo, a implementação completa de nossa classe mapper.

Nesse algoritmo simples, pegamos o value, que representa uma linha de cada arquivo, conforme foi definido pelo uso da classe TextInputFormat em nossa classe Driver, e utilizamos uma classe chamada StringTokenizer para determinar como essa linha será quebrada. no caso passamos um parâmetro espaço (” “) que fará com que a linha seja quebrada em um array (lista) de palavras.

Percorremos essa lista com o while e atribuímos um valor fixo para cada palavra, encontrada através do contexto.write(word, ONE)

Classe Reducer

Assim como a classe Mapper, a classe Reducer possui quatro parametrizações:

As classes de chave e valor da entrada, devem ser do mesmo tipo definido na saída de nossa classe Mapper, já que o resultado do Mapper é que servirá de entrada para a nossa classe Redurcer.

Já os valores de chave e valor de saída, são como os nossos dados serão escritos no arquivo final dentro do diretório de saída.

Precisamos dentro da classe Reducer, implementar o método:

Onde cada chave do tipo KEYIN, terá uma lista de VALUEIN.

Vejamos a implementação completa da classe Reducer.

Observe que a implementação é feita de forma bem simples. Pegamos todos os valores recebidos na chave, e acumulamos o total de valores recebidos dentro da lista de valores. Se lembrarmos da construção de nossa classe Mapper, veremos que cada valor conterá o número 1

Construindo

Feita todas a implementação necessária, vamos agora fazer a construção do nosso pacote, usando o comando abaixo.

O resultado, ao termino do processamento será algo similar a isso:

Isso irá gerar um pacote .jar, dentro do seu workspace, similar ao caminho abaixo:

No exemplo que acabei de fazer o meu está em:

É importante sabermos onde se encontra o nosso pacote, já que precisaremos saber o caminho do mesmo para executarmos nosso Job no Hadoop.

Preparando os nossos dados

Para esse exemplo vamos usar uma massa de dados com bastante palavras. Pode ser qualquer texto que tiver. Aqui nesse tutorial vou usar um Livro de Shakespeare, que na data de hoje 09/09/2017 pode ser encontrado no seguinte link.

Livro do Shakespeare para Uso

Após baixar o arquivo vamos subir ele no HDFS. Primeiro vamos criar a pasta de entrada do dados:

Agora vamos subir o arquivo para o diretório recém criado:

Executando

Podemos agora entrar no diretório onde está o nosso pacote, no meu caso seria:

Veremos o processamento ser realizado, com uma saída similar a essa:

Após o processamento, poderemos lista os arquivos gerados na pasta de saída:

Veja que o Hadoop criou 03 arquivos, em caso de sucesso, sendo dois arquivos vazios, e um arquivos contendo o resultado da operação part-r-00000.

Para vermos o resultado da contagem, basta agora darmos um cat no arquivo part-r-00000:

Veremos então uma lista de palavras, com o número de ocorrências a frente de cada uma.

3 Comments

  1. Boa noite,

    tentei realizar da mesma forma, porem estou encontrando um erro. Poderia me ajudar por favor.

    Postei da duvida na comunidade também.
    Link abaixo:
    https://www.guj.com.br/t/exception-in-thread-main-java-lang-arrayindexoutofboundsexception-0/394901

  2. Marcel,

    Ate tentei modificar os argumentos de entrada e saida, mas retorna o erro abaixo:

    19/11/03 14:48:57 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform… using builtin-java classes where applicable
    Exception in thread “main” java.lang.VerifyError: Bad type on operand stack
    Exception Details:
    Location:
    org/apache/hadoop/mapred/JobTrackerInstrumentation.create(Lorg/apache/hadoop/mapred/JobTracker;Lorg/apache/hadoop/mapred/JobConf;)Lorg/apache/hadoop/mapred/JobTrackerInstrumentation; @5: invokestatic
    Reason:
    Type ‘org/apache/hadoop/metrics2/lib/DefaultMetricsSystem’ (current frame, stack[2]) is not assignable to ‘org/apache/hadoop/metrics2/MetricsSystem’
    Current Frame:
    bci: @5
    flags: { }
    locals: { ‘org/apache/hadoop/mapred/JobTracker’, ‘org/apache/hadoop/mapred/JobConf’ }
    stack: { ‘org/apache/hadoop/mapred/JobTracker’, ‘org/apache/hadoop/mapred/JobConf’, ‘org/apache/hadoop/metrics2/lib/DefaultMetricsSystem’ }
    Bytecode:
    0000000: 2a2b b200 03b8 0004 b0

    at org.apache.hadoop.mapred.LocalJobRunner.(LocalJobRunner.java:573)
    at org.apache.hadoop.mapred.JobClient.init(JobClient.java:494)
    at org.apache.hadoop.mapred.JobClient.(JobClient.java:479)
    at org.apache.hadoop.mapreduce.Job$1.run(Job.java:563)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:415)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
    at org.apache.hadoop.mapreduce.Job.connect(Job.java:561)
    at org.apache.hadoop.mapreduce.Job.submit(Job.java:549)
    at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:580)
    at br.com.jonathan.hadoop.ContaPalavras.ContaPalavrasDriver.main(ContaPalavrasDriver.java:58)

    • Jonathan, boa tarde.

      Conseguiu resolver seu problema? Estive ausente um tempo.

      Esse erro aparenta ser diferença de versões entre as libs do Hadoop carregadas.

      QQ dúvida me avisa.

Leave a Reply

Pin It on Pinterest