MapReduce программирование - PullRequest
2 голосов
/ 17 мая 2011

Я сделал этот код на Java, который собирает различную информацию о фотографиях и извлекает результаты в текстовый файл.Я хотел бы преобразовать эту программу для работы с моделью MapReduce.Я новичок в программировании MapReduce.Любая помощь будет очень ценится!Спасибо

import java.io.*;
import java.util.*;
import java.net.*;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.aetrion.flickr.people.User;
import com.aetrion.flickr.photos.Photo;
import com.aetrion.flickr.photos.PhotoList;
import com.aetrion.flickr.photos.PhotosInterface;
import com.aetrion.flickr.photos.SearchParameters;
import com.aetrion.flickr.photosets.PhotosetsInterface;
import com.aetrion.flickr.test.TestInterface;
import com.aetrion.flickr.people.PeopleInterface;
import com.aetrion.flickr.groups.*;
import com.aetrion.flickr.groups.pools.*;


import com.aetrion.flickr.*;

public class example2{

public example2() {



}

/**
* @param args
* @throws FlickrException
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/

@SuppressWarnings("deprecation")
public static void main(String[] args) throws IOException, SAXException, FlickrException, ParserConfigurationException { // TODO Auto-generated method stub

FileWriter out = new FileWriter("photos.txt");

//Set api key
String key="apikey";
String svr="www.flickr.com";
REST rest=new REST();
rest.setHost(svr);

//initialize Flickr object with key and rest
Flickr flickr=new Flickr(key,rest);
Flickr.debugStream=false;

//initialize SearchParameter object, this object stores the search keyword
SearchParameters searchParams=new SearchParameters();
searchParams.setSort(SearchParameters.INTERESTINGNESS_DESC);
searchParams.setGroupId("group_id");

//Initialize PhotosInterface object
PhotosInterface photosInterface=flickr.getPhotosInterface();
//Execute search with entered tags
PhotoList photoList=photosInterface.search(searchParams,500,1);

if(photoList!=null){
//Get search result and check the size of photo result
for(int i=0;i<photoList.size();i++){
//get photo object
Photo photo=(Photo)photoList.get(i);

System.out.print(photo.getId()+"\t");
out.write(photo.getId()+"\t");

System.out.print(photo.getOwner().getId()+"\t");
out.write(photo.getOwner().getId()+"\t");

Photo photo1=photosInterface.getPhoto(photo.getId());


if(photo1.getGeoData() != null ){
System.out.print("latitute="+photo1.getGeoData().getLatitude()+"\t");
out.write(photo1.getGeoData().getLatitude()+"\t");

System.out.print("longitude="+photo1.getGeoData().getLongitude()+"\t");
out.write(photo1.getGeoData().getLongitude()+"\t");
}
else {System.out.print(photo1.getGeoData()+"\t");
out.write(photo1.getGeoData()+"\t\t"+photo1.getGeoData());}
System.out.println("");
out.write("\n");



}
out.close();
}
}}

Ответы [ 2 ]

1 голос
/ 17 мая 2011

Я не уверен, что это хороший вариант использования Hadoop, если только у вас нет тонн результатов поиска для обработки, и на обработку приходится значительная часть всей программы. Сам поиск не может быть выполнен параллельно: только обработка в вашем цикле for.

Если вы хотите обработать один поиск параллельно в Hadoop, вам сначала нужно будет выполнить поиск вне Hadoop ** и вывести результаты в текстовый файл - например, список идентификаторов. , Затем напишите маппер, который берет ID, выбирает фотографию и выполняет обработку, которую вы в данный момент выполняете в цикле for, испуская строку с вашими выбранными атрибутами (которую вы сейчас печатаете в System.out). Hadoop будет запускать этот маппер индивидуально для каждого идентификатора в вашем списке результатов.

Я не думаю, что это будет стоить того, если вы не планируете какую-то другую обработку. Некоторые альтернативы для рассмотрения:

  • Используйте map-reduction для параллельного выполнения множества различных поисков. Ваша программа практически не изменится - она ​​будет работать внутри функции карты вместо цикла main (). Или ваш поиск может происходить в маппере с выдачей результатов, а ваша обработка может происходить в редукторе. Ваш ввод будет список поисковых терминов.

  • Забудьте об уменьшении карты и просто запустите обработку параллельно, используя пул потоков. Проверьте различные Executors в java.util.concurrent.


** Альтернативный, хакерский способ заставить все это работать "внутри" Hadoop - запустить поиск внутри функции карты, выдавая результаты один за другим. Используйте входной файл с одной строкой текста - фиктивным значением, чтобы ваш маппер запускался только один раз. Затем выполните выборку изображений в редукторе вместо картографа.


Обновление

Если у вас есть куча разных идентификаторов групп для поиска, тогда вы можете использовать первый «альтернативный» подход.

Как вы и предлагали, используйте идентификаторы групп и ключи API в качестве ввода. Поместите по одному в каждой строке, разделенные вкладкой или что-то, что вы можете легко разобрать. Вам также придется разделить их на разные файлы, если вы хотите, чтобы они запускались в разных мапперах. Если у вас столько идентификаторов групп, сколько узлов, вы, вероятно, просто захотите поместить одну строку в каждый файл. Используйте TextInputFormat для своей работы в Hadoop. Строка с идентификатором группы и ключом API будет иметь значение - используйте value.toString().split("\t"), чтобы разделить ее на две части.

Затем запустите весь поиск внутри картографа. Для каждого результата используйте context.write(key, value) (или output.collect(key, value), в зависимости от вашей версии), чтобы написать идентификатор фотографии в качестве ключа и строку с вашими атрибутами в качестве значения. Оба из них должны быть преобразованы в Text объекты Hadoop.

Я не собираюсь давать оптовый код для этого - должно быть очень легко просто адаптировать учебник Hadoop MapReduce . Единственные реальные отличия:

  • Используйте job.setOutputValueClass(Text) и измените, где написано IntWritable в подпись класса картографа:

    public static class Map
        extends Mapper<LongWritable, Text, Text, Text> {
    
  • Просто отключите редуктор. Выньте класс редуктора и измените его:

    job.setMapperClass(Map.class);
    job.setCombinerClass(Reduce.class);
    job.setReducerClass(Reduce.class);
    

    в это:

    job.setMapperClass(Map.class);
    job.setNumReduceTasks(0);
    

Если у вас есть конкретные вопросы о том, как заставить это работать, не стесняйтесь спрашивать. Впрочем, сначала приложите усилия для исследования.

0 голосов
/ 17 мая 2011

Я не согласен с ответом Тима Йейтса. Ваш поиск может быть очень хорошо парализован. Мой подход будет следующим:

  1. Реализуйте Mapper, который будет принимать часть ваших поисковых запросов в качестве входных данных (вы должны разделить их на части для себя, потому что эти вещи не являются последовательными файлами), затем выполнить запрос и записать результат в файловую систему. Ключом будет ID, а Value будет вашей дополнительной информацией.
  2. Реализация сокращения, которое делает все, что вы хотите с данными (вывод первого шага).

Я уже сделал это с помощью API YouTube, поэтому он работает хорошо, парализовано. НО вы должны остерегаться ограничения квоты. Вы можете справиться с ними с Thread.sleep(PERIOD_OF_TIME) довольно хорошо. Это применимо только в том случае, если у вас есть несколько поисковых запросов, если у вас есть пользователь, который введет строку поиска, MapReduce не является (оптимальным) способом.

...