Mapreduce之基于内容的电影推荐(一)

Mapreduce之基于内容的电影推荐(一)

背景

你是不是很想知道腾讯或爱奇艺是如何为用户创建推荐电影?或者淘宝京东如何为用户推荐图书?肯定有某种魔法算法生成的这些推荐系统,那么有那些推荐系统呢?

这里介绍基于内容的推荐系统,基于内容的推荐系统会检查项目(如电影)的属性来为用户作出推荐,例如一个用户如果看了很多动作片,那么系统就会为他推荐这一类电影

原理

在基于内容的推荐系统中,我们得到的内容信息(如邻域和元数据)越多,算法就会变得越复杂,不过推荐也会变得更准确,更合理,如,要实现电影推荐,系统应当有一些元数据,如演员,导演和制片人,在这个例子中,算法仅限于对电影评分。接下来使用关联度算法,对Mapreduce处理好的数据来找出每个电影之间的关联,进而进行推荐。

MapReduce解决方案如下:

  • 阶段1:找出各个电影的评分总人数
  • 阶段2:对每个电影对A和B,找出同时对A和B评分的人
  • 阶段3:找出每两个相关的电影之间的关联,在这个阶段使用三个不同的关联度算法(Pearson,Cosine和Jaccard)一般的,要根据具体数据需求来选择关联度算法,不过这个阶段可以使用任何想要的算法作实验

样例输入

输入数据包括用户ID,电影ID,评分。

即< UserID > < MovieID > < rating >
样例生成程序如下:

package com.deng.MovieRecommend;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class create {
    public static void main(String[] args) throws IOException, IOException {
        String path="input/movieRecommend.txt";
        File file=new File(path);
        if(!file.exists()){
            file.getParentFile().mkdirs();
        }
        file.createNewFile();
        FileWriter fw=new FileWriter(file,true);
        BufferedWriter bw=new BufferedWriter(fw);

        for(int i=0;i<5000;i++){
            int id=(int)(Math.random()*100)+1;
            int movieId=(int)(Math.random()*300);
            while(id==movieId) movieId=(int)(Math.random()*300);
            bw.write("UserId=User"+id+" Movie=Movie"+movieId+" rating="+(int)(Math.random()*5)+"\n");
        }
        bw.flush();
        bw.close();
        fw.close();
    }
}

程序创建5000行用户对电影评分的信息
在这里插入图片描述

MapReduce阶段1

这个阶段的目标是读取输入数据 < UserID > < MovieID > < rating >, ,通过简单的MapReduce获取每个电影的评价人数

如下:


UserIDMovieIDrating
User1Movie11
User1Movie22
User1Movie23
User2Movie11
User2Movie22
User2Movie33

生成如下格式
其中,numberOfPairs表示评价该电影的人数


UserIDMovieIDratingnumberOfPairs
User1Movie1145
User1Movie2256
mapper阶段任务

通过处理输入记录 < UserID> ,< MovieID> < rating > 生成 < < MoiveID >,<Tuple2( UserID , rating) >> 的键值对。

mappre阶段编码
package com.deng.MovieRecommend;

import com.deng.MRDPUtil;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;
import java.util.Map;

public class findNumberOfRatersMapper extends Mapper<LongWritable,Text,Text, Tuple2> {
    private Text K;
    private Tuple2<String,Integer> V;
    public void map(LongWritable key,Text value,Context context){
        String line=value.toString();
        // 解析数据
        Map<String,String> parsed= MRDPUtil.transInformation(line);
        K=new Text(parsed.get("Movie"));
        String user=parsed.get("UserId");
        Integer rating=Integer.parseInt(parsed.get("rating"));
        V=new Tuple2(user,rating);
        // 使用try -catch,这样如果发生一场就不会结束整个程序的运行
        try {
            context.write(K,V);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

其中Tuple2的设计模式如下:

package com.deng.MovieRecommend;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class Tuple2<T1,T2> implements Writable, WritableComparable<Tuple2<T1,T2>>{
    private T1 _1;
    private T2 _2;

    public Tuple2(){
    }

    public Tuple2(T1 _1, T2 _2){
        set(_1,_2);
    }

    private void set(T1 s1, T2 s2) {
        _1=s1;
        _2=s2;
    }

    public T1 first() {
        return _1;
    }

    public void setFirst(T1 _1) {
        this._1 = _1;
    }

    public T2 second() {
        return _2;
    }

    public void setSecond(T2 _2) {
        this._2 = _2;
    }

    @Override
    public int compareTo(Tuple2 o) {
        return 0;
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        Text.writeString(dataOutput, String.valueOf(_1));
        Text.writeString(dataOutput, String.valueOf(_2));
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        _1= (T1) Text.readString(dataInput);
        _2= (T2) Text.readString(dataInput);
    }

    public String toString(){
        StringBuffer sb=new StringBuffer("Tuple2[");
        sb.append(_1).append(",").append(_2);
        return sb.append("]").toString();
    }
}
reduce阶段任务

对mapper发送过来的数据进行处理,生成 < < UserID> <Tuple3( MovieID,rating,numberOfPairs) > >的键值对

package com.deng.MovieRecommend;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class findNumberOfRatersReducer extends Reducer<Text,Tuple2,Text,Tuple3> {
    public Integer numberOfRaters;  //通过获取键值对的个数来判断电影被评价的次数
    public Text K;// 用户名称
    public Tuple3<String,Integer,Integer> V;
    public void reduce(Text key,Iterable<Tuple2> values,Context context){
        List<Tuple2> tuple2List=new ArrayList<Tuple2>();
        for(Tuple2 t:values) {
            tuple2List.add(new Tuple2(t.first(),t.second()));
        };
        numberOfRaters=tuple2List.size();
        Map<Tuple2,Integer> mp=new HashMap<Tuple2, Integer>();
        for(Tuple2 t2:tuple2List){
            if(mp.get(t2)==null){
                mp.put(t2,1);
                K=new Text((String) t2.first());
                V=new Tuple3(key.toString(),t2.second(),numberOfRaters);
                try {
                    context.write(K,V);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                continue;
            }
        }
    }
    public Integer totalValues(Iterable<Tuple2> V){
        Integer total=0;
        for(Tuple2 t:V) total++;
        return total;
    }
}

其中Tuple3设计模式如下:

package com.deng.MovieRecommend;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class Tuple3<T1,T2,T3> implements Writable, WritableComparable<Tuple3<T1,T2,T3>> {
    private T1 _1;
    private T2 _2;
    private T3 _3;

    public Tuple3(){
    }

    public Tuple3(T1 _1,T2 _2,T3 _3){
        set(_1,_2,_3);
    }

    private void set(T1 first,T2 second,T3 third){
        _1=first;
        _2=second;
        _3=third;
    }

    public T1 first(){
        return _1;
    }

    public void setFirst(T1 _1){
        this._1=_1;
    }

    public T2 second(){
        return _2;
    }

    public void setSecond(T2 _2){
        this._2=_2;
    }

    public T3 third(){
        return _3;
    }

    public void setThird(T3 _3){
        this._3=_3;
    }

    public boolean equal(Tuple3 o){
        if(_1==o._1&&_2==o._2&&_3==o._3) return true;
        return false;
    }

    @Override
    public int compareTo(Tuple3 o) {
        String num=_1.toString().substring(5);
        String numO=o._1.toString().substring(5);
        if(Integer.parseInt(num)<Integer.parseInt(numO)){
            return 1;
        }else return -1;
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        Text.writeString(dataOutput, String.valueOf(_1));
        Text.writeString(dataOutput, String.valueOf(_2));
        Text.writeString(dataOutput, String.valueOf(_3));
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        _1= (T1) Text.readString(dataInput);
        _2= (T2) Text.readString(dataInput);
        _3= (T3) Text.readString(dataInput);
    }

    public String toString() {
        StringBuilder sb = new StringBuilder("Tuple3[");
        sb.append(_1).append(",").append(_2).append(",").append(_3);
        return sb.append("]").toString();
    }
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值