Поделиться через


Разработка программ MapReduce на Java для Apache Hadoop в HDInsight

Узнайте, как использовать Apache Maven, чтобы создать приложение MapReduce на основе Java, а также запустить его с помощью Apache Hadoop в Azure HDInsight.

Предварительные требования

Настройка среды разработки

Среда, использованная в этой статье, — компьютер под управлением Windows 10. Команды были выполнены в командной строке, а различные файлы были отредактированы в Блокноте. Внесите изменения в соответствии с особенностями своей среды.

В командной строке введите приведенные ниже команды, чтобы создать рабочую среду.

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

Создание проекта Maven

  1. Введите следующую команду, чтобы создать проект Maven с именем wordcountjava.

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

    Эта команда создает каталог с именем, указанным в параметре artifactID (в этом примере — wordcountjava). Этот каталог содержит следующие элементы:

    • pom.xml — это объектная модель проекта (POM), которая содержит сведения и данные конфигурации, использующиеся при сборке проекта;
    • src\main\java\org\apache\hadoop\examples: содержит код приложения.
    • src\test\java\org\apache\hadoop\examples: содержит тесты для приложения.
  2. Удалите созданный пример кода. Удалите созданные файлы тестов и приложений AppTest.java и App.java, а затем введите следующие команды:

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

Обновление модели объекта проекта

Все справочные материалы по файлу pom.xml см. по адресу https://maven.apache.org/pom.html. Откройте pom.xml, введя следующую команду:

notepad pom.xml

Добавление зависимостей

Добавьте следующий текст в раздел <dependencies> файла pom.xml:

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

Это означает, что требуются библиотеки (перечисленные в параметре <artifactId>) определенной версии (указанной в параметре <version>). При компиляции эти зависимости скачиваются из репозитория Maven по умолчанию. Можно воспользоваться поиском по репозиторию Maven , чтобы получить дополнительную информацию.

<scope>provided</scope> сообщает Maven, что эти зависимости не должны быть упакованы с приложением, так как они будут предоставлены кластером HDInsight во время выполнения.

Важно!

Используемая версия должна соответствовать версии Hadoop в кластере. Дополнительные сведения о версиях см. в статье Что представляют собой различные компоненты и версии Hadoop, доступные в HDInsight?

Конфигурация построения

Подключаемые модули Maven позволяют настроить этапы сборки проекта. Этот раздел используется для добавления подключаемых модулей, ресурсов и других параметров конфигурации сборки.

Добавьте следующий код в файл pom.xml, затем сохраните и закройте файл. Эти строки должны находиться в файле внутри тегов <project>...</project> (например, между тегами </dependencies> и </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>

В этом разделе настраиваются подключаемые модули Apache Maven Compiler и Apache Maven Shade. Подключаемый модуль компилятора используется для компиляции топологии. Подключаемый модуль shade используется для предотвращения дублирования лицензии в JAR-файле, собранном Maven. Этот подключаемый модуль используется для предотвращения ошибки с дублированием файлов лицензий, которая появляется во время выполнения на кластере HDInsight. Использование maven-shade-plugin с реализацией ApacheLicenseResourceTransformer позволяет избежать этой ошибки.

maven-shade-plugin также создает так называемый uber jar, который содержит все зависимости, требуемые для приложения.

Сохраните файл pom.xml.

Создание приложения MapReduce

  1. Введите следующую команду, чтобы создать и открыть новый файл WordCount.java. Выберите Да в запросе, чтобы создать новый файл.

    notepad src\main\java\org\apache\hadoop\examples\WordCount.java
    
  2. Затем скопируйте и вставьте приведенный ниже код Java в новый файл. После этого закройте файл.

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

    Обратите внимание, что пакет имеет имя org.apache.hadoop.examples, а класс — имя WordCount. Эти имена будут использоваться при отправке задания MapReduce.

Сборка и создание пакета приложения

Выполните следующую команду из каталога wordcountjava, чтобы собрать JAR-файл, содержащий приложение:

mvn clean package

Эта команда удаляет остатки предыдущих сборок, скачивает все неустановленные на текущий момент зависимости, а затем собирает и упаковывает приложение.

После выполнения команды каталог wordcountjava/target будет содержать файл с именем wordcountjava-1.0-SNAPSHOT.jar.

Примечание

Файл wordcountjava-1.0-SNAPSHOT.jar является uberjar, который содержит не только задание WordCount, но и зависимости, необходимые заданию во время выполнения.

Передача JAR-файла и запуск заданий (SSH)

В следующих действиях используется команда scp для копирования JAR-файла в головной узел Apache HBase в кластере HDInsight. С помощью команды ssh выполняется подключение к кластеру; пример запускается непосредственно на головном узле.

  1. Передайте JAR-файл в кластер. Замените CLUSTERNAME именем кластера HDInsight, а затем введите следующую команду:

    scp target/wordcountjava-1.0-SNAPSHOT.jar sshuser@CLUSTERNAME-ssh.azurehdinsight.net:
    
  2. Подключитесь к кластеру. Замените CLUSTERNAME именем кластера HDInsight, а затем введите следующую команду:

    ssh sshuser@CLUSTERNAME-ssh.azurehdinsight.net
    
  3. В сеансе SSH используйте следующую команду для запуска приложения MapReduce:

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

    Эта команда запускает приложение WordCount MapReduce. Входной файл — /example/data/gutenberg/davinci.txt, а выходной каталог — /example/data/wordcountout. Файлы ввода и вывода хранятся в хранилище кластера по умолчанию.

  4. По завершении задания воспользуйтесь следующей командой, чтобы просмотреть результат:

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

    Должен появиться список слов и чисел со значениями, похожими на приведенные ниже:

    zeal    1
    zelus   1
    zenith  2
    

Дальнейшие действия

В этом документе объясняется, как разработать задание MapReduce на Java. Чтобы узнать о других методах работы с HDInsight, см. следующие документы.