2013-05-17 3 views
2

Мне было интересно, как распределенная задающая рекомендация mahout org.apache.mahout.cf.taste.hadoop.item.RecommenderJob обрабатывает файлы csv, где дублируются и вписываются данные пользователя, элементы позиций, но с разными значениями предпочтений. Например, если бы я имел .csv файл, который имел записи, как

1,1,0.7
1,2,0.7
1,2,0.3
1,3,0.7
1,3,-0.7
Mahout Datamodel с дублирующимся пользователем, item enteries, но разные значения предпочтений

Как DataModel Mahout в справиться с этим? Объединит ли он значения предпочтений для данного пользователя, запись элемента (например, для элемента пользователя 1,2 предпочтение будет равно (0,7 + 0,3)), или оно усредняет значения (например, для элемента пользователя 1,2 предпочтение (0,7 + 0,3)/2) или по умолчанию используется последний пользователь, элемент, который он обнаруживает (например, для пользователя 1,2 значение предпочтения установлено равным 0,3).

Я задаю этот вопрос, потому что рассматриваю рекомендации, основанные на множественных показателях предпочтений (взгляды на элементы, нравы, антипатии, сохранение корзины и т. Д.). Было бы полезно, если бы datamodel обрабатывал значения предпочтений в виде линейных весов (например, представления позиций плюс сохранить в список пожеланий имеет более высокий показатель предпочтения, чем представления элементов). Если datamodel уже обрабатывает это путем суммирования, это спасло бы меня от дополнительной дополнительной карты, чтобы сортировать и вычислять общие баллы на основе нескольких показателей. Любое разъяснение, которое любой может предоставить на mahout .csv datamodel, работает в этом отношении для org.apache.mahout.cf.taste.hadoop.item.RecommenderJob. Благодарю.

+0

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

ответ

5

Нет, это перезаписывается. Модель не является аддитивной. Однако модель в Myrrix, производная от этого кода (который я коммерциализую) имеет принципиально аддитивный модем данных, только по той причине, что вы даете. Входные значения являются весами и всегда добавляются.

+0

Спасибо, Шон для уточнения. Поэтому, если я правильно понял, что если «hasoop.item.RecommenderJob» Mahout занимает один длинный файл csv в качестве ввода (скажем, в задании EMR), значение предпочтения для конкретной пары будет установлено на <пользователь, элемент, значение > кортеж, появляющийся ближе всего к файлу csv? – Astronaut7

+0

Я даже не думаю, что у вас есть эта гарантия ... Есть потенциально много входов, которые читаются в разных порядках разными картографами. Порядок, в котором они появляются на редукторе, не гарантируется. Разумеется, предположение в Mahout заключается в том, что у вас нет дубликатов ключей на входе. –

+0

Спасибо, Шон, за своевременный ответ! Это немного улаживает меня. – Astronaut7

1

объединить его перед началом расчета.

примеры:

import java.io.IOException; 
import java.util.Iterator; 
import java.util.StringTokenizer; 

import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.io.FloatWritable; 
import org.apache.hadoop.io.LongWritable; 
import org.apache.hadoop.io.Text; 
import org.apache.hadoop.mapred.FileInputFormat; 
import org.apache.hadoop.mapred.FileOutputFormat; 
import org.apache.hadoop.mapred.JobClient; 
import org.apache.hadoop.mapred.JobConf; 
import org.apache.hadoop.mapred.MapReduceBase; 
import org.apache.hadoop.mapred.Mapper; 
import org.apache.hadoop.mapred.OutputCollector; 
import org.apache.hadoop.mapred.Reducer; 
import org.apache.hadoop.mapred.Reporter; 
import org.apache.hadoop.mapred.TextInputFormat; 
import org.apache.hadoop.mapred.TextOutputFormat; 

public final class Merge { 
    public Merge() { 
    } 

    public static class MergeMapper extends MapReduceBase implements 
      Mapper<LongWritable, Text, Text, FloatWritable> { 

     public void map(LongWritable key, Text value, OutputCollector<Text, FloatWritable> collector, 
       Reporter reporter) throws IOException { 
      // TODO Auto-generated method stub 
      String line = value.toString(); 
      StringTokenizer tokenizer = new StringTokenizer(line); 
      if (tokenizer.hasMoreTokens()) { 
       String userId = tokenizer.nextToken(","); 
       String itemId = tokenizer.nextToken(","); 
       FloatWritable score = new FloatWritable(Float.valueOf(tokenizer.nextToken(","))); 
       collector.collect(new Text(userId + "," + itemId), score); 
      } 
      else { 
       System.out.println("empty line " + line); 
      } 

     } 
    } 

    public static class MergeReducer extends MapReduceBase implements 
      Reducer<Text, FloatWritable, Text, FloatWritable> { 

     public void reduce(Text key, Iterator<FloatWritable> scores, 
       OutputCollector<Text, FloatWritable> collector, Reporter reporter) throws IOException { 
      // TODO Auto-generated method stub 
      float sum = 0.0f; 
      while (scores.hasNext()) { 
       sum += scores.next().get(); 
      } 
      if (sum != 0.0) 
       collector.collect(key, new FloatWritable(sum)); 
     } 
    } 


    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { 

     JobConf conf = new JobConf(Merge.class); 
     conf.setJobName("Merge Data"); 

     conf.setOutputKeyClass(Text.class); 
     conf.setOutputValueClass(FloatWritable.class); 

     conf.setMapperClass(MergeMapper.class); 
     // combine the same key items 
     conf.setCombinerClass(MergeReducer.class); 
     conf.setReducerClass(MergeReducer.class); 

     conf.setInputFormat(TextInputFormat.class); 
     conf.set("mapred.textoutputformat.separator", ","); 
     conf.setOutputFormat(TextOutputFormat.class); 

     FileInputFormat.setInputPaths(conf, new Path("hdfs://localhost:49000/tmp/data")); 
     FileOutputFormat.setOutputPath(conf, new Path("hdfs://localhost:49000/tmp/data/output")); 

     JobClient.runJob(conf); 
    } 
}