Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Data Mining - технологии обработки больших данных. Учебное пособие
.pdf
Напишите MapReduce-задачу, реализующую суммирующий паттерн
!/usr/bin/env python
import sys
from datetime import datetime
for line in sys.stdin:
data = line.strip().split("\t")
if len(data) == 6:
date, time, store, item, cost, payment = data
weekday = datetime.strptime(date, "%Y-%m-%d").weekday()
print "{0}\t{1}".format(weekday, cost)
#!/usr/bin/env python
import sys
from datetime import datetime
import collections
sales_for_each_day_of_the_week = collections.defaultdict(list)
for line in sys.stdin:
data = line.strip().split("\t")
if len(data) == 2:
weekday, sale = data
sales_for_each_day_of_the_week[weekday].append(float(sale))
for weekday in sales_for_each_day_of_the_week:
mean = sum(sales_for_each_day_of_the_week[weekday]) /
len(sales_for_each_day_of_the_week[weekday])
print "{0}\t{1}".format(weekday, mean)
$ gedit ~/.bashrc
cdh4.1.1.jar -mapper $1 -reducer $2 -file $1 -file $2 -input $3 -output $4
cdh4.1.1.jar -mapper $1 -reducer $2 –combiner $2 -file $1 -file $2 -input $3
-output $4
для подсчета среднеарифметического покупок в воскресенье.
День недели можно найти в поле «дата» следующим образом:
добавьте дополнительный импорт в начале:
from datetime import datetime;
для получения рабочего дня вы можете использовать это выражение:
weekday = datetime.strptime(date, "%Y-%m-%d").weekday();
затем используйте рабочий день в качестве выходного ключа. Это
определяется наличием в конце предложения одного из следующих
символов: «!», «?», «.» и «». При этом переносы строк не учитываются.
Реализация Mapper:
Реализация Reducer:
Задача 5. Напишите MapReduce-задачу, реализующую суммирующий
паттерн для подсчета среднеарифметического значения всех покупок,
совершенных в воскресенье, с использованием Combiner и посмотрите
значение reducer input records, перейдя по ссылке в терминале после
выполнения запроса.
Для инициализации Combiner необходимо добавить новую команду
быстрого доступа для виртуальной машины.
Для этого выполним следующие команды в терминале:
В открывшемся файле изменим строку
дописав:
21

После сохраним:
$ source ~/.bashrc
author_id, id, title, tagnames, node_type, parent_id, abs_parent_id,
added_at, score
user_id, "A", reputation, gold, silver, bronze
"12345" "A" "11" "3" "4" "1"
"12345" "B" "6336" "Unit 1: Same Value Q" "cs101 value same" "question"
"\N" "\N" "2012-02-25 08:09:06.787181+00" "1"
#!/usr/bin/env python
import sys
import csv
reader = csv.reader(sys.stdin, delimiter='\t')
for line in reader:
if line[0] == "id" or line[0] == "user_ptr_id":
continue
if len(line) == 5:
user_id, reputation, gold, silver, bronze = line
print "{0}\t{1}\t{2}\t{3}\t{4}\t{5}".format(user_id, "A",
reputation, gold, silver, bronze)
Теперь MapReduce-запрос будет использовать Combiner. Скриншот со
значениями параметров представлен на рис. 2.1.
Рисунок 2.1 - Скриншот со значениями параметров
Задача 6. Объедините два набора данных: сообщения с форума и
пользователей по полю id-автора.
Используемые поля для сообщений с форума:
Используемые поля для пользователей форума:
По своей сути оба файла представляют собой две таблицы реляционной
модели, связанных по полю id-автора.
Для каждой записи требуется сформировать вывод таким образом,
чтобы для сообщений первые два поля были: id-автора и значение “A”; а для
пользователей первые два поля: id-автора и значение “B”. На выходе mapper
должны получить:
Задача reducer заключается в объединении полей и сведению к 1
строке.
Реализация Mapper:
22

else:
id, title, tagnames, author_id, body, node_type, parent_id,
abs_parent_id, added_at, score, state_string, last_edited_id,
last_activity_by_id, last_activity_at, active_revision_id, extra,
extra_ref_id, extra_count, marked = line
print
"{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}".format(author_id, "B",
id, title, tagnames, node_type, parent_id, abs_parent_id, added_at, score)
Реализация Reducer:
#!/usr/bin/env python
import sys
users_attrs = dict()
posts_attrs = dict()
for line in sys.stdin:
data = line.strip().split("\t")
if data[1] == "A":
user_id, type, reputation, gold, silver, bronze = data
users_attrs[user_id] = [reputation, gold, silver, bronze]
elif data[1] == "B":
author_id, type, id, title, tagnames, node_type, parent_id,
abs_parent_id, added_at, score = data
posts_attrs[id] = [id, title, tagnames, author_id, node_type,
parent_id, abs_parent_id, added_at, score]
for post_id in posts_attrs:
id, title, tagnames, author_id, node_type, parent_id, abs_parent_id,
added_at, score = posts_attrs[post_id]
reputation, gold, silver, bronze = users_attrs[author_id]
print
"{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}".form
at(id, title, tagnames, author_id, node_type, parent_id, abs_parent_id,
added_at, score, reputation, gold, silver, bronze)
Задача 7. Придумайте и реализуйте по три запроса на каждый вид паттерна.
Таким образом, в практикуме изучены основные паттерны
проектирования MapReduce, и для каждого из них разработаны программы,
реализующие: фильтрующие паттерны (выборка, random sampling),
суммирующие паттерны (поиск min, max, среднее, стандартное отклонение,
инвертированный индекс), структурные паттерны (объединение двух
наборов данных реляционной модели).
Приобретенные навыки разработки MapReduce задач позволяют
разрабатывать эффективные программы для обработки больших данных,
реализуя фильтрацию данных, подсчет статистических значений.
Практикум 2.2. Интеллектуальный анализ данных с форума Udacity
Цель: провести интеллектуальный анализ больших данных с
применением полученных знаний написания MapReduce-запросов для
выполнения заданий, направленных на получение информации о
подготовленном наборе данных.
Задачи
1. Найти для каждого студента час, в течение которого он разместил
наибольшее количество сообщений.
2. Узнать, существует ли корреляция между длиной поста и длиной ответов.
3. Получить список популярных тегов, которые используются в сообщениях.
23

4. Сформировать учебные группы. Первоначально следует проанализировать,
author_id hour
13431511\t13
54525254141\t21
#!/usr/bin/env python
import sys
import csv
from datetime import datetime
from time import strftime
reader = csv.reader(sys.stdin, delimiter='\t')
for line in reader:
if line[0] == "id":
continue
print "{0}\t{1}".format(line[3], int(line[8].split('
')[1].split(':')[0]))
есть ли студенты на форумах, которые много общаются между собой.
5. Придумайте и реализуйте три новых запроса, реализующих
корреляционные зависимости.
Ход выполнения
В практикуме рассматривается набор с данными дискуссионного
форума, состоящий из двух файлов:
"forum_nodes.tsv" содержит все вопросы и ответы форума в одной
таблице. Файл состоит из следующих полей:
"id": id записи форума;
"title": заголовок записи. Если "node_type" является "answer" или
"comment", это поле остается пустым;
"tagnames": разделенные пробелом теги записи;
"author_id": id автора;
"body": содержание записи;
"node_type": тип записи, одно из: "question", "answer" или
"comment";
"parent_id": id родительской записи, останется пустым для
"node_type" – "questions";
"abs_parent_id": id главной записи;
"added_at": дата создания.
"forum_users.tsv" содержит поля:
"user_ptr_id" - идентификатор пользователя,
"reputation" – репутация пользователя,
количество заработанных "gold", "silver" и "bronze" бейджей.
Задача 1. Время студентов на форуме
Найдите для каждого студента час, в течение которого студент
разместил наибольшее количество сообщений. На выходе из MapReduce
должно быть:
Таким образом, сначала требуется вывести для каждого пользователя
список его публикаций и время создания публикации в map, а уже после с
помощью reduce подсчитать, в какое время совершено больше всего
публикаций.
Реализация Mapper.py:
24

Реализация Reducer.py:
#!/usr/bin/env python
import sys
count_hour = [0] * 24
id = None
for line in sys.stdin:
data = line.strip().split("\t")
if len(data) != 2:
continue
author_id, hour = data
if id and author_id != id:
print("{0}\t{1}".format(id, count_hour.index(max(count_hour))))
id = author_id
count_hour = [0] * 24
count_hour[int(hour)] += 1
continue
count_hour[int(hour)] += 1
id = author_id
print("{0}\t{1}".format(id, count_hour.index(max(count_hour))))
#!/usr/bin/env python
import sys
import csv
reader = csv.reader(sys.stdin, delimiter='\t')
for line in reader:
if line[0] == "id":
continue
if (line[5] == 'question'):
print "{0}\t{1}\t{2}".format(line[0], int(0), len(line[4]))
if (line[5] == 'answer'):
print "{0}\t{1}\t{2}".format(line[6], int(1), len(line[4]))
#!/usr/bin/env python
import sys
count_ = 0
len_ = 0
alen_ = 0
post_ = None
is_quest = 0
for line in sys.stdin:
data = line.strip().split("\t")
if len(data) != 3:
Результат запроса представлен на рис. 2.2.
Рисунок 2.2 - Результат запроса
Задача 2. Корреляция между длиной записи и ответами
Требуется реализовать программу MapReduce, которая будет
обрабатывать данные forum_node и выводить длину записи и среднюю длину
ответа (просто ответ, а не комментарий) для каждой записи.
Реализация Mapper.py:
Реализация Reducer.py:
25

continue
id_post, is_quest, len_post = data
if post_ and id_post != post_:
if count_ == 0:
print("{0}\t{1}\t{2}".format(post_, len_, 0))
else:
print("{0}\t{1}\t{2}".format(post_, len_, alen_ / count_))
count_ = 0
alen_ = 0
len_ = 0
if int(is_quest) == 0:
len_ = int(len_post)
else:
count_ += 1
alen_ += float(len_post)
post_ = id_post
if count_ == 0:
print("{0}\t{1}\t{2}".format(post_, len_, 0))
else:
print("{0}\t{1}\t{2}".format(post_, len_, alen_ / count_))
Результат запроса представлен на рис. 2.3.
#!/usr/bin/env python
import sys
import csv
reader = csv.reader(sys.stdin, delimiter='\t')
for line in reader:
if line[0] == "id":
continue
data = line[2].split(' ')
if len(data) == 1 and data[1] == '':
print "{0}\t{1}".format(data[0], int(1))
else:
for tag in data:
print "{0}\t{1}".format(tag, int(1))
#!/usr/bin/env python
import sys
values = [0] * 10
keys = [None for i in range(10)]
count_ = 0
tag_ = None
for line in sys.stdin:
Рисунок 2.3 - Результат запроса
Задача 3. Топ-10 тегов
Требуется реализовать программу MapReduce, которая выведет 10
лучших тегов, упорядоченных по количеству вопросов, в которых они
появляются. С помощью map выведите список всех тегов, а посредством
реализации reducer подсчитайте 10 наиболее часто встречаемых.
Реализация Mapper.py:
Реализация Reducer.py:
26

data = line.strip().split("\t")
if len(data) != 2:
continue
tag, cnt = data
if tag_ and tag != tag_:
if min(values) < count_:
key = values.index(min(values))
values[key] = count_
keys[key] = tag_
tag_ = tag
count_ = 1
continue
count_ = 0
count_ += 1
tag_ = tag
if min(values) < count_:
key = values.index(min(values))
values[key] = count_
keys[key] = tag_
new_list = [list(x) for x in zip(*sorted(zip(values, keys), reverse=True,
key=lambda pair: pair[0]))]
for i in range(10):
print("{0}\t{1}".format(new_list[1][i],new_list[0][i]))
Результат запроса представлен на рис. 2.4.
if (line[5] == 'question'):
Рисунок 2.4 - Результат запроса
Для реализации поиска топ-10 тегов по типу записи, необходимо в
mapper.py изменить код, добавив проверку условия на тип записи. Для
вопросов (“question”) необходимо добавить следующую строчку кода перед
проверкой на количество тегов в list:
Результат запроса представлен на рис. 2.5.
форума (это запись со его ответами и комментариями) даст нам список
студентов, которые что-либо разместили на форуме. Если студент несколько
раз публиковался в этом дереве, его также следует добавить в этот список
несколько раз, чтобы указать интенсивность общения. Таким образом, на
выходе получим id ветки (записи), под которой оставляют вопросы и
Задача 4. Группы студентов на форуме
Требуется написать программу MapReduce, которая для каждого дерева
Рисунок 2.5 - Результат запроса
27

комментарии студенты, а также соответствующий список студентов, которые
#!/usr/bin/env python
import sys
import csv
reader = csv.reader(sys.stdin, delimiter='\t')
for line in reader:
if line[0] == "id":
continue
if (line[5] == 'question'):
print "{0}\t{1}".format(line[0], line[3])
else:
print "{0}\t{1}".format(line[6], line[3])
#!/usr/bin/env python
import sys
students = list()
id_ = None
for line in sys.stdin:
data = line.strip().split("\t")
if len(data) != 2:
continue
id, author_id = data
if id_ and id != id_:
print("{0}\t{1}".format(id_, students))
id_ = id
students = list()
students.append(author_id)
continue
students.append(author_id)
id_ = id
print("{0}\t{1}".format(id_, students))
как раз и отметились под данной веткой, то есть задали вопрос и/или
оставили свой комментарий.
Реализация Mapper.py:
Реализация Reducer.py:
Результат запроса представлен на рис. 2.6.
Рисунок 2.6 – Результат запроса
корреляционные зависимости.
поиску корреляций, на основе паттернов, в частности: наиболее частое время
присутствия пользователя на форуме; соотношение длины вопроса и средней
длины ответов; топ-10 тегов по всему форуму и по разделу «вопросы»; поиск
студенческих групп по веткам форума.
Задача 5. Придумайте и реализуйте три новых запроса, реализующих
Таким образом, в практикуме реализованы MapReduce запросы по
28

Глава 3. Cloudera QuickStart VM
Практикумы в этой главе выполняются в виртуальной машине от
Cloudera, где установлен и настроен Apache Hadoop. Платформа от Cloudera
(CDH) позволяет сразу «из коробки» проводить операции с данными. В
виртуальной машине имеется краткое руководство пользователя и
предварительно подготовленные данные. Изучение происходит на примере
абстрактного интернет-магазина спортивных товаров. Данными служат
информация о продажах товаров и логи веб-сервера магазина (информация о
товарах, которые чаще всего ищут, которые чаще всего покупают,
информация о состоявшихся и не состоявшихся покупках).
Apache Sqoop – инструмент, который очень эффективно использует
MapReduce для переноса данных между кластерами Hadoop и реляционными
базами данных. В платформу Cloudera включены две версии Sqoop. Sqoop 1 -
это толстый клиент, который используется в этой работе. Sqoop 2 состоит из
центрального сервера, который отправляет задания MapReduce от имени
клиентов и является легким клиентом. В Cloudera Manager работает сервер
Sqoop 2.
Команда Sqoop «по импорту» запускает задания MapReduce для
экспорта данных из БД MySQL и импорту в HDFS. Одновременно она
создает таблицы для представления файлов HDFS в Impala Apache с
соответствующей схемой. Parquet - это формат, предназначенный для
аналитических приложений на Hadoop. Вместо группировки данных в
строки, они группируются в столбцы. Это идеально подходит для многих
аналитических запросов, где вместо извлечения данных из конкретных
записей анализируются отношения между конкретными переменными во
многих записях.
С помощью Apache Sqoop можно произвести загрузку данных в
файловую систему HDFS. При выполнении в терминале будут показаны
файлы . parquet, количество которых равно числу карт, используемых Sqoop.
Hive и Impala также позволяют создавать таблицы, определяя схему поверх
существующих файлов с помощью операторов CREATE EXTERNAL
TABLE, аналогичных традиционным БД. Sqoop создаёт эти таблицы
автоматически при импорте данных.
Hadoop может хранить неструктурированные и структурированные
данные, в том числе получать, хранить и обрабатывать веб-журнал событий.
На основе данных о веб-посещениях можно выяснить, что посетители сайта
просматривали чаще всего. Самый распространенный способ отслеживать
переходы по сайту - использование Apache Flume.
Flume представляет собой масштабируемый инструмент, который в
режиме реального времени позволяет отслеживать маршруты, фильтровать,
объединять и производить “мини-операции” на пути данных. Flume
используется совместно с библиотекой ETL Morphlines. Средства ETL
(Extract, Transform, Load) обеспечивают возможность сложных
преобразований и большей части технологического процесса преобразования
29

и очистки данных. Cloudera Morphlines – новая среда с открытым исходным
кодом, сокращает время и усилия, необходимые для интеграции, сборки и
изменения приложений обработки Hadoop. Она обеспечивает извлечение,
преобразование и загрузку данных в Apache Solr, Apache HBase, HDFS,
позволяя построить или облегчить обработку потоков без программирования
и без существенных навыков работы с MapReduce.
Для поиска взаимосвязей (корреляций) используется служба Spark.
Spark применяет операции, аналогичные map и reduce (операции join и
groupBy просто вариации reduce). Ключевое преимущество Spark - код
занимает меньше места, и промежуточные результаты могут храниться в
памяти, что позволяет проводить итерации намного быстрее.
Мы будем использовать Spark-on-YARN т.е. MapReduce и Spark,
которые (как и многие компоненты CDH) имеют общий менеджер ресурсов,
что облегчает распределение ресурсов среди большого числа пользователей.
Средствами, встроенными в CDH, можно индексировать данные в
реальном времени при помощи расширения конфигурации Apache Flume.
При этом необходимо выбрать пакетную индексацию данных с помощью
инструмента MapReduce Indexing или использовать Apache Solr.
Solr организует данные веб-журнала подобно реляционной модели.
Каждая запись называется документом и состоит из полей, определенных
схемой, аналогично строке в таблице базы данных. Разница в том, что
данные в Solr, как правило, более слабо структурированы. Начать
индексацию в режиме реального времени с помощью Cloudera Search and
Flume над данными журнала веб-сервера и использовать пользовательский
интерфейс поиска в Hue для его изучения можно путем создания индекса
поиска.
Применение Hadoop с MapReduce, Spark, Pig и Hive практически не
требует глубокого знания программирования. Используя современные
инструментальные средства, можно выполнить анализ и прогнозирование, а
также использовать визуализацию для моделирования проблем, что
существенно ускоряет и облегчает работу с большими данными.
Практикум 3.1. Взаимодействия и реляционные данные запроса
Цель: познакомиться с новыми инструментами виртуальной машиной
Cloudera QuickStart VM.
Задачи
1. Установить виртуальную машину «Cloudera QuickStart VM».
2. Используя Apache Sqoop, импортировать данные из MySQL в HDFS.
3. Произвести обновление метаданных.
4. Вывести десять самых популярных категорий товаров.
5. Вывести десять ведущих производителей товаров.
6. Придумать три собственных задачи с использованием объединения
таблиц.
30
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
