Processamento de Dados Distribuídos com Hadoop, Parte 3: Desenvolvimento de aplicativo

Desenvolvendo um aplicativo Ruby MapReduce para Hadoop

Com a configuração, instalação e uso do Hadoop em arquiteturas de um ou vários nós, é possível agora voltar-se à tarefa de desenvolver aplicativos dentro da infraestrutura do Hadoop. Este artigo final de uma série explora as APIs e o fluxo de dados do Hadoop e demonstra seu uso com um aplicativo simples de mapeador e redutor.

M. Tim Jones, Consultant Engineer, Emulex Corp.

M. Tim JonesM. Tim Jones é arquiteto de firmware integrado e autor das obras Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (agora, na segunda edição), AI Application Programming (na segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Sua experiência em engenharia vai desde o desenvolvimento de kernels para espaçonaves geossíncronas até a arquitetura de sistemas integrados e o desenvolvimento de protocolos de rede. Tim é engenheiro consultor da Emulex Corp. em Longmont, Colorado.



28/Set/2010

Entre em contato com Tim

Tim é um de nossos autores mais conhecidos e produtivos. Procure todos os artigos de Tim no developerWorks. Confira o perfil de Tim e entre em contato com ele, com outros autores e com leitores no My developerWorks.

Os primeiros dois artigos desta série tiveram como foco a instalação e a configuração do Hadoop para clusters de um ou vários nós. Este artigo final explora a programação no Hadoop—em particular, o desenvolvimento de um aplicativo de mapa e redução dentro da linguagem Ruby. Eu escolhi Ruby porque, primeiro, é uma excelente linguagem de script orientada a objetos que você deveria conhecer e, segundo, você encontrará inúmeras referências na seção Recursos para tutoriais que tratam das linguagens Java™ e Python. Por meio desta exploração de programação do MapReduce, também introduzirei a application programming interface (API) de streaming. Esta API fornece os meios para desenvolver aplicativos em idiomas que não a linguagem Java.

Começaremos com uma breve introdução a mapa e redução (da perspectiva funcional) e, a seguir, nos aprofundaremos mais no modelo de programação e arquitetura do Hadoop e elementos que formulam, distribuem e gerenciam o trabalho.

A origem de mapa e redução

Então, quais são os elementos funcionais que inspiraram o paradigma de programação MapReduce? Em 1958, John McCarthy inventou uma linguagem chamada Lisp, que implementou computação numérica e simbólica, mas de uma forma recursiva que é estranha à maioria das linguagens em uso hoje. (Na verdade, há uma história fascinante sobre o Lisp na Wikipedia que inclui um tutorial útil —vale a pena o tempo gasto para lê-lo.) O Lisp foi primeiro utilizado no IBM® 704, o primeiro computador produzido em massa, que também foi suportado por outra favorita: FORTRAN.

A função map, originária das linguagens funcionais como o Lisp, mas agora comum em muitas outras linguagens, é uma aplicação de uma função sobre uma lista de elementos. O que isso significa? A Listagem 1 fornece uma sessão interpretada com Scheme Shell (SCSH), que é uma derivação do Lisp. A primeira linha define uma função chamada square, que recebe um argumento e emite sua raiz quadrada. A linha seguinte ilustra o uso da função map. Como mostrado, com map, é fornecida a função e uma lista de elementos na qual a função é aplicada. O resultado é uma nova lista contendo a raiz quadrada dos elementos.

Listagem 1. Demonstração da função map no SCSH
> (define square (lambda (x) (* x x)))
> (map square '(1 3 5 7))
'(1 9 25 49)
>

A redução também é aplicada em uma lista, mas tipicamente reduz a lista a um valor escalar. O exemplo fornecido na Listagem 2 ilustra outra função SCSH para redução de uma lista a um escalar—neste caso, somando a lista de valores na forma (1 + (2 + (3 + (4 + (5))))). Note que isto é programação funcional clássica, basear-se em recursividade em vez de iteração.

Listagem 2. Demonstração da redução no SCSH
> (define (list-sum lis) (if (null? lis) 0 (+ (car lis) (list-sum (cdr lis)))))
> (list-sum '(1 2 3 4 5))
15
>

É interessante notar que a recursividade é tão eficiente quanto a interação em linguagens imperativas, pois a recursividade é traduzida em iteração por trás dos bastidores.


Modelo de programação do Hadoop

O Google introduziu a ideia de MapReduce como um modelo de programação para processar ou gerar grandes conjuntos de dados. No modelo canônico, uma função map processa pares de valores-chave, resultando em um conjunto intermediário de pares de valores-chave. Uma função reduce, a seguir, processa estes pares de valores-chave, mesclando os valores para as chaves associadas (consulte a figura 1). Os dados de entrada são particionados de tal forma que possam ser distribuídos entre um grupo de máquinas para processamento em paralelo. Da mesma forma, os dados intermediários gerados são processados em paralelo, tornando a abordagem ideal para o processamento de grandes quantidades de dados.

Figura 1. Visualização simplificada do processamento de MapReduce
Simplified view of MapReduce processing

Para relembrar rapidamente, veja a arquitetura na Figura 1 da perspectiva de mapa e redução para contagem de palavras (pois você desenvolverá um aplicativo de mapa e redução neste artigo). Quando os dados de entrada são fornecidos (dentro do sistema de arquivos do Hadoop [HDFS]), eles são primeiramente particionados e, a seguir, distribuídos para trabalhadores de mapa (por meio do rastreador de tarefas). Apesar de o exemplo na Figura 2 mostrar uma pequena frase sendo particionada, tipicamente a quantidade de trabalho para particionar está no intervalo de tamanho de 128MB por um motivo: É preciso um pequeno intervalo de tempo para configurar o trabalho, então ter mais trabalho a fazer minimiza esta sobrecarga. Os trabalhadores de mapa (no exemplo canônico) dividem o trabalho em vetores individuais que contêm a palavra em forma de tokens e um valor inicial (1, neste caso). Quando as tarefas de mapa estiverem concluídas (como definido no Hadoop pelo rastreador de tarefas), o trabalho é fornecido ao trabalhador de redução. O trabalhador de redução reduz as chaves a um conjunto único, com o valor representando o número de chaves encontradas.

Figura 2. Exemplo simples de MapReduce
Simple MapReduce example

Note que este processo pode ocorrer na mesma máquina ou em máquinas diferentes, ou ser feito sequencialmente ou em paralelo usando diferentes partições de dados, e ainda assim o resultado será o mesmo.

Apesar de a visão canônica (para geração de índice de busca usando contagem de palavras) for uma maneira de visualizar o Hadoop, ocorre que este modelo de computação pode ser aplicado genericamente a uma série de problemas computacionais, como você verá.


A flexibilidade do Hadoop

A partir do exemplo simples mostrado na Figura 2, note que os dois elementos principais são os processos map e reduce. Apesar de existir uma visão tradicional sobre como estes processos funcionam, não é um requisito da arquitetura de map e reduce para se comportar desta forma. Este é o verdadeiro poder do Hadoop—sua flexibilidade de implementar os processos map e reduce que se comportem de uma forma que solucione um aplicativo particular. O exemplo de contagem de palavras é útil e aplicável a um grande número de problemas, mas os outros modelos ainda se encaixam nesta estrutura geral. Tudo que é necessário é o desenvolvimento de um aplicativo de mapa e redução, tornando os processos visíveis para o Hadoop.

Entre outras aplicações, o Hadoop tem sido usado até mesmo para aplicações de aprendizado de máquina, implementando algoritmos tão diversos quanto redes neurais, máquinas de vetor de suporte e k-means clustering (consulte a seção Recursos para obter mais informações).


Streaming de dados

Apesar de o Hadoop ser uma estrutura com base em Java, é possível escrever aplicativos de mapa e redução em linguagens que não o Java. O streaming torna isso possível O utilitário streaming dentro do Hadoop implementa um tipo de cola de fluxo de dados. Com o utilitário streaming, é possível definir seus próprios executáveis de mapa e redução (com cada um recebendo a entrada padrão [stdin] e fornecendo saída pela saída padrão [stdout]), e o utilitário streaming lê e grava dados de forma apropriada, invocando seus aplicativos conforme necessário (consulte a Listagem 3).

Listagem 3. Usando o utilitário streaming do Hadoop
hadoop jar $HADOOP_HOME/hadoop-streaming.jar \
	-input inputData
	-output outputData
	-mapper map_exec
	-reducer reduce_exec

A Listagem 3 ilustra como usar o utilitário streaming dentro do Hadoop, enquanto que a Figura 3 mostra graficamente como o fluxo é definido. Note que este é um exemplo simples de uso de streaming. Várias opções estão disponíveis para definir como os dados são analisados, para definir como imagens são invocadas, para especificar imagens de substituição do particionador ou combinador e outros ajustes de configuração (consulte a seção Recursos para obter mais informações).

Figura 3. Exemplo gráfico de streaming
Graphical streaming example

Exemplo de Ruby

Com um entendimento básico do utilitário streaming, você está pronto para escrever um aplicativo de mapa e redução simples em Ruby e ver como usar os processos dentro da estrutura do Hadoop. O exemplo aqui usa o aplicativo canônico MapReduce, mas você verá outros aplicativos posteriormente (juntamente com a maneira como os implementará na forma mapa e redução).

Comece com o mapper. Este script obtém entrada textual de stdin, transforma-a em tokens e, a seguir, emite um conjunto de pares de valores-chave para stdout. Como a maioria das linguagens de script orientadas a objetos, esta tarefa é quase simples demais. O script mapper é mostrado na Listagem 4 (com alguns comentários e espaços em branco para dar a ele um pouco mais de tamanho). Este programa usa um iterador para ler uma linha de stdin e outro iterador para dividir a linha em tokens individuais. Cada token (palavra) é então enviado para stdout com um valor associado de 1 (separado por uma tabulação).

Listagem 4. Script map em Ruby (map.rb)
#!/usr/bin/env ruby

# Our input comes from STDIN
STDIN.each_line do |line|

  # Iterate over the line, splitting the words from the line and emitting
  # as the word with a count of 1.
  line.split.each do |word|
    puts "#{word}\t1"
  end

end

A seguir, veja o aplicativo de redução. Esta é um pouco mais complicada, mas usa hash do Ruby (array associativa) para simplificar a operação de redução (consulte a Listagem 5). Este script novamente trabalha nos dados de entrada a partir do stdin (passados pelo utilitário streaming) e divide a linha em palavra e valor. O hash é então verificado em relação à palavra; se encontrada, a contagem é adicionada ao elemento. Caso contrário, é criada uma nova entrada no hash da palavra e, a seguir, carrega a contagem (que deverá ser 1 para o processo mapper). Quando todas as entradas forem processadas, basta fazer a iteração no hash e emitir os pares de valores-chave para stdout.

Listagem 5. Script reduce em Ruby (reduce.rb)
#!/usr/bin/env ruby

# Create an empty word hash
wordhash = {}

# Our input comes from STDIN, operating on each line
STDIN.each_line do |line|

  # Each line will represent a word and count
  word, count = line.strip.split

  # If we have the word in the hash, add the count to it, otherwise
  # create a new one.
  if wordhash.has_key?(word)
    wordhash[word] += count.to_i
  else
    wordhash[word] = count.to_i
  end

end

# Iterate through and emit the word counters
wordhash.each {|record, count| puts "#{record}\t#{count}"}

Com os scripts map e reduce feitos, teste-os a partir da linha de comandos. Lembre-se de mudar estes arquivos para executáveis usando chmod +x. Comece gerando um arquivo de entrada, como mostra a Listagem 6.

Listagem 6. Gerando um arquivo de entrada
# echo "Hadoop is an implementation of the map reduce framework for " \
	"distributed processing of large data sets." > input
#

Com esta entrada, é possível agora testar o script mapper, como mostra a Listagem 7. Lembre-se de que este script simplesmente transforma a entrada em tokens para pares de valores-chave, onde cada valor será 1 (entrada não única).

Listagem 7. Testando o script mapper
# cat input | ruby map.rb
Hadoop	1
is	1
an	1
implementation	1
of	1
the	1
map	1
reduce	1
framework	1
for	1
distributed	1
processing	1
of	1
large	1
data	1
sets.	1
#

Até agora, tudo bem. Agora, agrupe o aplicativo inteiro no formato de streaming original (pipes do Linux®). Na Listagem 8, sua entrada é passada pelo script map, a saída é classificada (etapa opcional) e, a seguir, os dados resultantes intermediários são passados pelo script reducer.

Listagem 8. MapReduce simples usando pipes do Linux
# cat input | ruby map.rb | sort | ruby reduce.rb
large	1
of	2
framework	1
distributed	1
data	1
an	1
the	1
reduce	1
map	1
sets.	1
Hadoop	1
implementation	1
for	1
processing	1
is	1
#

Ruby com Hadoop

Com seus scripts map e reduce funcionando conforme esperado no ambiente shell, coloque-os em teste com o Hadoop. Vou ignorar as tarefas de configuração do Hadoop (consulte a Parte 1 ou Parte 2 desta série para configurar e executar o Hadoop).

A primeira etapa é criar um diretório de entrada no HDFS para seus dados de entrada e, a seguir, fornecer um arquivo de amostra no qual seus scripts serão testados. A Listagem 9 ilustra esta etapa (consulte a Parte 1 ou Parte 2 para obter mais informações sobre estas etapas).

Listagem 9. Criando dados de entrada para o processo MapReduce
# hadoop fs -mkdir input
# hadoop dfs -put /usr/src/linux-source-2.6.27/Documentation/memory-barriers.txt input
# hadoop fs -ls input
Found 1 items
-rw-r--r--  1 root supergroup  78031 2010-06-04 17:36 /user/root/input/memory-barriers.txt
#

A seguir, usando o utilitário streaming, invoque o Hadoop com os scripts personalizados, especificando os dados de entrada e o local da saída (consulte a Listagem 10). Note neste exemplo que as opções -file simplesmente dizem ao Hadoop para empacotar seus scripts Ruby como parte do envio da tarefa.

Listagem 10. Usando o streaming do Hadoop com scripts personalizados de MapReduce no Ruby
# hadoop jar /usr/lib/hadoop-0.20/contrib/streaming/hadoop-0.20.2+228-streaming.jar \
  -file /home/mtj/ruby/map.rb -mapper /home/mtj/ruby/map.rb \
  -file /home/mtj/ruby/reduce.rb -reducer /home/mtj/ruby/reduce.rb \
  -input input/* -output output
packageJobJar: [/home/mtj/ruby/map.rb, /home/mtj/ruby/reduce.rb, /var/lib/hadoop-0.20/...
10/06/04 17:42:38 INFO mapred.FileInputFormat: Total input paths to process : 1
10/06/04 17:42:39 INFO streaming.StreamJob: getLocalDirs(): [/var/lib/hadoop-0.20/...
10/06/04 17:42:39 INFO streaming.StreamJob: Running job: job_201006041053_0001
10/06/04 17:42:39 INFO streaming.StreamJob: To kill this job, run:
10/06/04 17:42:39 INFO streaming.StreamJob: /usr/lib/hadoop-0.20/bin/hadoop job ...
10/06/04 17:42:39 INFO streaming.StreamJob: Tracking URL: http://localhost:50030/...
10/06/04 17:42:40 INFO streaming.StreamJob:  map 0%  reduce 0%
10/06/04 17:43:17 INFO streaming.StreamJob:  map 100%  reduce 0%
10/06/04 17:43:26 INFO streaming.StreamJob:  map 100%  reduce 100%
10/06/04 17:43:29 INFO streaming.StreamJob: Job complete: job_201006041053_0001
10/06/04 17:43:29 INFO streaming.StreamJob: Output: output
#

Finalmente, explore a saída usando a operação cat do sistema de arquivos por meio do utilitário hadoop (consulte a Listagem 11).

Listagem 11. Explorando a saída do Hadoop
# hadoop fs -ls /user/root/output
Found 2 items
drwxr-xr-x  - root supergroup      0 2010-06-04 17:42 /user/root/output/_logs
-rw-r--r--  1 root supergroup  23014 2010-06-04 17:43 /user/root/output/part-00000
# hadoop fs -cat /user/root/output/part-00000 | head -12
+--->|	4
immediate	2
Alpha)	1
enable	1
_mandatory_	1
Systems	1
DMA.	2
AMD64	1
{*C,*D},	2
certainly	2
back	2
this	23
#

Portanto, com menos de 30 linhas de script, você implementou os elementos map e reduce e demonstrou sua execução dentro da estrutura do Hadoop. Um exemplo simples, mas um que ilustra o verdadeiro poder por trás do Hadoop e o porque ele está se tornando uma estrutura tão popular para processar grandes conjuntos de dados com algoritmos personalizados ou proprietários.


Outros aplicativos para o Hadoop

O Hadoop pode ser usado em muitos aplicativos além de simplesmente computar contagens de palavras em grandes conjuntos de dados. Tudo o que é necessário é uma representação dos dados em um formato de vetor que a infraestrutura do Hadoop possa usar. Apesar de os exemplos canônicos usarem a representação vetorial como uma chave e valor, não há restrição sobre como é possível definir o valor (como um agregado de uma série de valores). Esta flexibilidade pode abrir novas oportunidades para o Hadoop em um conjunto mais rico de aplicativos.

Um aplicativo interessante que se encaixa bem no modelo de contagem de palavras MapReduce é tabular a frequência do acesso ao servidor Web (discutido no documento semanal do Google). Para este aplicativo, as URLs servem como as chaves (conforme alimentadas a partir dos registros de acesso do servidor Web). O resultado do processo reduce é o número total de acessos por URL para um dado site da Web com base nos registros do servidor Web.

Em aplicativos de aprendizado de máquina, o Hadoop tem sido usado como uma forma de escalar algoritmos genéticos para processar grandes populações de indivíduos GA (soluções potenciais). O processo map realiza o algoritmo genético tradicional, buscando a melhor solução individual do conjunto local. O aplicativo reduce, então, torna-se um torneio de soluções individuais a partir da fase de mapa. Isto permite que nós individuais identifiquem sua melhor solução e, a seguir, permite que essas soluções concorram na fase de redução em uma exibição distribuída de sobrevivência do mais forte.

Outro aplicativo interessante foi criado para identificar botnets para spam de e-mail. A primeira etapa neste processo foi classificar mensagens de e-mail com a finalidade de reduzi-las (com base em um conjunto de impressões digitais) à medida que chegavam de uma determinada organização. A partir destes dados filtrados, foi criado um gráfico de e-mails que estavam conectados de alguma forma (por exemplo, referindo-se ao mesmo link no corpo da mensagem do e-mail). Estes e-mails relacionados foram então reduzidos a hosts (endereço IP estático ou dinâmico) para identificar o botnet em questão.

Fora dos aplicativos que veem o mundo por meio de primitivos de map e reduce, o Hadoop é útil como meio de distribuir trabalho em um conjunto de máquinas. Map e reduce não forçam necessariamente um tipo particular de aplicativo. Em vez disso, o Hadoop pode ser visto como uma forma de distribuir dados e algoritmos para hosts para processamento paralelo mais rápido.


Ecossistema de aplicativo Hadoop

Apesar de o Hadoop fornecer uma estrutura flexível, estão disponíveis outros aplicativos que podem transformar sua interface para outros aplicativos. Um exemplo interessante é chamado Hive, que é uma infraestrutura de armazém de dados com sua própria linguagem de consulta (chamada Hive QL). O Hive torna o Hadoop mais familiar para aqueles com um histórico de Structured Query Language (SQL), mas também suporta a infraestrutura MapReduce tradicional para processamento de dados.

HBase é outro aplicativo interessante que reside sobre o HDFS. É um sistema de banco de dados de alto desempenho similar ao Google BigTable. Em vez do processamento de arquivos tradicional, o HBase torna tabelas de banco de dados o formulário de entrada e de saída para processamento do MapReduce.

Finalmente, Pig é uma plataforma no Hadoop para analisar grandes conjuntos de dados. O Pig fornece uma linguagem de alto nível que compila em aplicativos map e reduce.


Indo além

Este artigo final na série Hadoop explorou o desenvolvimento de um aplicativo map e reduce no Ruby para a estrutura Hadoop. Esperamos que, com este artigo, seja possível ver o verdadeiro poder do Hadoop. Apesar de o Hadoop restringi-lo a um modelo de programação particular, aquele modelo é flexível e pode ser aplicado a um grande número de aplicativos.

Recursos

Aprender

  • MapReduce: Processamento de dados simplificado em grandes clusters é o documento sobre MapReduce, escrito em 2004 por Jeff Dean e Sanjay Ghemawat. Este documento é uma leitura agradável.
  • Este artigo explorou o utilitário streaming do Hadoop, que permite o desenvolvimento de scripts de map e reduce em linguagens que não o Java. O Apache fornece um excelente conjunto de recursos para streaming, incluindo a documentação do Hadoop Streaming e a wiki do streaming (que fornece uma boa introdução às várias opções da linha de comandos).
  • A Wikipedia fornece excelentes introduções às linguagens Lisp e Scheme, bem como uma introdução geral aos conceitos de programação funcional (e MapReduce).
  • Para demonstrar os elementos de programação funcional de map e reduce, este artigo usou o Scheme shell. Se desejar experimentar o Scheme, o SCSH é um excelente laboratório para experimentar com esta linguagem poderosa. Também é possível aprender sobre o Scheme e scripting com C no artigo de Tim Scripting com Guile (developerWorks, janeiro de 2009) ou ler uma excelente introdução ao Scheme.
  • No documento Map-Reduce para aprendizado de máquina em Multicore, o modelo MapReduce é usado para implementar uma variedade de algoritmos de aprendizado de máquina para processadores com vários núcleos. É uma leitura interessante para explorar como o modelo MapReduce pode se aplicar a uma variedade de algoritmos computacionais.
  • Hive é uma infraestrutura de armazém de dados construída sobre o Hadoop. ela fornece uma linguagem de consulta sobre dados do Hadoop, ao mesmo tempo em que suporta o modelo de programação tradicional do Hadoop. HBase é uma representação de banco de dados sobre o HDFS do Hadoop, permitindo que o MapReduce opere em tabelas de banco de dados, em vez de arquivos simples. Finalmente, Pig é uma plataforma para análise de grandes conjuntos de dados que inclui uma linguagem de alto nível para programação no Hadoop.
  • A linguagem Ruby é a mais recente das linguagens de script orientadas a objetos. Ela é dinâmica, com um foco em produtividade do programador.
  • Confira esta lista de algoritmos Mapreduce e Hadoop em documentos acadêmicos. Este site fornece uma perspectiva interessante sobre como o Hadoop é usado para uma variedade de aplicações (em ciência, aprendizado de máquina, serviços da web e mais).
  • O Yahoo! fornece um grande conjunto de recursos para o Hadoop na rede de desenvolvedores. Especificamente, o Yahoo! O Hadoop Tutorial apresenta o Hadoop e proporciona uma discussão detalhada de seu uso e configuração.
  • Na zona Linux do developerWorks, encontre centenas de artigos e tutoriais, bem como downloads, fóruns de discussão e muitos outros recursos para desenvolvedores e administradores Linux.
  • Mantenha-se atualizado com os eventos técnicos e webcasts do developerWorks focados em uma variedade de produtos IBM e assuntos da indústria de TI.
  • Participe de uma orientação gratuita do developerWorks Live! para atualizar-se rapidamente sobre produtos e ferramentas da IBM, assim como tendências da indústria de TI.
  • Assista às demos on demand do developerWorks que abrangem da instalação do produto e demos de configuração para iniciantes à funcionalidade avançada para desenvolvedores experientes.
  • Siga o developerWorks no Twitter, ou inscreva-se em um feed dos tweets do Linux no developerWorks.

Obter produtos e tecnologias

Discutir

  • Envolva-se na comunidade My developerWorks. Entre em contato com outros usuários do developerWorks enquanto explora os blogs, fóruns, grupos e wikis dos desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux, Tecnologia Java, Software livre
ArticleID=507684
ArticleTitle=Processamento de Dados Distribuídos com Hadoop, Parte 3: Desenvolvimento de aplicativo
publish-date=09282010