Недавно я нашел интересный набор данных под названием Million Song Dataset (MSD), который содержит подробные акустические и контекстные данные о миллионе песен. Для каждой песни мы можем найти информацию, такую как название, жаркость, темп, продолжительность, танцевальность, громкость, а также имя исполнителя, популярность, локализация (пара широты и долготы) и многое другое. Здесь нет музыкальных файлов, но ссылки на превью песен в формате MP3 на 7digital.com могут быть легко построены на основе данных.
Набор данных состоит из 339 текстовых файлов, разделенных табуляцией. Каждый файл содержит около 3000 песен, и каждая песня представлена в виде отдельной строки текста. Набор данных общедоступен, и вы можете найти его на Infochimps или Amazon S3 . Поскольку общий размер этих данных составляет около 218 ГБ, обработка их на одной машине может занять очень много времени.
Определенно, гораздо более интересный и эффективный подход состоит в том, чтобы использовать несколько машин и обрабатывать песни параллельно, используя преимущества инструментов с открытым исходным кодом из экосистемы Apache Hadoop (например, Apache Pig ). Если у вас есть несколько собственных машин, вы можете просто использовать CDH (дистрибутив Cloudera, включая Apache Hadoop), который включает в себя полный стек Apache Hadoop. CDH можно установить вручную (быстро и легко, набрав пару простых команд) или даже автоматически с помощью Cloudera Manager Free Edition. CDH и Cloudera Manager можно бесплатно загрузить с веб-сайта Cloudera . Кроме того, вы можете арендовать некоторые машины у Amazon с уже установленным Hadoop и обрабатывать данные с помощью Amazon Elastic MapReduce.(вот классное описание, написанное Полом Лемером, как его использовать и заплатить всего за 1 доллар, и вот моя презентация об Elastic MapReduce, представленная на 2-м собрании варшавской группы пользователей Hadoop ).
Определение проблемы
Мне пришла в голову идея обработать этот набор данных, чтобы найти «экзотические» (но все еще популярные) песни. Под экзотическими песнями я имею в виду песню, записанную артистом, живущим в какой-то зарубежной стране, вдали от других артистов. Общая цель — найти пару необычных и народных песен, связанных с культурой какой-либо страны. Забавным примером может служить песня Jarzębina «Koko Koko Euro Spoko» , которую поляки выбрали в качестве официальной песни сборной Польши по футболу во время UEFA EURO 2012;)
Apache Pig
Я использовал Apache Pig для достижения этой цели. Apache Pig — это удобный инструмент, созданный в Yahoo! анализировать большие наборы данных легко и эффективно. Apache Pig обеспечивает высокий уровень и простой в изучении, понимании и поддержке язык программирования потоков данных, называемый PigLatin. PigLatin очень похож на языки сценариев, он поддерживает множество полезных операций, таких как фильтрация, сортировка, агрегация, объединение, разбиение, и предоставляет несколько сложных типов данных (кортежи, пакеты и карты). Примерный сценарий PigLatin в 20 раз короче, чем его эквивалент в Java MapReduce, и на его реализацию у программиста уходит в 16 раз меньше времени ( подробнее ), в то же время он лишь немного медленнее, чем Java MapReduce (см. Тест PigMix2).). Благодаря этим преимуществам Apache Pig часто используется многими признанными компаниями и организациями, например, Yahoo! (в настоящее время около 90% рабочих мест Hadoop написаны на PigLatin), Twitter, Nokia Ovi Maps, AOL, Mendeley, LinkedIn и ICM UW .
PigLatin скрипт
Чтобы найти такие популярные народные и местные песни, я реализовал простой скрипт PigLatin (около 50 строк кода PigLatin). Этот сценарий использует немного наивную, но довольно эффективную идею и пытается найти «изолированные» песни. Изолированная песня — это просто песня, в которой среднее расстояние между локализацией артиста и любыми другими артистами настолько мало, насколько это возможно (точнее, я должен сказать, что изолированная песня — это песня, записанная изолированным артистом). Такой подход дает нам гораздо большую вероятность обнаружить «привлекательные» песни из Конго, Мали, Польши и Вьетнама, чем из США или Великобритании.
Как уже упоминалось, набор данных содержит информацию о локализации художников в виде пар lat / long, и, к счастью, есть библиотека с открытым исходным кодом DataFu (созданная LinkedIn), которая предоставляет, например, PigLatin UDF для вычисления расстояния между двумя парами lat / long с использованием формулы Хаверсайна. ,
Просто в нескольких словах. Я читаю входные данные и отфильтровываю непопулярные песни или песни без лат / долгой локализации (отношение
отфильтрованный
Другой
дистанцировался
AvgDistanced
Популярный
Ограниченное
Displable
Вот исходный код:
SET default_parallel $parallel SET pig.tmpfilecompression true SET pig.tmpfilecompression.codec lzo SET pig.maxCombinedSplitSize 134217728 REGISTER '/usr/lib/pig-0.10.0/contrib/datafu-0.0.4/dist/datafu-0.0.4.jar'; DEFINE haversineMiles datafu.pig.geo.HaversineDistInMiles(); Songs = LOAD '$input'; --"Project early and often" Projected = FOREACH Songs GENERATE (double) $6 AS artistLat, (double) $8 AS artistLong, $12 AS artistName, (double) $43 AS songHotness, $51 AS songTitle, (int) $52 AS songPreview; --"Filter early and often" Filtered = FILTER Projected BY (songHotness >= $hotness) AND (artistLat IS NOT NULL) AND (artistLong IS NOT NULL); --"Copy useful fields from Popluar relation" Filtered2 = FOREACH Filtered GENERATE songPreview as song2Preview, artistLat AS artist2Lat, artistLong AS artist2Long; --"Produce all pairs of different songs and calculate distance between localizations of their artists" Crossed = CROSS Filtered, Filtered2; Different = FILTER Crossed BY songPreview != song2Preview; Distanced = FOREACH Different GENERATE artistLat..songPreview, haversineMiles(artistLat, artistLong, artist2Lat, artist2Long) as distance; --"For each song, calculate average distance between its artists and all other artists" Grouped = GROUP Distanced BY artistLat..songPreview; AvgDistanced = FOREACH Grouped { Distances = Distanced.distance; GENERATE FLATTEN(group), AVG(Distances) AS distanceAvg; } --"Find the most popular song for a given location" Locationed = GROUP AvgDistanced BY (artistLat, artistLong); Popular = FOREACH Locationed { OrderedSongs = ORDER AvgDistanced BY songHotness DESC; TopSong = LIMIT OrderedSongs 1; GENERATE FLATTEN(TopSong); } --"Find the most isolated songs which were recored by artists who live far away from other artists" Ordered = ORDER Popular BY distanceAvg DESC; Limited = LIMIT Ordered $topCount; --"Generate results in such a format that can be easily displayed by Google Maps (by copy & paste)" Displayed = FOREACH Limited GENERATE CONCAT('[', (chararray) artistLat), artistLong, songPreview, CONCAT('"', CONCAT((chararray) songTitle, '"')), CONCAT('"', CONCAT((chararray) artistName, '"')), songHotness, CONCAT((chararray)distanceAvg, '],'); STORE Displayed INTO '$output' USING PigStorage(',');
Запуск скрипта PigLatin
Я использую Apache Pig 0.10.0 (новейшая версия Apache Pig на момент написания этой статьи). Вы можете прочитать о новых возможностях в Pig 0.10.0 здесь .
Мой сценарий принимает пять параметров, то есть пути ввода и вывода, порог жаркости песни (число с плавающей запятой между 0,0 и 1,0), количество выходных песен и уровень параллелизма по умолчанию.
time /usr/lib/pig-0.10.0/bin/pig -p input=input/million-song -p hotness=0.5 -p topCount=200 -p parallel=100 -p output=output/million-song/all.5.200.100 exotic-songs.pig
Pig запускает этот скрипт как последовательность из семи заданий MapReduce. Общее время выполнения этого скрипта составило 40 млн. 47,758 с. Я оптимизировал этот сценарий, увеличив объем памяти, доступной для дочерних задач, комбинируя небольшие входные файлы, сжимая выходные данные задач карты и выходные промежуточные задания, используя сжатие LZO. Я также отключил умозрительное выполнение как для карты, так и для задач сокращения. Обратите внимание, что в то время в кластере Hadoop не выполнялось никаких других заданий.
Я запустил этот скрипт на кластере Hadoop, который принадлежит ICM UW, Я использовал три «толстых» подчиненных узла и виртуальную машину на отдельной машине в роли HDFS NameNode и Hadoop JobTracker. Каждый рабочий узел имеет четыре процессора AMD Opteron 6174 (всего 48 ядер), 192 ГБ ОЗУ и может хранить 7 ТБ данных. Для этого сценария Pig я настроил на каждом рабочем узле 45 карт и 35 максимально сокращенных задач (итого я могу запустить 135 карт и 105 параллельных задач). Я понимаю, что это не типичная конфигурация Hadoop (определенно, это не стандартное оборудование), но я просто использую то, что у меня есть. В настоящее время здесь установлен CDH3u3, который включает Hadoop 0.20.2, Pig 0.8.1 по умолчанию. Я установил Pig 0.10.0 вручную на своем клиентском компьютере и использовал его для передачи заданий в этот кластер.
Будущие оптимизации
Читаемость и производительность этого скрипта могут быть улучшены за счет реализации собственных пользовательских функций (UDF), например, многотекстовой конкатенации, настройки некоторых параметров MapReduce и Pig (например,
pig.maxCombinedSplitSize
ПАРАЛЛЕЛЬНО
Поскольку я не хочу делать этот пост долгим, эффекты рефакторизации и оптимизации будут подробно описаны в моих следующих постах. Я хотел бы написать пару постов, посвященных разработке и оптимизации сценариев PigLatin на основе этого примера и набора данных песни milion. Я хотел бы упомянуть, какие инструменты и библиотеки Pig можно использовать, показать некоторые тесты и т. Д.
Результат, чтобы увидеть
Результаты можно визуализировать, используя JavaScipt с GoogleMaps. На приведенной ниже карте показано 200 песен, и для каждой песни я поместил кликабельный маркер в локализацию лота / лонга его исполнителя, который отображает основную информацию об этой песне и ссылку на ее предварительный просмотр.
Результат для прослушивания
Вот несколько песен, которые привлекли мое внимание:
- Cler Achel от Tinariwen (Мали) (жаркость: 0,6590)
- Yolele от Papa Wemba (Демократическая Республика Конго) (жаркость: 0,6103)
- Smooth Operator от Sade (Нигерия) (жаркость: 0.9458)
- Cherry Town от Трилока Гурту (Индия) (жаркость: 0,6192)
- Pandi panda от Chantal Goya (Вьетнам) (жаркость: 0.5952)
- La Camisa Negra от Juanes (Колумбия) (жаркость: 0,8290)
- Электрический проспект Эдди Гранта (Гайана) (жара: 0,8206)
- Todo se transma от Хорхе Дрекслер (Уругвай) (жаркость: 0.7946)
- Abusadora от Wilfrido Vargas (Бразилия) (жаркость: 0,6773)
- Laura non c’è от Nek (Италия) (жаркость: 0,7786)
- Брацка от Гжегожа Турнау (Польша) (жара: 0,7332) — посвящена моей Наталье и нашей полу-собаке-полу-кролику Тофи
Африка
Азия
Южная Америка
Европа
Если вы найдете более интересные примеры, просто дайте мне знать или просто поместите их в комментариях ниже. Я понимаю, что мой музыкальный вкус может быть сомнительным;)
Особая благодарность
Поскольку все мои вычисления были выполнены на кластере Hadoop, который принадлежит ICM UW , я хотел бы поблагодарить персонал ICM за возможность использовать кластер.