Дата поста: 05-11-2013
Сегодня посчастливилось ознакомиться со статьей Майкла Нолла (Michael Noll) о том, как написать распределённое Hadoop приложение на питоне (Python).
Я всегда был большим поклонником распределённой обработки (MapReduce), но, так как в своей работе использую PHP, я подумал, что неплохо бы было портировать этот пример и показать, как можно создавать распределенные приложения на PHP.
Чтобы глубже понять, что мы будем делать дальше, рекомендую прочитать упомянутую выше оригинальную статью. Для начала нужно установить и запустить Hadoop, но установка Hadoop-кастера — это довольно нетривиальная задача, с которой можно провозиться весь день. Однако, если Вы хотите поэкспериментировать с платформой прямо сейчас, можно загрузить образ виртуальной машины с предварительно сконфигурированной единичной Hadoop нодой. Конечно, у Вас не будет высокопроизводительного Hadoop-кластера, но будет возможность проводить эксперименты на своей локальной машине, запуская простые MapReduce задачи. Виртуалка создана так, что её можно использовать с помощью бесплатного VMware плеера.
Образ виртуальной машины можно загрузить с Google Code University (150Мб). Образ имеет предустановленных пользователей:
> root root
> guest guest
Для установки php5 запустите
apt-get install php5-cli
из-под пользователя root. Если не устанавливается, сделайте
apt-get update
и повторите установку php.
Маp: mapper.php
Скрипт, который выполняет кусочек основной задачи. Сохраните приведенный ниже код в файл /home/guest/mapper.php
:
#!/usr/bin/php
<?php
$word2count = array();
// Ввод данных происходит через STDIN
while (($line = fgets(STDIN)) !== false) {
// убираем лишние символы и переводим в нижний регистр
$line = strtolower(trim($line));
// разбиваем строки по словам и убираем пустые значения
$words = preg_split('/\W/', $line, 0, PREG_SPLIT_NO_EMPTY);
// увеличиваем счетчик
foreach ($words as $word) {
$word2count[$word] += 1;
}
}
// Вывод результатов в STDOUT
// Эти данные будут обрабатываться "склеиваться" reducer.php
// Reduce step, i.e. the input for reducer.py
foreach ($word2count as $word => $count) {
// разделение табуляцией
echo $word, chr(9), $count, PHP_EOL;
}
?>
Reduce: reducer.php
Сохраните приведенный ниже код в файл /home/guest/reducer.php
:
#!/usr/bin/php
<?php
$word2count = array();
// input comes from STDIN
while (($line = fgets(STDIN)) !== false) {
// убираем лишние символы и переводим в нижний регистр
$line = trim($line);
// разбираем данные, которые прислал mapper.php
list($word, $count) = explode(chr(9), $line);
// приводим тип - из строки в целое число
$count = intval($count);
// суммируем
if ($count > 0) $word2count[$word] += $count;
}
// сортируем результат
//
// это не обязательно, но есть в официальном примере работы с Hadoop
ksort($word2count);
// выводим результат в STDOUT
foreach ($word2count as $word => $count) {
echo $word, chr(9), $count, PHP_EOL;
}
?>
Не забудьте выставить права на выполнение скрипта.
chmod +x /home/guest/mapper.php /home/guest/reducer.php
Запускаем PHP-код на Hadoop:
Загружаем тестовые данные
Как и у Майкла Нолла, для данного примера мною были использованы электронные книги из проекта Gutenberg:
- http://www.gutenberg.org/files/20417/20417-8.txt
- http://www.gutenberg.org/dirs/etext04/7ldvc10.txt
- http://www.gutenberg.org/dirs/etext02/0xhgp10a.txt
- http://www.gutenberg.org/dirs/etext02/01hgp10a.txt
- и т.д.
Загрузите каждую книгу и сохраните ее в какую-нибудь директорию на выбор, например в /tmp/gutenberg
Копируем данные на распределённую файловую систему HDFS
Перед запуском тестовой задачи нужно скопировать данные с локальной файловой системы на распределённую файловую систему Hadoop’s HDFS
bin/hadoop dfs -copyFromLocal /tmp/gutenberg gutenberg
Запускаем тестовый пример
Теперь все готово к запуску нашей распределенной задачи на Hadoop-кластере. Для того, чтобы уменьшить обмен данными через STDIN и STDOUT между Map и Reduce компонентами, используем HadoopStreaming.
bin/hadoop jar contrib/hadoop-streaming.jar
-mapper /home/guest/mapper.php
-reducer /home/guest/reducer.php
-input gutenberg/* -output gutenberg-output
Как это работает
Эта задача читает все файлы в HDFS директории gutenberg, обрабатывает их и сохраняет результат в файл, который находится в HDFS директории gutenberg-output.
Вы можете проследить состояние задачи, используя web-интерфейс Hadoop http://localhost:50030/
Когда задача будет отработана, проверьте, чтобы результат был сохранен в выходной HADOOP директории gutenberg-output:
bin/hadoop dfs -ls gutenberg-output
Вы также можете просмотреть содержимое файла, используя команду dfs -cat:
bin/hadoop dfs -cat gutenberg-output/part-00000
Вот и все, познавайте магию Hadoop — это будущее 😉