Начало работы с MapReduce
Код приложения для MapReduce состоит из трех частей:
-
Mapper
-
Reducer
-
Driver
Эти части, как правило, базируются на классах с такими же названиями:
-
Mapper. Этот класс отвечает за выполнение первой стадии обработки данных. Объект
InputSplit
является логическим представлением входных данных. Он описывает единицу работы, которую выполняет одна задача на стадии Map в задании для MapReduce.RecordReader
обрабатывает каждую отдельную запись и генерирует соответствующую пару ключ-значение. MapReduce сохраняет эти промежуточные данные на локальном диске узла. -
Reducer. Этот класс отвечает за выполнение второй стадии обработки данных. MapReduce поставляет промежуточные данные, сгенерированные процессами mapper, на вход процессам reducer, которые формируют окончательные данные и сохраняют их в HDFS.
-
Driver. Данный класс отвечает за настройку задания для MapReduce, которое будет запущено в Hadoop.
Рассматриваемый пример будет подсчитывать слова в текстовом файле sample.txt с использованием MapReduce. Мы определим уникальные слова и сколько раз каждое слово встречается в тексте. Обработка данных проходит несколько стадий, как представлено на следующей схеме.
-
Как представлено на схеме, входной текст разделен на три части, распределенные по узлам DataNodes.
-
Каждый экземпляр mapper разбивает полученный текст на токены (слова) и присваивает каждому из них значение
1
. -
Образуется столько пар ключ-значение (где ключ — это слово, а значение — 1), сколько всего слов в строке без учета уникальности. Например, из первой строки "One Two Three" получим три пары: ("One", 1), ("Two", 1) и ("Three", 1). Если какое-то слово встречается несколько раз, то образуется такое же количество одинаковых пар. Данный процесс работает одинаково на всех узлах.
-
После фазы map выполняется процесс сортировки и распределения (shuffling) данных так, что все пары с одинаковым ключом будут направлены на вход одного процесса агрегации (reducer).
-
После распределения каждый reducer получит уникальный ключ и список значений, где каждое значение равно 1, например: ("One", [1,1]), ("Zero", [1,1,1]) и так далее.
-
Агрегатор складывает все значения в списке. Например, в приведенной схеме агрегатор получает список [1,1] по ключу "One". Он подсчитывает количество единиц в списке и формирует окончательный результат – ("One", 2).
-
В конечном итоге MapReduce собирает все пары и записывает их в один файл.
Код Mapper
Код mapper выполняет следующие операции:
-
Создает класс
Map
, расширяющий классMapper
из библиотеки MapReduce. -
Определяет типы входных и выходных ключей и значений в угловых скобках в определении класса. Как вход, так и выход метода обработки данных внутри класса состоят из пар ключ-данные.
Входные данные:-
Ключ равен смещению соответствующей ему строки текста во входном файле — тип
LongWritable
(изменяемое длинное целое число). -
Значением является строка, на которую указывает ключ — тип
Text
.
Выходные данные:-
Ключом является слово, выделенное как токен — тип
Text
. -
Значение, закрепленное в коде, равно 1 — тип
IntWritable
(изменяемое целое число).Пример выходных данных: ("Dear", 1), ("Bear", 1) и так далее.
Мы представили код, написанный на Java, который разделяет текст на токены и назначает каждому значение 1.
-
Код Reducer
Код агрегации (reducer) выполняет следующие операции:
-
Создает класс
Reduce
, расширяющий классReducer
аналогично тому, как это сделано в Mapper. -
Задает типы данных для входных и выходных ключей и значений аналогично тому, как это сделано для Mapper. На входе и выходе основного метода обработки данных используются пары ключ-значение.
Входные данные:-
Ключом является уникальное слово, выделенное в результате сортировки и распределения данных — тип
Text
. -
Значением является список целых чисел, соответствующих ключу — тип
IntWritable
.Пример входных данных: ("Bear", [1, 1]), ("Car", [1, 1, 1]) и так далее.
Выходные данные:-
Ключом является одно из уникальных слов, обнаруженных во входном текстовом файле — тип
Text
. -
Значением является частота вхождения слова в тексте — тип
IntWritable
.Пример выходных данных: ("Bear", 2), ("Car", 3) и так далее.
-
Рассмотренный код агрегирует значения, представленные в списке каждого ключа, и выдает окончательный результат. Процесс reducer выполняется для каждого уникального слова, а ограничение на общее количество таких параллельных процессов определено в mapred-site.xml.
Код Driver
Код driver выполняет следующие операции:
-
Настраивает задание (job) для MapReduce в Hadoop.
-
Дает название заданию, определяет типы входных и выходных данных для обработчиков mapper и reducer.
-
Определяет названия классов для mapper и reducer.
-
Задает пути к папкам для нахождения входных данных и записи выходных данных.
Метод setInputFormatClass()
определяет способ чтения входных данных или единицу работы. Здесь мы выбрали тип TextInputFormat
, в результате чего mapper считывает данные из входного файла построчно.
Метод main()
является точкой входа. Этот метод активизирует объект Configuration
для задания.