MapReduce 社交好友推荐算法

Stella981
• 阅读 855

原理

如果A和B具有好友关系,B和C具有好友关系,而A和C却不是好友关系,那么我们称A和C这样的关系为:二度好友关系。

在生活中,二度好友推荐的运用非常广泛,比如某些主流社交产品中都会有"可能认识的人"这样的功能,一般来说可能认识的人就是通过二度好友关系搜索得到的,在传统的关系型数据库中,可以通过图的广度优先遍历算法实现,而且深度限定为2,然而在海量的数据中,这样的遍历成本太大,所以有必要利用MapReduce编程模型来并行化。

初始数据如下:

A B

C D

E F

F G

B D

B C

map阶段得到的结果为:

Key:A Value:B

Key:B Value:A C D

Key:C Value:B D

Key:E Value:F

Key:F Value:E G

Key:G Value:F

Reduce阶段再将Value进行笛卡尔积运算就可以得到二度好友关系了

(笛卡尔积公式:A×B={(x,y)|x∈A∧y∈B}

例如,A={a,b}, B={0,1,2},则

A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}

B×A={(0, a), (0, b), (1, a), (1, b), (2, a), (2, b)})

环境

Linux Ubuntu 14.04

jdk-7u75-linux-x64

Hadoop 2.6.0-cdh5.4.5

内容

MapReduce 社交好友推荐算法

MapReduce 社交好友推荐算法

通过初始数据,假设有A、B、C、D、E、F、G七位同学,其中A与B是好友关系,C与D是好友关系,E与F是好友关系,F与G是好友关系,B与D是好友关系,B与C是好友关系,通过分析A与B是好友,且B与C也是好友,我们就认为A与C互为可能认识的人,向A与C互相推荐对方。

实验步骤

1.首先,来准备实验需要用到的数据,切换到/data/mydata目录下,使用vim编辑一个friend_data.txt文件。

  1. cd /data/mydata

  2. vim friend_data.txt

2.将如下初始数据写入其中(注意数据之间以空格分割)

  1. A B

  2. C D

  3. E F

  4. F G

  5. B D

  6. B C

3.切换到/apps/hadoop/sbin目录下,开启Hadoop相关进程

  1. cd /apps/hadoop/sbin

  2. ./start-all.sh

4.输入JPS查看一下相关进程是否已经启动。

  1. jps

MapReduce 社交好友推荐算法

5.在HDFS的根下创建一个friend目录,并将friend_data.txt文件上传到HDFS上的friend文件夹下。

  1. hadoop fs -mkdir /friend

  2. hadoop fs -put /data/mydata/friend_data.txt /friend

6.打开Eclipse,创建一个Map/Reduce项目。

MapReduce 社交好友推荐算法

MapReduce 社交好友推荐算法

7.设置项目名为mr_sf并点击Finish。

MapReduce 社交好友推荐算法

8.创建一个包,名为mr_friend。

MapReduce 社交好友推荐算法

MapReduce 社交好友推荐算法

9.创建一个类,名为Find_Friend。

MapReduce 社交好友推荐算法

MapReduce 社交好友推荐算法

10.下面开始编写Find_Friend类的代码。

完整代码为:

  1. package mr_friend;

  2. import java.io.IOException;

  3. import java.net.URI;

  4. import java.net.URISyntaxException;

  5. import java.util.HashSet;

  6. import java.util.Iterator;

  7. import java.util.Set;

  8. import org.apache.hadoop.conf.Configuration;

  9. import org.apache.hadoop.fs.FileSystem;

  10. import org.apache.hadoop.fs.Path;

  11. import org.apache.hadoop.io.LongWritable;

  12. import org.apache.hadoop.io.Text;

  13. import org.apache.hadoop.mapreduce.Job;

  14. import org.apache.hadoop.mapreduce.Mapper;

  15. import org.apache.hadoop.mapreduce.Reducer;

  16. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

  17. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

  18. public class Find_Friend {

  19. /*

  20. map结果:

  21. A B

  22. B A

  23. C D

  24. D C

  25. E F

  26. F E

  27. F G

  28. G F

  29. B D

  30. D B

  31. B C

  32. C B

  33. */

  34. public static class FindFriendsMapper extends Mapper<LongWritable, Text, Text, Text> {

  35. @Override

  36. protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)

  37. throws IOException, InterruptedException {

  38. String line = value.toString();

  39. String array[] = line.split("\\s+");

  40. context.write(new Text(array[0]), new Text(array[1]));

  41. context.write(new Text(array[1]), new Text(array[0]));

  42. }

  43. }

  44. /*

  45. map之后,Shuffling将相同key的整理在一起,结果如下:

  46. shuffling结果(将结果输出到reduce):

  47. A B

  48. B A

  49. B D

  50. B C

  51. C D

  52. C B

  53. E F

  54. F E

  55. F G

  56. G F

  57. */

  58. //reduce将上面的数据进行笛卡尔积计算

  59. public static class FindFriendsReduce extends Reducer<Text, Text, Text, Text> {

  60. @Override

  61. protected void reduce(Text key, Iterable values, Reducer<Text, Text, Text, Text>.Context context)

  62. throws IOException, InterruptedException {

  63. //将重复数据去重

  64. Set set = new HashSet();

  65. for (Text v : values) {

  66. set.add(v.toString());

  67. }

  68. if (set.size() > 1) {

  69. for (Iterator i = set.iterator(); i.hasNext();) {

  70. String qqName = i.next();

  71. for (Iterator j = set.iterator(); j.hasNext();) {

  72. String otherQqName = j.next();

  73. if (!qqName.equals(otherQqName)) {

  74. context.write(new Text(qqName), new Text(otherQqName));

  75. }

  76. }

  77. }

  78. }

  79. }

  80. }

  81. public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {

  82. final String INPUT_PATH = "hdfs://127.0.0.1:9000/friend/friend_data.txt";

  83. final String OUTPUT_PATH = "hdfs://127.0.0.1:9000/friend/output";

  84. Configuration conf = new Configuration();

  85. //Configuration:map/reduce的配置类,向hadoop框架描述map-reduce执行的工作

  86. final FileSystem fileSystem = FileSystem.get(new URI(INPUT_PATH), conf);

  87. if(fileSystem.exists(new Path(OUTPUT_PATH))) {

  88. fileSystem.delete(new Path(OUTPUT_PATH), true);

  89. }

  90. Job job = Job.getInstance(conf, "Find_Friend");//设置一个用户定义的job名称

  91. job.setJarByClass(Find_Friend.class);

  92. job.setMapperClass(FindFriendsMapper.class);    //为job设置Mapper类

  93. job.setReducerClass(FindFriendsReduce.class);    //为job设置Reducer类

  94. job.setOutputKeyClass(Text.class);              //为job的输出数据设置Key类

  95. job.setOutputValueClass(Text.class);            //为job输出设置value类

  96. FileInputFormat.addInputPath(job, new Path(INPUT_PATH));

  97. FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));

  98. System.exit(job.waitForCompletion(true) ?0 : 1);          //运行job

  99. }

  100. }

11.下面在Find_Friend类下,单击右键,选择Run As=>Run on Hadoop,运行程序,查看执行结果。

MapReduce 社交好友推荐算法

12.程序执行完以后,查看HDFS上的/friend/output目录中的计算结果。

  1. hadoop fs -ls -R /friend

  2. hadoop fs -cat /friend/output/part-r-00000

MapReduce 社交好友推荐算法

通过分析结果,就得出了各位同学的可能认识的人的列表了。

至此,实验就已经结束了。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
QQ玩一玩好友排行榜与世界排行榜
QQ玩一玩好友排行榜与世界排行榜1、开发环境CocosCreatorV2.0.5手Q版本V7.9.0.3820(目前市场中最新版本)qqPlayCore.jsbuildTime:'FriNov09201813:20:45GMT0800(GMT08:00)'上出现,
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
3 OneToMany ManyToMany MappedBy Cascade
1双向1N关联对于1N关联,Hibernate推荐使用双向关联,而且不要让1的一方控制关联关系,而使用多的一方控制关联关系。a.一的一方 表示班级@Entity@Table(name"team_1")publicclassTeam{@Id@Gen
Stella981 Stella981
2年前
ELK学习笔记之ElasticSearch的索引详解
0x00ElasticSearch的索引和MySQL的索引方式对比Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
郑天寿 郑天寿
5个月前
IM 应用场景中如何限制只有好友之间才能互发消息?
功能介绍好友关系由开发者的应用服务器自行维护好友关系,融云服务器提供消息发送能力,消息发送过程中默认不会做任何权限校验得到userId后即可发送消息,例如:A发送消息给B,只需要把B的userId传给融云服务即可发送消息这样易用的设计可以使开发者高度自由集
郑天寿 郑天寿
5个月前
IM 应用场景中如何限制只有好友之间才能互发消息?
功能介绍好友关系由开发者的应用服务器自行维护好友关系,融云服务器提供消息发送能力,消息发送过程中默认不会做任何权限校验得到userId后即可发送消息,例如:A发送消息给B,只需要把B的userId传给融云服务即可发送消息这样易用的设计可以使开发者高度自由集