2016-12-07 4 views
1

У меня есть небольшой проект, который я делаю в mapreduce, и так как я новичок в этом, я сталкиваюсь с множеством трудностей, поэтому приветствую помощь. в этом prjoect у меня есть файл, который содержит сайт и тег (есть 10 тегов на сайт). Я хочу найти для каждого сайта simmilar сайты по общим тегам. так, например, из 3-х сайтов это мой набор данныхMapreduce значения цепочки в список для каждого ключа

site1 tag1 
site1 tag2 
site1 tag3 
site1 tag4 
site1 tag5 
site2 tag1 
site2 tag2 
site2 tag3 
site2 tag11 
site2 tag12 
site3 tag1 
site3 tag11 
site3 tag13 
site3 tag14 
site3 tag15 

(я сделал только 5 для каждого сайта для данного примера). что я пытаюсь сделать, это сделать mapreduce, что ключ будет тегом и значением сайта. я хочу для каждого тега, чтобы получить список (или массив или любой другой) сайтов, которые имеют этот тег поэтому в данном примере:

tag1: site1, site2, site3 
tag2: site1,site2 
tag3: site1, site2 
tag4: site1 

и так далее , а затем бегать по спискам и для каждого общего пара дает vaule от 1 рядом с ним, так будет выглядеть следующим образом

tag1: site1_site2 1, site1_site3 1, site2_site3 1 
tag2: site1_site2 1 

и так далее , а затем цепь другой MapReduce задания просуммировать значения для каждой пары я написал этот код для него

public static class TokenizerMapper extends Mapper<Object, Text, Text, Text>{ 

    private Text site = new Text(); 
    private Text tag = new Text(); 
    public void map(Object key, Text value, Context context) 
         throws IOException, InterruptedException { 
     StringTokenizer itr = new StringTokenizer(value.toString(), "\t"); 
     while (itr.hasMoreTokens()) { 
      site.set(itr.nextToken()); 
      tag.set(itr.nextToken()); 
      context.write(tag, site); 
     } 
    } 
} 

public static class tagCount extends Reducer<Text,IntWritable,Text,Text> { 

    public void reduce(Text key, Iterable<Text> values, Context context) 
          throws IOException, InterruptedException { 
     String res = ""; 
     while (values.iterator().hasNext()) { 
      res = res + "," + values.iterator().next(); 
     } 
     Text result = new Text(res); 
     context.write(key, result); 
    } 
} 

public static void main(String[] args) throws Exception { 
    Configuration conf = new Configuration(); 
    Job job = Job.getInstance(conf, "tag count"); 
    job.setJarByClass(WordCount.class); 
    job.setMapperClass(TokenizerMapper.class); 
    job.setCombinerClass(tagCount.class); 
    job.setReducerClass(tagCount.class); 
    job.setOutputKeyClass(Text.class); 
    job.setOutputValueClass(Text.class); 
    FileInputFormat.addInputPath(job, new Path(args[0])); 
    FileOutputFormat.setOutputPath(job, new Path(args[1])); 
    System.exit(job.waitForCompletion(true) ? 0 : 1); 
} 

моя первая проблема - как я могу объединить значения в редукторе? так как теперь я просто получить список

tag1 site1 
tag1 site2 

и так далее я попытался установить строку и когда я итерацию значений, чтобы добавить следующий маркер строки, но он не работает

спасибо очень много заранее за помощь

+0

Чтобы уточнить мой вопрос, я хочу знать, как я могу перебирать все значения для определенного ключа внутри редуктора. –

+0

ok Я действительно узнал, что мой код даже не переходит к функции редуктора только функции карты :( –

+0

Удалите 'job.setCombinerClass (tagCount.class);'. Вы не хотите объединителя для этого. –

ответ

1

Вот переписана вашего редуктора, чтобы вы начали:

public static class TagCount extends Reducer<Text,IntWritable,Text,IntWritable> { 

    private IntWritable one = new IntWritable(1); 
    private Text out = new Text(); 

    public void reduce(Text key, Iterable<Text> values, Context context) 
         throws IOException, InterruptedException { 

     List<String> sites = new ArrayList<String>(); 
     for (Text t : values) { 
      sites.add(t.toString()); 
     } 

     for (int i=0; i<sites.size()-1; i++) { 
      for (int j=i+1; j<sites.size(); j++) { 
       out.set(sites.get(i) + "_" + sites.get(j)) 
       context.write(out, one); 
      } 
     } 
    } 
} 

Резюме:

  • Вам необходимо построить внутреннюю коллекцию значений. В этом случае я использовал список строк, который является самым безопасным способом, пока вам не станет удобно, как Hadoop повторно использует объекты.
  • Этот код предполагает, что sites не будет большим, поэтому улучшение будет включать некоторую проверку его размера, поскольку мы помещаем его в память, а следующий context.write будет расширять данные.
  • Затем вы перебираете сайты и генерируете перестановки, записывая каждый из них.
  • Запишите данные с помощью SequenceFileOutputFormat, а затем ваша следующая работа может использовать SequenceFileInputFormat, а типы ввода картографа будут Text и IntWritable.
+0

Привет, спасибо за помощь, это действительно подтолкнуло меня вперед я написал то, что вы сказали, и когда я отлаживаю его в консоли, он отлично работает, но когда я смотрю на файл, он пуст по какой-то причине. context.write внутри For не работает или не перезаписывает себя. Думаю, –

+0

Убедитесь, что у вас есть работа .setOutputValueClass (IntWritable.class); ' –

+1

Прежде всего, я действительно хотел поблагодарить вас за то, что вы нашли время, чтобы помочь мне это оценить. –

Смежные вопросы