Статьи

Уменьшить карту — насколько это круто?

Время от времени я слышу несколько упоминаний о MapReduce; до недавнего времени я избегал смотреть на это. CACM этого месяца , однако, переполнен совершенством MapReduce. Прочитав некоторые статьи, я решил немного более внимательно изучить этот подход к обработке больших наборов данных.

Реализация Python

Map-Reduce — приятный функциональный подход к решению нескольких тесно связанных проблем.

  • Параллелизм.
  • Фильтрация и исключение.
  • Преобразуя.
  • Подводя итоги.

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

Map-Reduce на дешевые

Основы уменьшения карты можно сделать несколькими способами в Python. Мы могли бы использовать встроенную карту и уменьшить функции. Это может привести к проблемам, если вы предоставите плохо разработанную функцию для уменьшения.

Но Python также предоставляет функции генератора. См. PEP 255 для справки об этом. Функция генератора позволяет легко реализовать простую обработку стилей сокращения карт на одном хосте.

Вот простой синтаксический анализатор веб-журнала, построенный в стиле карты с некоторыми функциями генератора.

Вот операция на высшем уровне. Это не слишком интересно, потому что оно просто выбирает поле и сообщает о нем. Дело в том, что он восхитительно прост и сфокусирован на поставленной задаче, без беспорядка.

def dump_log( log_source ):
 for entry in log_source:
     print entry[3]

Конечно, мы можем улучшить это, сделав еще больше вычислений, фильтрации и даже сокращения. Однако давайте не будем загромождать этот пример слишком большим количеством.

Вот функция карты, которая может выполнять роль log_source . Учитывая источник строк, это определит, являются ли они анализируемыми записями журнала, и выдаст синтаксический анализ как 9-кортеж. Это сопоставляет строки с 9-ю кортежами, отфильтровывая все, что не может быть проанализировано.

log_row_pat= re.compile( r'(\d+\.\d+\.\d+\.\d+) (\S+?) (\S+?) (\[[^\]]+?]) ("[^"]*?") (\S+?) (\S+?) ("[^"]*?") ("[^"]*?")' )
def log_from_rows( row_source ):
 for row in row_source:
     m= log_row_pat.match( row )
     if m is not None:
         yield m.groups()

Этот источник журналов имеет один бит нечистого функционального программирования Аккуратная, чисто функциональная альтернатива сохранению объекта сопоставления m , кажется, не стоит дополнительных строк кода.

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

def rows_from_name( name_source ):
 for aFileName in name_source:
     logger.info( aFileName )
      with open(aFileName,"r") as source:
           for row in source:
                yield row

Вот отображение из корня каталога в последовательность имен файлов в структуре каталога.

def names_( root='/etc/httpd/logs' ):
for path, dirs, files in os.walk( root ):
   for f in files:
       logging.debug( f )
       if f.startswith('access_log'):
           yield os.path.join(path,f)

Это применяет простой фильтр имен. Мы могли бы использовать Python fnmatch, который дал бы нам немного более расширяемую структуру.

Положить его вместе

Это лучшая часть этого стиля функционального программирования. Это просто соединяется с простыми правилами композиции.

logging.basicConfig( stream=sys.stderr, level=logging.INFO )
dump_log( log_from_rows( rows_from_name( names_from_dir() ) ) )
logging.shutdown()

Мы можем просто определить функции карты. Наша цель, выраженная в dump_log , является главой композиции. Это зависит от хвоста, который анализирует, читает файл и находит все файлы в каталоге.

Каждый шаг конвейера карты представляет собой приятную композицию.

Конвейеры

Этот стиль программирования может быть легко разложен для работы через конвейеры в стиле Unix.

Мы можем вырезать последовательность сокращения карты где угодно. Голова композиции получит данные из операции расщепления вместо исходного хвоста.

Оригинальный хвост композиции будет использоваться новой головой, которая травит результаты. Затем эту новую главу можно поместить в источник конвейера в стиле Unix.

параллелизм

Есть два уровня параллелизма, доступных в этом виде уменьшения карты. По умолчанию в одном процессе мы не получаем ни того, ни другого.

Однако, если мы разделим шаги на отдельные физические процессы, мы получим огромное преимущество в производительности. Мы заставляем операционную планировать. И у нас есть процессы, которые имеют много ресурсов для них.

[Люди любят скручивать руки над «тяжелой» обработкой против потоков. Практически это редко имеет значение. Создавайте процессы, пока вы не докажете, что они неэффективны.]

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

Пока вы не нуждаетесь в фреймворке, вы можете начать сокращать карты уже сегодня.

Ссылка: http://hadoop.apache.org/mapreduce/

С http://slott-softwarearchitect.blogspot.com