Desenvolver programas Java MapReduce para Apache Hadoop no HDInsight

Saiba como utilizar o Apache Maven para criar uma aplicação MapReduce baseada em Java e, em seguida, executá-la com o Apache Hadoop no Azure HDInsight.

Pré-requisitos

Configurar o ambiente de desenvolvimento

O ambiente utilizado para este artigo era um computador com Windows 10. Os comandos foram executados numa linha de comandos e os vários ficheiros foram editados com o Bloco de Notas. Modifique em conformidade para o seu ambiente.

Numa linha de comandos, introduza os comandos abaixo para criar um ambiente de trabalho:

IF NOT EXIST C:\HDI MKDIR C:\HDI
cd C:\HDI

Criar um projeto do Maven

  1. Introduza o seguinte comando para criar um projeto maven com o nome wordcountjava:

    mvn archetype:generate -DgroupId=org.apache.hadoop.examples -DartifactId=wordcountjava -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    

    Este comando cria um diretório com o nome especificado pelo artifactID parâmetro (wordcountjava neste exemplo.) Este diretório contém os seguintes itens:

    • pom.xml - O Modelo de Objeto de Projeto (POM) que contém informações e detalhes de configuração utilizados para criar o projeto.
    • src\main\java\org\apache\hadoop\examples: contém o código da aplicação.
    • src\test\java\org\apache\hadoop\examples: contém testes para a sua aplicação.
  2. Remova o código de exemplo gerado. Elimine os ficheiros de teste e aplicação gerados AppTest.javae App.java , ao introduzir os comandos abaixo:

    cd wordcountjava
    DEL src\main\java\org\apache\hadoop\examples\App.java
    DEL src\test\java\org\apache\hadoop\examples\AppTest.java
    

Atualizar o Modelo de Objeto de Projeto

Para obter uma referência completa do ficheiro pom.xml, consulte https://maven.apache.org/pom.html. Abra pom.xml ao introduzir o comando abaixo:

notepad pom.xml

Adicionar dependências

Em pom.xml, adicione o seguinte texto na <dependencies> secção:

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-examples</artifactId>
    <version>2.7.3</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-common</artifactId>
    <version>2.7.3</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.7.3</version>
    <scope>provided</scope>
</dependency>

Isto define as bibliotecas necessárias (listadas em <artifactId>) com uma versão específica (listada na <versão>). No momento da compilação, estas dependências são transferidas a partir do repositório maven predefinido. Pode utilizar a pesquisa de repositório do Maven para ver mais.

O <scope>provided</scope> indica ao Maven que estas dependências não devem ser empacotadas com a aplicação, uma vez que são fornecidas pelo cluster do HDInsight em tempo de execução.

Importante

A versão utilizada deve corresponder à versão do Hadoop presente no cluster. Para obter mais informações sobre versões, veja o documento controlo de versões de componentes do HDInsight .

Compilar a configuração

Os plug-ins do Maven permitem-lhe personalizar as fases de compilação do projeto. Esta secção é utilizada para adicionar plug-ins, recursos e outras opções de configuração de compilação.

Adicione o seguinte código ao pom.xml ficheiro e, em seguida, guarde e feche o ficheiro. Este texto tem de estar dentro das <project>...</project> etiquetas no ficheiro, por exemplo, entre </dependencies> e </project>.

<build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <configuration>
        <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
            </transformer>
        </transformers>
        </configuration>
        <executions>
        <execution>
            <phase>package</phase>
                <goals>
                <goal>shade</goal>
                </goals>
        </execution>
        </executions>
        </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.1</version>
        <configuration>
        <source>1.8</source>
        <target>1.8</target>
        </configuration>
    </plugin>
    </plugins>
</build>

Esta secção configura o Plug-in do Compilador Apache Maven e o Plug-in de Sombra do Apache Maven. O plug-in do compilador é utilizado para compilar a topologia. O plug-in de sombra é utilizado para impedir a duplicação de licenças no pacote JAR criado pelo Maven. Este plug-in é utilizado para evitar um erro de "ficheiros de licença duplicados" no tempo de execução no cluster do HDInsight. A utilização do maven-shade-plugin com a ApacheLicenseResourceTransformer implementação impede o erro.

O maven-shade-plugin também produz um jar uber que contém todas as dependências exigidas pela aplicação.

Guarde o ficheiro pom.xml.

Criar a aplicação MapReduce

  1. Introduza o comando abaixo para criar e abrir um novo ficheiro WordCount.java. Selecione Sim na linha de comandos para criar um novo ficheiro.

    notepad src\main\java\org\apache\hadoop\examples\WordCount.java
    
  2. Em seguida, copie e cole o código Java abaixo no novo ficheiro. Em seguida, feche o ficheiro.

    package org.apache.hadoop.examples;
    
    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;
    import org.apache.hadoop.util.GenericOptionsParser;
    
    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();
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.err.println("Usage: wordcount <in> <out>");
            System.exit(2);
        }
        Job job = new Job(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(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
        }
    }
    

    Repare que o nome do pacote é org.apache.hadoop.examples e o nome da classe é WordCount. Utilize estes nomes quando submeter a tarefa mapReduce.

Criar e empacotar a aplicação

wordcountjava No diretório, utilize o seguinte comando para criar um ficheiro JAR que contenha a aplicação:

mvn clean package

Este comando limpa quaisquer artefactos de compilação anteriores, transfere quaisquer dependências que ainda não tenham sido instaladas e, em seguida, compila e empacota a aplicação.

Quando o comando for concluído, o wordcountjava/target diretório contém um ficheiro com o nome wordcountjava-1.0-SNAPSHOT.jar.

Nota

O wordcountjava-1.0-SNAPSHOT.jar ficheiro é um uberjar, que contém não só a tarefa wordCount, mas também as dependências de que a tarefa necessita no runtime.

Carregar o JAR e executar tarefas (SSH)

Os passos seguintes utilizam scp para copiar o JAR para o nó principal primário do apache HBase no cluster do HDInsight. Em ssh seguida, o comando é utilizado para ligar ao cluster e executar o exemplo diretamente no nó principal.

  1. Carregue o jar para o cluster. Substitua pelo CLUSTERNAME nome do cluster do HDInsight e, em seguida, introduza o seguinte comando:

    scp target/wordcountjava-1.0-SNAPSHOT.jar sshuser@CLUSTERNAME-ssh.azurehdinsight.net:
    
  2. Ligue-se ao cluster. Substitua pelo CLUSTERNAME nome do cluster do HDInsight e, em seguida, introduza o seguinte comando:

    ssh sshuser@CLUSTERNAME-ssh.azurehdinsight.net
    
  3. Na sessão SSH, utilize o seguinte comando para executar a aplicação MapReduce:

    yarn jar wordcountjava-1.0-SNAPSHOT.jar org.apache.hadoop.examples.WordCount /example/data/gutenberg/davinci.txt /example/data/wordcountout
    

    Este comando inicia a aplicação WordCount MapReduce. O ficheiro de entrada é /example/data/gutenberg/davinci.txte o diretório de saída é /example/data/wordcountout. Tanto o ficheiro de entrada como o resultado são armazenados no armazenamento predefinido do cluster.

  4. Depois de concluída a tarefa, utilize o seguinte comando para ver os resultados:

    hdfs dfs -cat /example/data/wordcountout/*
    

    Deverá receber uma lista de palavras e contagens, com valores semelhantes ao seguinte texto:

    zeal    1
    zelus   1
    zenith  2
    

Passos seguintes

Neste documento, aprendeu a desenvolver uma tarefa de Java MapReduce. Veja os seguintes documentos para obter outras formas de trabalhar com o HDInsight.