hadoop2.7.3+win10+idea环境下:MapReduce实现二度好友推荐算法

CSDN源码下载:MapReduce实现二度好友推荐算法

一、Hadoop安装

  可参考文章:Win10下安装Hadoop2.7.3

二、问题描述

  好友推荐功能简单的说是这样一个需求:
  预测某两个人是否认识,并推荐为好友,并且某两个非好友的用户,他们的共同好友越多,那么他们越可能认识。
alt
   以QQ好友举例,顶点A、B、C到G分别是QQ用户,两顶点之间的边表示两顶点代表的用户之间相互关注。比如,B、G有共同好友A,应该推荐B、G认识,而D、F有两个共同好友C、E,那么更加应该推荐D、F认识。

三、思路分析
  1. 推荐者与被推荐者一定有一个或多个相同的好友
  2. 全局去寻找好友列表中两两关系
  3. 去除直接好友
  4. 统计两两关系出现次数
四、步骤讲解
  1. 导入数据
    alt
  2. 第一次Map,映射<(好友,好友), 0/1>键值对
    在这里插入图片描述
  3. 第一次Reduce,统计共同好友个数,去掉直接好友
    在这里插入图片描述
  4. 第一次进行job运算
    在这里插入图片描述
  5. 第二次Map,映射<(用户,hot值),好友:hot值>
      由于在MapReduce中,key值自动能够排序,而value值往往不可以。所以为了根据每一个用户与其他用户的共同好友个数从高到低排序,不仅需要将用户名作为key,还需要将该用户与推介用户的共同好友个数作为key的一部分。
  6. 第二次Reduce,对结果进行排序拼接处理
    hello:2,hadoop:2,mr:1,world:1,
  7. 第二次Job运算,得到结果
    在这里插入图片描述
五、代码
  1. 输入数据friends_demo.txt(用户 直接好友)
tom	cat,hadoop,hello
hello	mr,tom,world,hive
cat	tom,hiv
hive	cat,hadoop,world,hello,mr
mr	hive,hello
hadoop	tom,hive,world
world	hadoop,hive,hello
  1. 类型定义
      由于A1:A2与A2:A1是同一个潜在好友列表,为了能够方便的统计,故统一按照字典排序,输出A1:A2格式。
package friends_7_demo2;

import org.apache.hadoop.io.Text;

public class FoF extends Text {

    public  FoF() {
        super();
    }

    public FoF(String friend01,String friend02) {
        set(getof(friend01,friend02));
    }

    private String getof(String friend01, String friend02) {

        int c = friend01.compareTo(friend02);
        if (c>0) {
            return friend02+"\t"+friend01;
        }
        return friend01+"\t"+friend02;
    }
}
  1. 定义Map01
package friends_7_demo2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.util.StringUtils;

import java.io.IOException;

/**
 * map函数,统计好友之间的FOF关系列表(FOF关系:潜在好友关系)
 */
public class Map01 extends Mapper<LongWritable, Text, FoF, IntWritable> {

    @Override
    protected void map(LongWritable key, Text value,Context context)
            throws IOException, InterruptedException {
        String lines = value.toString(); // 用户所有的好友列表
        String userAndFriends[] = StringUtils.split(lines, '\t');
        String user = userAndFriends[0];
        String[] friends;
        if(userAndFriends.length == 1){
            return;
        }else if (userAndFriends[1].length() == 1){
            friends = new String[]{userAndFriends[1]};
        }else {
            friends= userAndFriends[1].split(",");
        }

        //好友之间的FOF关系矩阵
        for (int i = 0; i < friends.length; i++) {
            String friend = friends[i];
            context.write(new FoF(user,friend),new IntWritable(0));//输出好友列表,值为0。方便在reduce阶段去除已经是好友的FOF关系。

            for (int j = i+1; j < friends.length; j++) {
                String friend2 = friends[j];
                context.write(new FoF(friend, friend2), new IntWritable(1));//输出好友之间的FOF关系列表,值为1,方便reduce阶段累加
            }
        }
    }
}
  1. 定义Reduce01
package friends_7_demo2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.util.StringUtils;

import java.io.IOException;

/**
 * reduce函数,统计全部的FOF关系列表的系数
 */
public class Reduce01 extends Reducer<FoF, IntWritable, Text, NullWritable> {

    @Override
    protected void reduce(FoF key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {

        int sum = 0;
        boolean f = true;
        for(IntWritable i : values){
            if (0==i.get()) { //已经是好友关系
                f=false;
                break;
            }
            sum+=i.get();	//累计,统计FOF的系数
        }
        System.out.println("******************Reduce01*******************");
        if (f) {
            String msg = StringUtils.split(key.toString(), '\t')[0]+" "+StringUtils.split(key.toString(), '\t')[1]+" "+sum;
            System.out.println(msg);
            context.write(new Text(msg), NullWritable.get()); //输出key为潜在好友对,值为出现的次数
        }
    }
}
  1. 定义JobFriends类,实现jobOne
package friends_7_demo2;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class JobFriends {

    public static void main(String[] args) {
        Boolean flag = jobOne();
        if (flag) {
            jobTwo();
        }
    }

    // MapReduce01
    private static Boolean jobOne() {
        Configuration config = new Configuration();

        boolean flag = false;
        try{
            Job job = Job.getInstance(config);

            job.setJarByClass(JobFriends.class);
            job.setJobName("fof one job");

            job.setMapperClass(Map01.class);
            job.setReducerClass(Reduce01.class);

            job.setOutputKeyClass(FoF.class);
            job.setOutputValueClass(IntWritable.class);

            Path input = new Path("……\\input\\friends_7.txt");
            FileInputFormat.addInputPath(job, input);

            Path output = new Path("……\\output\\friends_7\\f1");
            //如果文件存在,,删除文件,方便后续调试代码
            if (output.getFileSystem(config).exists(output)) {
                output.getFileSystem(config).delete(output,true);
            }

            FileOutputFormat.setOutputPath(job, output);

            flag = job.waitForCompletion(true);
            if (flag) {
                System.out.println("job1 success...");
            }
        } catch(Exception e){
            e.printStackTrace();
        }

        return flag;
    }
}

  输出结果:

cat hadoop 2
cat hello 2
cat mr 1
cat world 1
hadoop hello 3
hadoop mr 1
hive tom 3
mr tom 1
mr world 2
tom world 2
  1. 好友推荐计算,类型定义
      由于在MapReduce中,key值自动能够排序,而value值往往不可以。所以为了根据每一个用户与其他用户的共同好友个数从高到低排序,不仅需要将用户名作为key,还需要将该用户与推介用户的共同好友个数作为key的一部分,所以需要重新定义一个类。
package friends_7_demo2;

import org.apache.hadoop.io.WritableComparable;

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

/**
 *  FriendSort作为key和value,FriendSort:用户名+FOF系数
 *  用户名一致,FOF系数从大到小排序。 很容易得到一个用户的好友推介的列表
 */
public class FriendSort implements WritableComparable<FriendSort> {

    private String friend;
    private int hot;

    public String getFriend() {
        return friend;
    }

    public void setFriend(String friend) {
        this.friend = friend;
    }

    public int getHot() {
        return hot;
    }

    public void setHot(int hot) {
        this.hot = hot;
    }


    public FriendSort() {
        super();
    }

    public FriendSort(String friend, int hot) {
        this.friend = friend;
        this.hot = hot;
    }
    //反序列化
    @Override
    public void readFields(DataInput in) throws IOException {
        this.friend=in.readUTF();
        this.hot=in.readInt();
    }
    //序列化
    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(friend);
        out.writeInt(hot);
    }
    //判断是否为同一用户,并通过hot值排序
    @Override
    public int compareTo(FriendSort newFriend) {
        System.out.println(friend+"-------"+newFriend.getFriend());

        int c = friend.compareTo(newFriend.getFriend());
        int e = -Integer.compare(hot, newFriend.getHot());
        if (c==0) {
            return e;
        }
        return c;
    }
}
  1. 定义Map02
package friends_7_demo2;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.util.StringUtils;

import java.io.IOException;

/**
 * map函数,每个用户的推介好友列表,并按推介指数从大到小排序
 */
public class Map02 extends Mapper<LongWritable, Text, FriendSort, Text > {

    @Override
    protected void map(LongWritable key, Text value,Context context)
            throws IOException, InterruptedException {

        String lines = value.toString();
        String friend01 = StringUtils.split(lines,' ')[0];
        String friend02 = StringUtils.split(lines,' ')[1];	//推介的好友
        int hot = Integer.parseInt(StringUtils.split(lines,' ')[2]);	// 该推介好友的推介系数

        System.out.println("**************Map02******************");
        System.out.println(friend01+"  "+friend02+"  "+hot);
        System.out.println(friend02+"  "+friend01+"  "+hot);
        context.write(new FriendSort(friend01,hot),new Text(friend02+":"+hot));	 //mapkey输出用户和好友推介系数
        context.write(new FriendSort(friend02,hot),new Text(friend01+":"+hot));	//好友关系是相互的

    }
}
  1. 定义sort类
package friends_7_demo2;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

/**
 * 将key根据用户名和次数排序
 */
public class NumSort extends WritableComparator {
    public NumSort(){
        super(FriendSort.class,true);
    }

    public int compare(WritableComparable a, WritableComparable b) {
        FriendSort o1 =(FriendSort) a;
        FriendSort o2 =(FriendSort) b;

        int r =o1.getFriend().compareTo(o2.getFriend());
        if(r==0){
            return -Integer.compare(o1.getHot(), o2.getHot());
        }
        return r;
    }
}
  1. 定义group类
package friends_7_demo2;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

/**
 *  将同一个用户作为一个Group,同时被reduce处理
 */
public class UserGroup extends WritableComparator {
    public UserGroup(){
        super(FriendSort.class,true);
    }

    public int compare(WritableComparable a, WritableComparable b) {
        FriendSort o1 =(FriendSort) a;
        FriendSort o2 =(FriendSort) b;
        return o1.getFriend().compareTo(o2.getFriend());
    }
}
  1. 定义Reduce02
package friends_7_demo2;

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

import java.io.IOException;

/**
 * reduce函数
 */
public class Reduce02 extends Reducer<FriendSort, Text, Text, Text> {

    @Override
    protected void reduce(FriendSort user, Iterable<Text> friends, Context context)
            throws IOException, InterruptedException {

        String msg = "";
        //拼接推荐好友
        for(Text friend :friends){
            System.out.println("***************Reduce02*****************");
            msg += friend.toString()+",";
            System.out.println(msg);
        }
        context.write(new Text(user.getFriend()), new Text(msg));
    }
}
  1. 定义 JobTwo 类
package friends_7_demo2;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class JobFriends {

    public static void main(String[] args) {
        Boolean flag = jobOne();
        if (flag) {
            jobTwo();
        }
    }

    // MapReduce01
    private static Boolean jobOne() {
        Configuration config = new Configuration();

        boolean flag = false;
        try{
            Job job = Job.getInstance(config);

            job.setJarByClass(JobFriends.class);
            job.setJobName("fof one job");

            job.setMapperClass(Map01.class);
            job.setReducerClass(Reduce01.class);

            job.setOutputKeyClass(FoF.class);
            job.setOutputValueClass(IntWritable.class);

            Path input = new Path("……\\input\\friends_7.txt");
            FileInputFormat.addInputPath(job, input);

            Path output = new Path("……\\output\\friends_7\\f1");
            //如果文件存在,,删除文件,方便后续调试代码
            if (output.getFileSystem(config).exists(output)) {
                output.getFileSystem(config).delete(output,true);
            }

            FileOutputFormat.setOutputPath(job, output);

            flag = job.waitForCompletion(true);
            if (flag) {
                System.out.println("job1 success...");
            }
        } catch(Exception e){
            e.printStackTrace();
        }

        return flag;
    }

    private static Boolean jobTwo() {
        Configuration config =new Configuration();

        Boolean flag = false;
        try {
            Job job = Job.getInstance(config);

            job.setJarByClass(JobFriends.class);
            job.setJobName("fof two job");

            job.setMapperClass(Map02.class);
            job.setReducerClass(Reduce02.class);
            job.setSortComparatorClass(NumSort.class); //sort类
            job.setGroupingComparatorClass(UserGroup.class); //group类
            job.setMapOutputKeyClass(FriendSort.class);
            job.setMapOutputValueClass(Text.class);

            Path input = new Path("……\\output\\friends_7\\f1");
            FileInputFormat.addInputPath(job, input);

            Path output = new Path("……\\output\\friends_7\\f2");
            //如果文件存在,,删除文件,方便后续调试代码
            if (output.getFileSystem(config).exists(output)) {
                output.getFileSystem(config).delete(output,true);
            }

            FileOutputFormat.setOutputPath(job, output);

            flag = job.waitForCompletion(true);
            if (flag) {
                System.out.println("job2 success...");
            }

        } catch (Exception e) {
            e.printStackTrace();
        };
        return flag;
    }
}

  输出最终结果:

cat	hello:2,hadoop:2,mr:1,world:1,
hadoop	hello:3,cat:2,mr:1,
hello	hadoop:3,cat:2,
hive	tom:3,
mr	world:2,hadoop:1,tom:1,cat:1,
tom	hive:3,world:2,mr:1,
world	mr:2,tom:2,cat:1,

参考文章:【1】MapReduce实例——好友推荐 - sinat_34045444的博客
     【2】hadoop学习笔记–8.MapReduce案例一:简单好友推介实现 - 云计算技术频道 - 红黑联盟
     【3】mapreduce实现——腾讯大数据QQ共同好友推荐系统_码神岛
     【4】MR — 好友推荐算法 - ImCoder博客’s 文章
     【5】Hadoop实例:二度人脉与好友推荐 - 程序园
     【6】推荐算法之好友推荐 - - ITeye博客
     【7】Hadoop实例:二度人脉与好友推荐 - intergret的个人空间 - OSCHINA
     【8】MapReduce 社交好友推荐算法 - 夏延 - 博客园
     【9】MapReduce模拟小型推荐系统 - ThisisWilli - CSDN博客
     【10】MapReduce模拟实现好友推荐系统 - 张不帅 - CSDN博客

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值