Мэппер и Редуктор с итераторами и генераторами - Hadoop Python
Primary tabs
Давайте немного усовершенствуем код мэппера и редуктора отсюда:
1) mapper.py
#!/usr/bin/env python """Более сложный Mapper, использующий Итераторы и генераторы Питона""" import sys # эта функция вернёт своебразный "массив массивов" def read_input(file): for line in file: # разбивает строку на слова yield line.split() # возвращает генератор """Точка входа в мэппер с разделителем в виде таба в качестве разделителя по-умолчанию.""" def main(separator='\t'): # Передаём в качестве "файла" стандартный поток ввода data = read_input(sys.stdin) for words in data: # Пишем результаты в стандартный поток вывода # what we output here will be the input for the Выход мэппера будет входом редуктора # Reduce step, i.e. the input for reducer.py # # отделяем слово табом от формального # ("формального" так как сумма ещё не подсчитана - это будет сделано в редукторе) # числа вхождений равного 1 for word in words: print '%s%s%d' % (word, separator, 1) if __name__ == "__main__": main()
2) reducer.py
#!/usr/bin/env python from itertools import groupby from operator import itemgetter import sys # читаем выход мэппера # и разбиваем каждую пару на ключ-значение # по знаку табуляции def read_mapper_output(file, separator='\t'): for line in file: yield line.rstrip().split(separator, 1) def main(separator='\t'): # будем читать из стандартного потока ввода data = read_mapper_output(sys.stdin, separator=separator) # groupby groups multiple word-count pairs by word, # and creates an iterator that returns consecutive keys and their group: # current_word - string containing a word (the key) # group - iterator yielding all ["<current_word>", "<count>"] items # с помощью groupby группирует пары "слово-число вхождений" # по значению слова и создаёт итератор # # # for current_word, group in groupby(data, itemgetter(0)): try: total_count = sum(int(count) for current_word, count in group) print "%s%s%d" % (current_word, separator, total_count) except ValueError: # count was not a number, so silently discard this item pass if __name__ == "__main__": main()
- Log in to post comments
- 21626 reads
humanmashine
Mon, 02/10/2014 - 22:34
Permalink
Немного прокомментирую reducer
Этот код:
Возвращает генератор, который при каждой итерации будет возвращать список из двух строк полученных расзделением строки. считанной из файла, оттталкиваясь от разделителя (сепаратора). Как я понял из предыдущих примеров, выглядить будет так: ['foo', '1'].
Это выражение вернёт генератор, который будет при каждой итерации возвращать кортедж, первое значение - это сгруппированное значение в коллекции без повторений, тоесть если у нас такая коллекция: [['foo', '1'], ['foo', '1'], ['foo', '1']], то результат будет (['foo', '1'], [['foo', '1'], ['foo', '1'], ['foo', '1']]), причём жирный список, это утрированное представление значений генератора, по настоящему вместо жирного списка будет генератор и чтобы получить эти значения, надо его "проитерировать" (скажем применить функцияю list()).
Слудея вышесказанному, следующий цикл:
Будет перебирать все слова в data, но уже без повторений, а сами повторения можно выбрать из group - так как это генератор, из которого можно достать ранее рассмотренные "жирные" значения. Собственно в цикле мы с помощью генератора списков:
который формирует список чисел, находим сумму элементов списка, используя встроенную функцию sum().
vedro-compota
Tue, 02/11/2014 - 11:29
Permalink
м?)
м?)
_____________
матфак вгу и остальная классика =)
vedro-compota
Tue, 02/11/2014 - 11:29
Permalink
будет при каждой итерации
то есть первое значение этого кортежа - это тоже кортеж (пара - ['foo', '1'])
тогда получается, что в current_word попадёт не слово ....
выходит что кортеж такой: ('foo', [['foo', '1'], ['foo', '1'], ['foo', '1']]) ?
_____________
матфак вгу и остальная классика =)
humanmashine
Tue, 02/11/2014 - 12:52
Permalink
Да )))
Да, ошибся. Первое значение - это ключ группировки, в нашем случае - слово.
vedro-compota
Wed, 02/12/2014 - 15:37
Permalink
ок) в любом случае - ответ
ок) в любом случае - ответ был отличный (в конце я пропишу комментарии в первом сообщений)
ещё уточнение:
у нас эта строка лихо пишет значения сразу в две переменные.
а может ли сразу в три, четыре и т.д.?
_____________
матфак вгу и остальная классика =)
humanmashine
Wed, 02/12/2014 - 20:10
Permalink
Да, можно и три и четыре и сто-пятьсот
Этот вопрос можно выделить в отдельную тему. Тему присваивания. Дело в том, что в Python можно присваивать элементы картежа (или другой коллекции, скажем списка) отдельным переменным (Упаковка и распаковка). Это учень удобно для передачи и получений значений при работе с функциями.
Тут лучше пример:
vedro-compota
Thu, 02/13/2014 - 14:38
Permalink
В отдельную тему вынес.
В отдельную тему вынес. правильно ли я понимаю, что если попытаться присвоить результат из fun_func() двум переменным. то будет брошена ошибка?
типа:
наверное, это можно сразу как примечание написать там.
_____________
матфак вгу и остальная классика =)
humanmashine
Thu, 02/13/2014 - 15:13
Permalink
Правильно)))
Правильно)))