具有重复用户,项目条目但具有不同偏好值的Mahout数据模型

时间:2013-05-17 14:22:29

标签: hadoop mahout recommendation-engine mahout-recommender

我想知道分布式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的数据模型将如何处理?它会为给定用户,项目条目(例如,对于用户项目1,2,偏好将是(0.7 + 0.3))总结偏好值,或者是否对值进行平均(例如,对于用户项目1,2,偏好是(0.7 + 0.3)/ 2)或者它是否默认为最后一个用户,它检测到的项目条目(例如,对于用户1,2,优先级值设置为0.3)。

我问这个问题是因为我正在考虑基于多个偏好指标的推荐(项目视图,喜欢,不喜欢,保存到购物车等)。如果数据模型将偏好值视为线性权重(例如,项目视图加上保存到愿望列表具有比项目视图更高的偏好分数)将是有帮助的。如果datamodel已经通过求和来处理这个问题,它将为我节省额外map-reduce的杂项,以根据多个指标对总分进行排序和计算。任何人都可以在mahout .csv datamodel上为org.apache.mahout.cf.taste.hadoop.item.RecommenderJob工作的任何澄清都非常感谢。感谢。

2 个答案:

答案 0 :(得分:5)

不,它会覆盖。该模型不是附加的。然而,Myrrix中的模型,这个代码的衍生物(我正在商业化)有一个基本的附加数据模式,只是出于你给出的原因。输入值是权重,并且总是被添加。

答案 1 :(得分: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);
    }
}