Статьи

Herding Apache Pig — использование Pig с Perl и Python

Примерно на прошлой неделе мы получили новые данные, которые нам пришлось быстро обработать. Существует довольно много технологий для быстрого создания карты / сокращения рабочих мест в Hadoop ( Cascading , Hive , Crunch , Jaql и многие другие), мой личный фаворит — Apache Pig . Я обнаружил, что императивный характер свиньи позволяет относительно легко понять, что происходит и куда идут данные, и что он производит достаточно эффективную карту / уменьшает. С другой стороны, у pig нет управляющих структур, поэтому работа с pig также означает, что вам необходимо расширить его с помощью пользовательских функций (UDF) или потоковой передачи Hadoop . Обычно я использую Java или Scala для написания UDF, но всегда приятно попробовать что-то новое, поэтому мы решили проверить некоторые другие технологии, а именно Perl и Python. В этом посте рассказывается о некоторых подводных камнях, которые мы встречали, и о том, как их обойти.

Юваль, который работал со мной над этим мини-проектом, любит perl (я думаю, каждому), поэтому мы начали с этого. В поисках примеров pig и perl мы нашли что-то вроде следующего:

1
2
A = LOAD 'data';
B = STREAM A THROUGH `stream.pl`;

Первая ловушка здесь заключается в том, что имя сценария perl заключено в обратный тик (символ на клавише тильды (~)), а не в одиночную кавычку (поэтому в приведенном выше скрипте «data» окружена одинарными кавычками и «stream.pl»). `окружен спинами). Второй ловушкой было то, что приведенный выше код хорошо работает, когда вы используете pig в локальном режиме (pig -x local), но он не работает, когда мы пытаемся запустить его в кластере. Потребовалось немного почесать голову и проб и ошибок, но в конце концов Ювал пришел со следующим:

1
2
3
DEFINE CMD `perl stream.pl` ship ('/PATH/stream.pl');
A = LOAD 'data'
B = STREAM A THROUGH CMD;

По сути, мы говорим pig скопировать скрипт piggy в HDFS, чтобы он был доступен на всех узлах. Итак, Perl работал довольно хорошо, но поскольку мы используем потоковую передачу Hadoop и получаем данные через stdin, мы теряем весь контекст данных, которые знает pig. Нам также необходимо эмулировать текстовые представления сумок и кортежей, чтобы возвращаемые данные были доступны для дальнейшего использования. Это все выполнимо, но работать не весело (по-моему, в любом случае). Я решил написать UDF свиньи в Python. Python можно использовать с потоковой передачей Apache, как и в приведенном выше Perl, но он также более тесно интегрируется с Pig через jython (то есть UDF Python компилируется в java и доставляется в кластер, поскольку часть jar pig генерируется для карты / уменьшить в любом случае) ,

UDF Pig лучше потоковой, поскольку вы получаете схему Pig для параметров, и вы можете указать Pig схему, которую вы возвращаете для вывода. UDF в python особенно хороши, так как код почти на 100% обычный Python, и Pig выполняет отображение за вас (например, пакет кортежей в pig транслируется в список кортежей в python и т. Д.). На самом деле единственное отличие состоит в том, что если вы хотите, чтобы Pig знал о типах данных, которые вы возвращаете из кода Python, вам нужно аннотировать метод с помощью @outputSchema, например, простой UDF, который получает месяц как int из строки даты в формате YYYY -ММ-ДД ЧЧ: ММ: СС

01
02
03
04
05
06
07
08
09
10
11
@outputSchema('num:int')
def getMonth(strDate):
    try:
        dt, _, _ = strDate.partition('.')
        return datetime.strptime(dt, '%Y-%m-%d %H:%M:%S').month
    except AttributeError:
        return 0
    except IndexError:
        return 0
    except ValueError:
        return 0

Использование PDF так же просто, как объявление файла Python, в котором определен UDF. Предполагая, что наш UDF — это файл с именем utils.py, он будет объявлен следующим образом:

1
Register utils.py using jython as utils;

И тогда использование этого UDF будет примерно таким:

1
2
A = LOAD 'data' using PigStorage('|') as (dateString:chararray);
B = FOREACH A GENERATE utils.getMonth(dateString) as month;

Опять же, как и в случае с Perl, здесь есть несколько подводных камней. для одного сценарий python и сценарий pig должны находиться в одном каталоге (относительные пути работают только в локальном режиме). Еще более раздражающая ловушка ударила меня, когда я захотел импортировать некоторые библиотеки Python (например, datetime в примере, который импортируется с использованием «from datetime import datetime»). Я не мог придумать, как сделать эту работу. Решение, которое я в итоге придумал, состояло в том, чтобы взять отдельный jjhton .jar (jar с общими библиотеками python) и заменить jython Jar Pig (в каталоге lib lib) на stanalone. Вероятно, есть более хороший способ сделать это (и я был бы рад услышать об этом), но это сработало для меня. Это нужно сделать только на машине, где вы запускаете скрипт pig, так как код python компилируется и отправляется в кластер как часть файла jar, который Pig генерирует в любом случае.

Работать с Pig и python было очень приятно. Мне больше нравилось писать UDF-файлы в Python, чем писать их на Java или Scala. Это объясняется двумя основными причинами того, что большого количества java-приложений для интеграции с pig просто нет, поэтому я могу сосредоточиться только на решении бизнес-задач, а другая причина в том, что и Pig, и Python являются «сценариями» цикла обратной связи от Внесение изменений в работу намного короче. В любом случае, Pig также поддерживает Javascript и Ruby UDF, но их придется ждать в следующий раз.

Ссылка: Herding Apache Pig — использование Pig с Perl и Python от нашего партнера по JCG Арнона Ротем-Гал-Оз в блоге Cirrus Minor .