Введение
В огромном пустыне-dessерте один торговец отправляется в опасный путь, пытаясь разгадать тайны, скрытые под жёстким солнцем и песком. Целью торговца является обнаружение древних реликвий и артефактов, раскрытие секретов давно забытой цивилизации. Однако огромный объем данных, заложенных в песке, представляет собой огромную проблему, требующую мощности Hadoop MapReduce для эффективной обработки и анализа информации.
Реализация маппера
В этом шаге мы создадим класс маппера для обработки сырых данных, полученных из раскопок в пустыне. Наша цель - извлечь из данных соответствующую информацию и подготовить ее для дальнейшего анализа редьюсером.
Используйте команду su - hadoop, чтобы переключиться на пользователя hadoop и автоматически перейти в директорию /home/hadoop. В этот момент используйте команду ls., чтобы увидеть файл данных data*.txt. Затем создайте и заполните файл ArtifactMapper.java в этой директории в соответствии с кодом ниже:
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class ArtifactMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
private final static LongWritable ONE = new LongWritable(1);
private Text word = new Text();
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// Разделяем строку на слова
String[] tokens = value.toString().split("\\s+");
// Выводим каждое слово с количеством 1
for (String token : tokens) {
word.set(token);
context.write(word, ONE);
}
}
}
В классе ArtifactMapper мы расширяем класс Mapper, предоставляемый Hadoop. Метод map переопределяется для обработки каждой пары ключ-значение входных данных.
- Входной ключ - это
LongWritable, представляющий смещение байтов в строке входных данных, а входное значение - это объектText, содержащий строку текста из входного файла. - Метод
mapразделяет входную строку на отдельные слова с использованием методаsplitи регулярного выражения"\\s+"для сопоставления одного или более пробельных символов. - Для каждого слова метод
mapсоздает объектTextи выводит его в качестве ключа, а также постоянное значениеLongWritableравное1в качестве значения, представляющее количество этого слова.
Реализация редьюсера
В этом шаге мы создадим класс редьюсера для агрегации данных, выданных маппером. Редьюсер подсчитает количество вхождений каждого слова и выдаст окончательный результат.
Создайте и заполните файл ArtifactReducer.java в директории /home/hadoop в соответствии с следующим содержанием кода:
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class ArtifactReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
public void reduce(Text key, Iterable<LongWritable> values, Context context)
throws IOException, InterruptedException {
long sum = 0;
for (LongWritable value : values) {
sum += value.get();
}
context.write(key, new LongWritable(sum));
}
}
В классе ArtifactReducer мы расширяем класс Reducer, предоставляемый Hadoop. Метод reduce переопределяется для агрегации значений, связанных с каждым ключом.
- Входной ключ - это объект
Text, представляющий слово, а входные значения - этоIterableобъектовLongWritable, представляющих количество вхождений этого слова, выданных мапперами. - Метод
reduceперебирает значения и вычисляет сумму всех подсчетов для данного слова. - Затем метод
reduceвыводит слово в качестве ключа и общую сумму в качестве значения, используяcontext.write.
Создание драйвера
В этом шаге мы создадим класс драйвера для управления процессом MapReduce. Драйвер настроит задачу, укажет пути для ввода и вывода и отправит задачу в кластер Hadoop.
Создайте и заполните файл ArtifactDriver.java в директории /home/hadoop в соответствии с следующим содержанием кода:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class ArtifactDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "Artifact Word Count");
// Укажите jar-файл задачи по классу
job.setJarByClass(ArtifactDriver.class);
// Установите классы маппера и редьюсера
job.setMapperClass(ArtifactMapper.class);
job.setReducerClass(ArtifactReducer.class);
// Установите типы ключей и значений вывода
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
// Установите пути для ввода и вывода
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// Отправьте задачу и подождите ее завершения
System.exit(job.waitForCompletion(true)? 0 : 1);
}
}
В классе ArtifactDriver мы создаем задачу MapReduce и настраиваем ее для запуска наших классов ArtifactMapper и ArtifactReducer.
- Метод
mainсоздает новый объектConfigurationи объектJobс именем "Artifact Word Count". - Методы
setMapperClassиsetReducerClassиспользуются для указания классов маппера и редьюсера, которые будут использоваться в задаче. - Методы
setOutputKeyClassиsetOutputValueClassиспользуются для указания типов ключей и значений вывода для задачи. - Метод
FileInputFormat.addInputPathиспользуется для указания пути для ввода задачи, который берется в качестве первого аргумента командной строки. - Метод
FileOutputFormat.setOutputPathиспользуется для указания пути для вывода задачи, который берется в качестве второго аргумента командной строки. - Метод
job.waitForCompletionвызывается для отправки задачи и ожидания ее завершения. Программа завершается с кодом статуса 0, если задача выполнена успешно, или 1, если она завершилась с ошибкой.
Компиляция и запуск задачи
В этом шаге мы скомпилируем Java-классы и запустим задачу MapReduce на кластере Hadoop.
Во - первых, нам нужно скомпилировать Java-классы:
javac -source 8 -target 8 -classpath $HADOOP_HOME/share/hadoop/common/hadoop-common-3.3.6.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:. *.java
Эта команда компилирует Java-классы и помещает скомпилированные файлы .class в текущую директорию. Параметр -classpath включает пути к библиотекам Hadoop, которые необходимы для компиляции кода, использующего классы Hadoop. Параметры -source и -target используются для указания версий исходного Java и целевого байт-кода, чтобы соответствовать версии Java в Hadoop.
Далее, упакуем файлы .class с помощью команды jar:
jar -cvf Artifact.jar *.class
Наконец, мы можем запустить задачу MapReduce, и все данные о пустыне уже хранятся в директории HDFS /input:
hadoop jar Artifact.jar ArtifactDriver /input /output
После выполнения команды вы должны увидеть логи, показывающие прогресс задачи MapReduce. Как только задача завершена, вы можете найти выходные файлы в директории HDFS /output. И используйте следующие команды, чтобы просмотреть результат:
hdfs dfs -ls /output
hdfs dfs -cat /output/part-r-00000
Резюме
Поздравляем! Вы успешно освоили процесс написания кодов мапперов и редьюсеров для задачи Hadoop MapReduce. Руководствуясь сценарием, в котором торговец в пустыне ищет древние артефакты, вы воспользовались мощью Hadoop MapReduce для анализа огромных данных о пустыне. Реализация класса ArtifactMapper позволяла извлекать соответствующие данные, а класс ArtifactReducer агрегировал выходные данные маппера. Управление процессом с использованием класса ArtifactDriver еще более углубило ваше понимание. На протяжении всего процесса акцентировалось внимание на лучших практиках, полных примерах кода и проверках. Этот практический опыт углубил ваше понимание Hadoop MapReduce и подчеркнул эффективный дизайн обучения.



