Sviluppare programmi Java MapReduce per Apache Hadoop in HDInsight

Informazioni sull'uso di Apache Maven per creare un'applicazione MapReduce basata su Java, quindi per eseguirla con Apache Hadoop su Azure HDInsight.

Prerequisiti

Configurare l'ambiente di sviluppo

L'ambiente usato per questo articolo è un computer che esegue Windows 10. I comandi sono stati eseguiti in un prompt dei comandi e i vari file sono stati modificati con blocco note. Modificare di conseguenza per l'ambiente.

Da un prompt dei comandi immettere i comandi seguenti per creare un ambiente di lavoro:

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

Creare un progetto Maven

  1. Immettere il comando seguente per creare un progetto Maven denominato wordcountjava:

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

    Questo comando crea una directory con il nome specificato dal artifactID parametro (wordcountjava in questo esempio). Questa directory contiene gli elementi seguenti:

    • pom.xml: il modello a oggetti dei progetti (POM o Project Object Model) che contiene le informazioni e i dettagli di configurazione usati per compilare il progetto.
    • src\main\java\org\apache\hadoop\examples: contiene il codice dell'applicazione.
    • src\test\java\org\apache\hadoop\examples: contiene test per l'applicazione.
  2. Rimuovere il codice di esempio generato. Eliminare i file AppTest.javadi test e dell'applicazione generati e App.java immettendo i comandi seguenti:

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

Aggiornare il modello a oggetti dei progetti

Per informazioni di riferimento complete sul file pom.xml, vedere https://maven.apache.org/pom.html. Aprire pom.xml immettendo il comando seguente:

notepad pom.xml

Aggiungere le dipendenze

In pom.xmlaggiungere il testo seguente nella <dependencies> sezione :

<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>

Questa operazione definisce le librerie richieste (elencate in <artifactId>) con una versione specifica (elencata in <version>). In fase di compilazione, queste dipendenze vengono scaricata dal repository Maven predefinito. È possibile usare la ricerca nel repository Maven per visualizzare più informazioni.

<scope>provided</scope> indica a Maven che queste dipendenze non devono essere fornite con l'applicazione, perché vengono fornite dal cluster HDInsight in fase di esecuzione.

Importante

La versione usata deve corrispondere alla versione di Hadoop presente nel cluster. Per altre informazioni sulle versioni, vedere il documento sulle versioni dei componenti HDInsight.

Configurare la compilazione

I plug-in di Maven consentono di personalizzare le fasi di compilazione del progetto. Questa sezione viene usata per aggiungere plug-in, risorse e altre opzioni di configurazione della compilazione.

Aggiungere il codice seguente al pom.xml file e quindi salvare e chiudere il file. Nel file, il testo deve essere incluso tra i tag <project>...</project>, ad esempio tra </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>

Questa sezione configura il plug-in del compilatore Apache Maven e il plug-in di shade Apache Maven. Il plug-in compiler viene usato per compilare la topologia, mentre il plug-in shade viene usato per impedire la duplicazione della licenza nel pacchetto JAR compilato da Maven. Questo plug-in viene usato per evitare che i file di licenza duplicati causino un errore in fase di esecuzione sul cluster HDInsight. L'uso di maven-shade-plugin con l'implementazione di ApacheLicenseResourceTransformer previene il verificarsi di questo errore.

Il plug-in maven-shade-plugin produce anche un file uberjar, che contiene tutte le dipendenze richieste dall'applicazione.

Salvare il file.pom.xml

Creare l'applicazione MapReduce

  1. Immettere il comando seguente per creare e aprire un nuovo file WordCount.java. Selezionare al prompt per creare un nuovo file.

    notepad src\main\java\org\apache\hadoop\examples\WordCount.java
    
  2. Copiare e incollare il codice Java seguente nel nuovo file. Chiudere quindi il file.

    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);
        }
    }
    

    Si noti che il nome del pacchetto è org.apache.hadoop.examples e il nome della classe è WordCount. Questi nomi vengono usati per l'invio del processo MapReduce.

Compilare e creare il pacchetto dell'applicazione

Dalla directory wordcountjava usare il comando seguente per compilare un file JAR contenente l'applicazione:

mvn clean package

In tal modo, vengono eliminati eventuali elementi di compilazione precedenti, scaricate le dipendenze non ancora installate e quindi compilato e creato il pacchetto dell'applicazione.

Al completamento del comando, la directory wordcountjava/target contiene un file denominato wordcountjava-1.0-SNAPSHOT.jar.

Nota

Il file wordcountjava-1.0-SNAPSHOT.jar è un file di tipo uberjar che contiene non solo il processo WordCount, ma anche le dipendenze richieste dal processo durante il runtime.

Caricare il file JAR ed eseguire i processi (SSH)

La procedura seguente usa scp per copiare il file JAR nel nodo head primario di Apache HBase nel cluster HDInsight. Il comando ssh viene quindi usato per connettersi al cluster ed eseguire l'esempio direttamente nel nodo head.

  1. Caricare il file JAR nel cluster. Sostituire CLUSTERNAME con il nome del cluster HDInsight e quindi immettere il comando seguente:

    scp target/wordcountjava-1.0-SNAPSHOT.jar sshuser@CLUSTERNAME-ssh.azurehdinsight.net:
    
  2. Connettersi al cluster. Sostituire CLUSTERNAME con il nome del cluster HDInsight e quindi immettere il comando seguente:

    ssh sshuser@CLUSTERNAME-ssh.azurehdinsight.net
    
  3. Nella sessione SSH usare il comando seguente per eseguire l'applicazione MapReduce:

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

    Questo comando avvia l'applicazione MapReduce WordCount. Il file di input è /example/data/gutenberg/davinci.txt e la directory di output è /example/data/wordcountout. I file di input e di output saranno archiviati nell'archiviazione predefinita del cluster.

  4. Dopo il completamento del processo, usare il comando seguente per visualizzare i risultati:

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

    Dovrebbe essere visualizzato un elenco di parole e conteggi, con valori simili al testo seguente:

    zeal    1
    zelus   1
    zenith  2
    

Passaggi successivi

In questo documento si è appreso come sviluppare un processo Java MapReduce. Vedere i documenti seguenti per altre modalità di utilizzo di HDInsight.