Статьи

Основы Hadoop – создание программы MapReduce

Hadoop — это проект с открытым исходным кодом для обработки больших наборов данных параллельно с использованием низкоуровневых машин.

Hadoop состоит из двух основных частей: специальной файловой системы, называемой Hadoop Distributed File System (HDFS), и Map Reduce Framework.

Файловая система HDFS — это оптимизированная файловая система для распределенной обработки очень больших наборов данных на обычном оборудовании.

Каркас Map Reduce работает в двух основных фазах для обработки данных: фаза «карта» и фаза «сокращение».

Чтобы объяснить это, давайте создадим пример приложения Hadoop.

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

Это приложение будет принимать различные словари перевода с английского на другие языки (английский-испанский, английский-итальянский, английский-французский) и создавать файл словаря, в котором есть английское слово, за которым следуют все переводы, разделенные пробелом.

Прежде всего, конечно же, загрузка Hadoop. Переходим в каталог, в который мы хотим установить hadoop, и скачиваем его wget http://apache.favoritelinks.net//hadoop/core/stable/hadoop-0.20.2.tar.gz. Затем распакуйте его tar zxvf hadoop-0.21.0.tar.gz.

Теперь мы получаем файлы нашего словаря. Я скачал их с http://www.ilovelanguages.com/IDP/files/.txt

Следующим шагом будет размещение наших файлов в HDFS (этот пример на самом деле не должен делать это, но я делаю это только для того, чтобы показать как). Для этого нам нужно сначала отформатировать файловую систему в HDFS. Это делается следующим образом:

Переходим в каталог bin из hadoop и выполняем ./hadoop namenode -format. По умолчанию это отформатирует каталог / tmp / hadoop-username / dfs / name.

После того, как система отформатирована, нам нужно поместить наши словарные файлы в эту файловую систему. Hadoop лучше работает с одним большим файлом, чем со многими маленьким. Таким образом, мы объединяем файлы в один, чтобы поместить их туда.

Хотя это лучше сделать при записи в файловую систему hadoop с помощью операции PutMerge, мы сначала объединяем файлы, а затем копируем их в hdfs, что проще, и наши примеры файлов невелики.

cat French.txt >> fulldictionary.txt

cat Italian.txt >> fulldictionary.txt

cat Spanish.txt >> fulldictionary.txt

Чтобы скопировать файл в hdfs, мы выполним следующую команду:

./hadoop fs -put /home/cscarioni/Documentos/hadooparticlestuff/fulldictionary.txt /tmp/hadoop-cscarioni/dfs/name/file

Теперь мы создадим реальную программу уменьшения карты для обработки данных. Программа будет полностью содержаться в одном уникальном файле Java. В файле у нас будут алгоритмы Map и Reduce. Давайте посмотрим код, а затем объясним, как работает каркас сокращения карты.

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.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class Dictionary
{
    public static class WordMapper extends Mapper<Text, Text, Text, Text>
    {
        private Text word = new Text();
        public void map(Text key, Text value, Context context) throws IOException, InterruptedException
        {
            StringTokenizer itr = new StringTokenizer(value.toString(),",");
            while (itr.hasMoreTokens())
            {
                word.set(itr.nextToken());
                context.write(key, word);
            }
        }
    }
    public static class AllTranslationsReducer
    extends Reducer<Text,Text,Text,Text>
    {
        private Text result = new Text();
        public void reduce(Text key, Iterable<Text> values,
        Context context
        ) throws IOException, InterruptedException
        {
            String translations = "";
            for (Text val : values)
            {
                translations += "|"+val.toString();
            }
            result.set(translations);
            context.write(key, result);
        }
    }
    public static void main(String[] args) throws Exception
    {
        Configuration conf = new Configuration();
        Job job = new Job(conf, "dictionary");
        job.setJarByClass(Dictionary.class);
        job.setMapperClass(WordMapper.class);
        job.setReducerClass(AllTranslationsReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        job.setInputFormatClass(KeyValueTextInputFormat.class);
        FileInputFormat.addInputPath(job, new Path("/tmp/hadoop-cscarioni/dfs/name/file"));
        FileOutputFormat.setOutputPath(job, new Path("output"));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

Наблюдая за кодом, мы видим, что наш класс состоит в основном из трех частей. Статический класс содержит маппер, другой статический класс содержит редуктор, а основной метод работает как драйвер нашего приложения. Следуйте за кодом, читая следующие несколько абзацев.

Во-первых, давайте поговорим о картографе

Наш картограф — очень стандартный картограф. Основная работа картографа — создать список пар ключ-значение для последующей обработки. Идеальная структура этого списка пар ключ-значение такова, что ключи будут повторяться во многих элементах списка (созданных этим же картографом или другим, который объединит свои результаты с этим), так что на следующих этапах карты уменьшится Алгоритм использовать их. Сопоставитель получает ключ, пару значений в качестве параметров и, как уже было сказано, создает список новых ключей, пар значений.

Пара ключ-значение, полученная преобразователем, зависит от используемой реализации InputFormat . В нашем примере мы используем KeyValueTextInputFormat . Эта реализация использует в качестве каждой пары значение ключа начало каждой строки входного файла до первого пробела в качестве ключа, а оставшуюся часть строки в качестве значения. Поэтому, если строка содержит aaa bbb, ccc, ddd, мы получим aaa в качестве ключа и bbb, ccc, ddd в качестве значения.

Из каждого ввода в преобразователь сгенерированный список пар ключ-значение представляет собой ключ, объединенный с каждым из значений, разделенных запятой. Объяснение: Для ввода aaa bbb, ccc, ddd вывод будет: List (aaa bbb, aaa ccc, aaa ddd) и для каждого входа в преобразователь.

Редуктор

После картографа и перед редуктором происходят фазы перемешивания и объединения. Фаза shuffler гарантирует, что каждая пара значений ключа с одним и тем же ключом поступает к одному и тому же редуктору, а объединяющая часть преобразует все пары значений ключа одного и того же ключа в ключ формы группировки list (values), который в конечном итоге получает редуктор. ,

Задача более стандартного редуктора — взять пару ключей (значений), работать с сгруппированными значениями и хранить их где-нибудь. Это именно то, что делает наш редуктор. Он берет пару списка ключей (значений), просматривает значения, объединяющие их в строку, разделенную конвейером, и отправляет новую пару значений ключа на выход, поэтому список aaa пары (aaa, bbb) преобразуется в aaa aaa | BBB и хранится вне.

Чтобы запустить нашу программу, просто запустите ее как обычный основной файл java с библиотеками hadoop на classpath (все jar в домашнем каталоге hadoop и все jar в каталоге lib hadoop. Вы также можете запустить команду hadoop с параметром classpath, чтобы получить полный требуемый путь к классам). Для этого первого теста я использовал IDE DrJava.

Запуск программы в моем случае сгенерировал файл с именем part-r-00000 с ожидаемым результатом.

Распространение

Основной причиной существования Map Reduce Framework является выполнение обработки большого количества данных распределенным способом на обычных машинах. На самом деле, запускать его только на одной машине не намного полезнее, чем учить нас, как это работает.

Распространение приложения может быть предметом другого более продвинутого поста.