hadoop学习笔记--8.MapReduce案例一:简单好友推介实现
来源:互联网 发布:行知基地实践活动作文 编辑:程序博客网 时间:2024/06/06 04:19
好友推荐算法在实际的社交环境中应用较多,比如qq软件中的“你可能认识的好友”或者是Facebook中的好友推介。常见的好友推介算法有六度分割理论,三元闭包论 和最基本的好友推介算法。在这简单介绍最简单的好友推介算法。
假设用户A有好友A1,A2,A3,则A1,A2,A3相互之间都可能通过好友A认识,是潜在的好友关系。如果用户B有好友A1,A2,B1,则A1,A2,B1相互之间都可能通过好友B认识。如下图所示
如上图所示,A1,A2在潜在好友列表中出现2次,说明A1,A2有2个共同好友,在上图中即为A,B。当两个潜在好友如果共同好友越多,则他们可能认识的可能性就越大,彼此之间推介机会就越高。算法简单介绍如下:首先需要遍历所有用户的好友列表生成两两间的潜在好友列表,计算所有用户潜在好友列表中同一对潜在好友出现的次数。如上图例子中A1,A2出现次数为2次。注意:A1:A2与A2:A1为相同的一对潜在好友,计算时应进行累加。再次计算同一个用户的潜在好友列表和出现的次数,如图中A1用户,A1与A2出现2次,A1与A3出现1次,A1与B1出现1次。如果只能给每个用户推介一个好友的话,A2与A1认识的可能性更大,优先推介A2。注意:还需要除去已经是该用户好友的潜在好友列表。如果A1与A2已经是好友关系了,则不需要再次推介。
2.1 实验数据
备注:每个名字之间用”\t”分隔符隔开。
2.2 潜在好友列表统计
2.2.1 类型定义
由于A1:A2与A2:A1是同一个潜在好友列表,为了能够方便的统计,故统一按照字典排序,输出A1:A2格式。
package friendsToFriends;import org.apache.hadoop.io.Text;/** * * @author liu * 说明:好友a:b之间与好友b:a之间是一样的,为了在reduce阶段,key相同可以自动合并, * 故采用字典排序统一规范好友之间的名字列表 */public class Fof extends Text{ public Fof(){ super(); } public Fof(String a,String b){ super(getFof(a, b)); } //统一确定a与b的排序格式 public static String getFof(String a,String b){ int r = a.compareTo(b); if(r<0){ return a+"\t"+b; }else{ return b+"\t"+a; } }}
2.2.2 Map类定义
//map函数,统计好友之间的FOF关系列表(FOF关系:潜在好友关系) static class FofMapper extends Mapper<Text, Text, Fof, IntWritable>{ @Override protected void map(Text key, Text value, Context context) throws IOException, InterruptedException { String user = key.toString(); //用户 String[] friends = StringUtils.split(value.toString(), '\t'); //用户所有的好友列表 //好友之间的FOF关系矩阵 for (int i = 0; i < friends.length; i++) { String f1 = friends[i]; //好友1 Fof AlreadyFriends =new Fof(user, f1); //用户的好友列表 context.write(AlreadyFriends, new IntWritable(0)); //输出好友列表,值为0。方便在reduce阶段去除已经是好友的FOF关系。 for (int j = i+1; j < friends.length; j++) { String f2 = friends[j]; //好友2 Fof fof = new Fof(f1,f2); context.write(fof, new IntWritable(1)); //输出好友之间的FOF关系列表,值为1,方便reduce阶段累加 } } } }
2.2.3 Reduce类定义
//reduce函数,统计全部的FOF关系列表的系数 static class FofReducer extends Reducer<Fof, IntWritable, Fof, IntWritable>{ @Override protected void reduce(Fof arg0, Iterable<IntWritable> arg1, Context arg2) throws IOException, InterruptedException { int sum = 0; boolean f = true; for(IntWritable i:arg1){ if(i.get() == 0){ //已经是好友关系 f = false; break; }else { sum = sum+i.get(); //累计,统计FOF的系数 } } if(f){ //已经是好友关系的,不再重复推介 arg2.write(arg0, new IntWritable(sum)); //输出key为潜在好友对,值为出现的次数 } } }
2.2.4 运行类定义
public static void run1(Configuration config) { try { FileSystem fs =FileSystem.get(config); //设置job Job job = Job.getInstance(config); job.setJarByClass(Main.class); //设置main方法所在的类 job.setJobName("run1"); //设置mapper相关类 job.setMapperClass(FofMapper.class); job.setMapOutputKeyClass(Fof.class); job.setMapOutputValueClass(IntWritable.class); //设置reducer相关属性 job.setReducerClass(FofReducer.class); job.setOutputKeyClass(Fof.class); job.setOutputValueClass(IntWritable.class); //设置keyvalue分隔符 job.setInputFormatClass(KeyValueTextInputFormat.class); //设置输入输出目录 FileInputFormat.addInputPath(job, new Path("/home/liu/input/FOF/FOF数据.txt")); Path outPath = new Path("/home/liu/output/FOF/f1"); if(fs.exists(outPath)){ fs.delete(outPath, true); } FileOutputFormat.setOutputPath(job, outPath); //提交任务 boolean f = job.waitForCompletion(true); if(f){ System.out.println("job执行成功"); } } catch (Exception e) { e.printStackTrace(); } }
2.2.5 实验结果
2.3 好友推介计算
由于在MapReduce中,key值自动能够排序,而value值往往不可以。所以为了根据每一个用户与其他用户的共同好友个数从高到低排序,不仅需要将用户名作为key,还需要将该用户与推介用户的共同好友个数作为key的一部分。所以需要重新定义一个类。
2.3.1 类型定义
package friendsToFriends;import java.io.DataInput;import java.io.DataOutput;import java.io.IOException;import org.apache.hadoop.io.WritableComparable;/** * * @author liu * User作为key和value,User:用户名+FOF系数 * 用户名一致,FOF系数从大到小排序。 很容易得到一个用户的好友推介的列表 */public class User implements WritableComparable<User>{ private String name; private int friendsCount; public User() { } public User(String name,int friendsCount){ this.name=name; this.friendsCount=friendsCount; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getFriendsCount() { return friendsCount; } public void setFriendsCount(int friendsCount) { this.friendsCount = friendsCount; } //反序列化 public void readFields(DataInput arg0) throws IOException { this.name = arg0.readUTF(); this.friendsCount = arg0.readInt(); } //序列化 public void write(DataOutput arg0) throws IOException { arg0.writeUTF(name); arg0.writeInt(friendsCount); } //判断是否为同一用户 public int compareTo(User o) { int result = this.name.compareTo(o.name); if(result==0){ return Integer.compare(this.friendsCount, o.friendsCount); } return result; }}
2.3.2 Map类定义
//map函数,每个用户的推介好友列表,并按推介指数从大到小排序 static class SortMapper extends Mapper<Text, Text,User, User>{ protected void map(Text key, Text value, Context context) throws IOException, InterruptedException { String[] splits = StringUtils.split(value.toString(),'\t'); String other = splits[0]; //推介的好友 int friendsCount = Integer.parseInt(splits[1]); // 该推介好友的推介系数 context.write(new User(key.toString(),friendsCount), new User(other,friendsCount)); //mapkey输出用户和好友推介系数。 context.write(new User(other,friendsCount), new User(key.toString(),friendsCount)); //好友关系是相互的, } }
2.3.3 sort类定义
package friendsToFriends;import org.apache.hadoop.io.WritableComparable;import org.apache.hadoop.io.WritableComparator;/** * * @author liu * 将key根据用户名和次数排序 */public class FofSort extends WritableComparator{ public FofSort() { super(User.class,true); } public int compare(WritableComparable a,WritableComparable b){ User u1 = (User) a; User u2 = (User) b; int result = u1.getName().compareTo(u2.getName()); //比较用户名 if(result == 0){ return -Integer.compare(u1.getFriendsCount(), u2.getFriendsCount()); //比较次数 } return result; }}
2.3.4 Group类定义
package friendsToFriends;import org.apache.hadoop.io.WritableComparable;import org.apache.hadoop.io.WritableComparator;/** * * @author liu * 将同一个用户作为一个Group,同时被reduce处理。 */public class FoFGroup extends WritableComparator{ public FoFGroup() { super(User.class,true); } public int compare(WritableComparable a, WritableComparable b) { User u1 =(User) a; User u2=(User) b; return u1.getName().compareTo(u2.getName()); //比较是否为同一个用户 }}
2.3.5 Reduce类定义
//同一时刻,同一个group的值同时处理,同一个group的值放在 Iterable<User> arg1中static class SortReducer extends Reducer<User, User, Text, Text>{ protected void reduce(User arg0, Iterable<User> arg1, Context arg2) throws IOException, InterruptedException { String user = arg0.getName(); //用户名 StringBuffer sb = new StringBuffer(); for(User u:arg1){ sb.append(u.getName()+":"+u.getFriendsCount()+","); //推介好友 } arg2.write(new Text(user), new Text(sb.toString())); } }
2.3.6 运行类定义
public static void run2(Configuration config) { try { FileSystem fs =FileSystem.get(config); //设置job Job job = Job.getInstance(config); job.setJarByClass(Main.class); //设置main方法所在的类 job.setJobName("run2"); //设置mapper相关类 job.setMapperClass(SortMapper.class); job.setMapOutputKeyClass(User.class); job.setMapOutputValueClass(User.class); //设置reducer相关属性 job.setReducerClass(SortReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); //设置排序分组 job.setSortComparatorClass(FofSort.class); job.setGroupingComparatorClass(FoFGroup.class); //设置keyvalue分隔符 job.setInputFormatClass(KeyValueTextInputFormat.class); //设置输入输出目录 FileInputFormat.addInputPath(job, new Path("/home/liu/output/FOF/f1")); Path outPath = new Path("/home/liu/output/FOF/f2"); if(fs.exists(outPath)){ fs.delete(outPath, true); } FileOutputFormat.setOutputPath(job, outPath); //提交任务 boolean f = job.waitForCompletion(true); if(f){ System.out.println("job执行成功"); } } catch (Exception e) { e.printStackTrace(); } }
2.3.6 实验结果
- hadoop学习笔记--8.MapReduce案例一:简单好友推介实现
- Hadoop学习笔记:MapReduce原理简单学习
- Hadoop-简单的MapReduce案例
- hadoop学习--MapReduce初级案例
- Hadoop学习笔记---MapReduce
- Hadoop学习笔记---MapReduce
- Hadoop学习笔记---MapReduce
- Hadoop MapReduce学习笔记
- 使用MapReduce实现寻找共同好友的案例
- hadoop入门--简单的MapReduce案例
- hadoop入门--简单的MapReduce案例
- hadoop入门--简单的MapReduce案例
- hadoop入门--简单的MapReduce案例
- hadoop入门--简单的MapReduce案例
- hadoop入门--简单的MapReduce案例
- Hadoop MapReduce 简单案例--求平均值
- Hadoop MapReduce 简单案例--求素数个数
- TinyOS学习笔记推介
- 验证码工具类
- 一个http请求的详细过程
- hdu 1754 I hate it 线段树维护最大值
- C语言实现继承和多态
- SQL 语句(四)--------------数据查询(嵌套查询)
- hadoop学习笔记--8.MapReduce案例一:简单好友推介实现
- const的用法总结
- React-Native|实现ListView下拉刷新加载更多
- 智能一代云平台(三十九):不同服务之间数据调用的一些思考
- 线性渐变linear-gradient,放射性渐变radial-gradient,循环渐变
- 字符串
- new操作符做了哪些事情?
- 小白算法练习 街区最短问题
- Linux命令大全——面试