实验目的

初步认识图计算的知识点

复习mapreduce的知识点,复习自定义排序分组的方法

学会设计mapreduce程序解决实际问题

实验原理

  QQ好友推荐算法是所有推荐算法中思路最简单的,我们利用的思想就是好友的好友很有可能是自己的好友,而共同好友越多,说明两个人认识的可能性越大。其实这个想法属于图计算的内容,人际关系社交网络是很典型的图计算的内容,大家可以参考相关资料。我们今天就基于共同好友的想法实现。

1.实现思路
  我们已有的数据是每个人以及他的好友,我们无法直接从这个数据得到他的好友的好友,换一种思路我们能够知道他的所有好友都有一个共同好友就是他,例如A有两个好友B和C,如果B和C不是好友那我们可以把B推荐给C,因为B和C有一个共同好友。基于这种思路我们有了实现方案。
  第一个map,首先输出key为自己和每一个好友组合,value标识已经是好友,另外还有输出key为好友的两两组合,value为1代表共同好友个数。reduce判断得到的数据的value如果已经是共同好友就直接返回,否则就累加,就能得到每两个非好友的人的共同好友人数。
  这个思路有个问题,我们map的key为两个人的组合,但是组合A+B和组合B+A是一样的,所以我们在写出数据之前,应该对数据进行排序,保证不会同时出现A+B和B+A。另外最后我们得到了每两个人的共同好友个数,但是我们应该排序才能得到应该推荐的好友是哪些。在reduce进行排序的方法大家都懂,需要自定义输出类,实现compareTo方法,同时定义GroupingComparator类。

2.代码实现
  例如一行数据为 A、B、C。
  第一个map可以先对B,C排序,输出(A|B,2)(A|C,2)代表A和B、C已经是好友了,然后输出(B|C,1),代表B、C有一个共同好友,第一个reduce遍历value,遇到2就说明已经是好友,直接return,否则一直累加,写出两个人共同好友数量。
  第二个mapreduce可以自定义一个FriendOfFriend的输出类,有id,推荐好友id,共同好友数量三个属性,map读进来的数据直接封装成这样的对象写出,他的分组compareTo方法先比较id然后比较共同好友数量,然后分组函数直接按id分组。在reduce的时候每组数据就是id一样按照count排序好的FriendOfFriend对象,直接写出。

实验环境

1.操作系统
  操作机:Windows_7
  操作机默认用户名:hongya,密码:123456
2.实验工具
  IntelliJ IDEA

 

 

IDEA全称IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合、代码审查、创新的GUI设计等方面的功能可以说是超常的。IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

  优点:
1)最突出的功能自然是调试(Debug),可以对Java代码,JavaScript,JQuery,Ajax等技术进行调试。其他编辑功能抛开不看,这点远胜Eclipse。
2)首先查看Map类型的对象,如果实现类采用的是哈希映射,则会自动过滤空的Entry实例。不像Eclipse,只能在默认的toString()方法中寻找你所要的key。
3)其次,需要动态Evaluate一个表达式的值,比如我得到了一个类的实例,但是并不知晓它的API,可以通过Code Completion点出它所支持的方法,这点Eclipse无法比拟。
4)最后,在多线程调试的情况下,Log on console的功能可以帮你检查多线程执行的情况。

  缺点:
1)插件开发匮乏,比起Eclipse,IDEA只能算是个插件的矮子,目前官方公布的插件不足400个,并且许多插件实质性的东西并没有,可能是IDEA本身就太强大了。
2)在同一页面中只支持单工程,这为开发带来一定的不便,特别是喜欢开发时建一个测试工程来测试部分方法的程序员带来心理上的不认同。
3)匮乏的技术文章,目前网络中能找到的技术支持基本没有,技术文章也少之又少。
4)资源消耗比较大,建个大中型的J2EE项目,启动后基本要200M以上的内存支持,包括安装软件在内,差不多要500M的硬盘空间支持。(由于很多智能功能是实时的,因此包括系统类在内的所有类都被IDEA存放到IDEA的工作路径中)。

  特色功能:
  智能选择
  丰富的导航模式
  历史记录功能
  JUnit的完美支持
  对重构的优越支持
  编码辅助
  灵活的排版功能
  XML的完美支持
  动态语法检测
  代码检查等等

步骤1:实验环境介绍

  本次试验和之前一样在本地运行,本地测试,数据也放在本地,由于数据是好友关系,大家可以自己生成数据进行测试。打开idea,本次的代码放在hellohadoop|com.hongya|day026下面,们可以进入D:/hongya/ideaspace/hellohadoop/src/com/hongya/day026查看源代码。有兴趣的同学也可以自行新建项目进行学习。

  1.1代码分析(此处打开操作机桌面的“idea64”进行操作)。
  第一个mapreduce实现类似Wordcount,只不过每次输出之前要排序,保证A+B和B+A都能输出A|B,另外直接好友多输出一个2标识已经是好友了。
  第二个mapreduce先定义一个FriendOfFriend类,compareTo方法先比较id然后比较共同好友数。另外自定义分组类,按照id分组。
  自定义一个FriendOfFriend的输出类,有id,推荐好友id,共同好友数量三个属性,map读进来的数据直接封装成这样的对象写出,他的分组compareTo方法先比较id然后比较共同好友数量,然后分组函数直接按id分组。在reduce的时候魅族数据就是id一样按照count排序好的FriendOfFriend对象,直接写出。

  FriendOfFriend:

public class FriendOfFriend implements WritableComparable<FriendOfFriend> {

    private String username;

    private String fof;

    private int count;

    //get set方法省略

    public void readFields(DataInput arg0) throws IOException {

        this.username=arg0.readUTF();

        this.count=arg0.readInt();

        this.fof=arg0.readUTF();

 

    }

    public void write(DataOutput arg0) throws IOException {

        arg0.writeUTF(username);

        arg0.writeInt(count);

        arg0.writeUTF(fof);

    }

 

    /**

     * 相当于 Object对象equals

     */

    @Override

    public int compareTo(FriendOfFriend o) {

        int result = this.username.compareTo(o.getUsername());

        if(result == 0){

            return Integer.compare(o.count, this.getCount());

        }

        return result;

    }

}

 

 

分组类FriendRecommendGroup:

public class FriendRecommendGroup extends WritableComparator {

 

    public FriendRecommendGroup(){

        super(FriendOfFriend.class,true);

    }

 

    public int compare(WritableComparable a, WritableComparable b) {

        FriendOfFriend k1=(FriendOfFriend) a;

        FriendOfFriend k2=(FriendOfFriend) b;

 

        return k1.getUsername().compareTo(k2.getUsername());

    }

}