Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Data Mining - технологии обработки больших данных. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
Напишите 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