Я изучаю MapReduce, но у меня возникают некоторые проблемы, вот ситуация: у меня есть два файла: «users» содержит список пользователей с некоторыми их данными (пол, возраст, страна и т. д...) файл выглядит так:
user_000003 m 22 United States Oct 30, 2005
«songs» содержит данные о песнях, прослушанных всеми пользователями (идентификатор пользователя, дата и время прослушивания, идентификатор исполнителя, имя исполнителя, идентификатор песни, название песни):
user_000999 2008-12-11T22:52:33Z b7ffd2af-418f-4be2-bdd1-22f8b48613da Nine Inch Nails 1d1bb32a-5bc6-4b6f-88cc-c043f6c52509 7 Ghosts I
цель состоит в том, чтобы найти k самых популярных песен в определенных странах. с k и списком стран, предоставленным на входе.
Я решил использовать класс MultipleInputs для преобразователя, чтобы один преобразователь выдавал набор пар ключ-значение, который выглядит следующим образом: . другой маппер будет выводить . насколько я знаю, я должен иметь возможность читать все значения в паре с определенным ключом (поэтому я должен найти страну и определенное количество песен в списке значений, связанных с идентификатором пользователя) в редюсере и вывести набор файл с парами, которые будут выделены другим заданием MapReduce.
Я почти уверен, что картографы делают свою работу, так как я смог записать их вывод с помощью редуктора.
ОБНОВЛЕНИЕ: файлы передаются мапперам со следующим кодом:
Job job = Job.getInstance(conf);
MultipleInputs.addInputPath(job, new Path(songsFile), TextInputFormat.class, SongMapper.class);
MultipleInputs.addInputPath(job, new Path(usersFile), TextInputFormat.class, UserMapper.class);
FileOutputFormat.setOutputPath(job, new Path(outFile));
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setJarByClass(Songs.class);
job.setCombinerClass(Combiner.class);
job.setReducerClass(UserSongReducer.class);
Код картографа:
public static class UserMapper extends Mapper<LongWritable, Text, Text, Text>{
//empty cleanUp()
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String record = value.toString();
String[] userData = record.split("\t");
if(userData.length>3 && !userData[3].equals(""))
{
context.write(new Text(userData[0]), new Text(userData[3]));
}
}
//empty run() and setup()
}
public static class SongMapper extends Mapper<LongWritable, Text, Text, Text>{
//empty cleanUp()
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String record = value.toString();
String[] songData = record.split("\t");
if(songData.length>3 && !songData[3].equals(""))
{
context.write(new Text(songData[0]), new Text(songData[5]+" ||| "+songData[3]));
}
}
//empty run() and setup()
}
Код комбайна:
public static class Combiner extends Reducer<Text, Text, Text, Text>
{
private boolean isCountryAllowed(String toCheck, String[] countries)
{
for(int i=0; i<countries.length;i++)
{
if(toCheck.equals(countries[i]))
return true;
}
return false;
}
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException
{
ArrayList<String> list = new ArrayList<String>();
String country = "foo";
for(Text value : values)
{
if(!value.toString().contains(" ||| "))
{
country = value.toString();
}else
{
list.add(value.toString());
}
}
if(isCountryAllowed(country, context.getConfiguration().getStrings("countries")))
{
for (String listVal : list)
{
context.write(new Text(country),
new Text(listVal));
}
}
}
}
Проблемы возникают, когда я пытаюсь вывести пары с редуктором:
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException
{
for (Text value : values)
{
context.write(key,value);
}
}
}
Я использовал « ||| » для создания строки «исполнитель + название», проблема в том, что страна остается «foo». Я думаю, что должен увидеть хотя бы одну строку вывода с правильной нацией в качестве ключа, но вывод всегда "foo" (файл песен 2,5 КБ):
foo Deep Dish ||| Fuck Me Im Famous (Pacha Ibiza)-09-28-2007
foo Vnv Nation ||| Kingdom
foo Les Fleur De Lys ||| Circles
foo Home Video ||| Penguin
foo Of Montreal ||| Will You Come And Fetch Me
foo Godspeed You! Black Emperor ||| Bbf3
foo Alarum ||| Sustained Connection
foo Sneaker Pimps ||| Walking Zero
foo Cecilio And Kapono ||| I Love You
foo Garbage ||| Vow
foo The Brian Setzer Orchestra ||| Gettin' In The Mood
foo Nitin Sawhney ||| Sunset (J-Walk Remix)
foo Nine Inch Nails ||| Heresy
foo Collective Soul ||| Crowded Head
foo Vicarious Bliss ||| Limousine
foo Noisettes ||| Malice In Wonderland
foo Black Rebel Motorcycle Club ||| Lien On Your Dreams
foo Mae ||| Brink Of Disaster
foo Michael Andrews ||| Rosie Darko
foo A Perfect Circle ||| Blue
Что я делаю неправильно?
PS У меня должна быть возможность избежать второго задания, если я использую собственный объединитель, действует ли объединитель точно так же, как редюсер?