hadoop编程----寻找社交网络图中的三角关系

来源:互联网 发布:java全排列 编辑:程序博客网 时间:2024/05/17 23:03

实验背景

图的三角形计数问题是一个基本的图计算问题,是很多复杂网络分析(比如社交网络分析)的基础。目前图的三角形计数问题已经成为了Spark 系统中GraphX 图计算库所提供的一个算法级API。本次实验任务就是要在Hadoop 系统上实现Twitter 社交网络图的三角形计数任务。

有向图转化为无向图

如下图所示,社交网络中的关注关系一般为有向图,这里需要转化为无向图。转化思路为:如果IF (A->B) or (B->A) THEN A-B。只要A与B在有向图中存在一条有向边,便认为A与B在无向图中存在边。
这里写图片描述
在具体实现中我们用邻接表来记录无向图。图中每个节点用long值来表示的。在邻接表中我们设置:
如果A-B & A < B,则将B加入A的邻接表;
如果A-B & B < A,则将A加入B的邻接表;
这样得到的邻接表中A : linkNode1, linkNode2, linkNode3,…记录与A节点相邻的节点,并且A < min(linkNode1, linkNode2, …)也即A的邻接表中记录的节点,标志它们long值都比A的long值要大。

从关系表中寻找三角关系

对于一个三角关系A,B,C,我们需要寻找到A-B,B-C,C-A才能确认一个三角关系是否存在。从中可以发现节点A需要同时对应A-B以及A-C。所以想到的思路如下:
对于邻接表中的A:node1,node2,…,nodek,A-node1以及A-node2都是相连的,所以想要判断node1与node2是否相连,只需要再查找node1与node2是否相连就可以了。假定node1 < node2,那么只需要在node1: ….中寻找node1的邻接关系中是否存在node2即可。
我们设定邻接表中所有节点node ∊ NODE, 每个node的邻接关系为LINKnode,那么可以将算法写成:
For all node ∊ NODE
For all pair (node1, node2) ∊ Linknode X Linknode
If node1 < node2
Emit (key = node1, value = node2);
Else if node2 < node1
Emit(key = node2, value = node1);

Emit将

类的设计

一共设计了3个类:
a) ToUndirectedGraph类负责将输入的有向图关系转化为无向图,并得到邻接关系作为输出。
b) CountNum类负责从邻接关系中找三角关系。
c) CountDriver类则负责连接ToUndirectedGraph和CountNum这两个Map-Reduce任务。

ToUndiredctedGraph类设计

Mapper:
对于输入中读入的一行中的a b,我们令Text key = min(a,b),Text value = max(a,b)作为输出。
Reducer:
对于key = a的所有输入,它们的value记录的节点便是与a相连的节点。
所以我们用一个TreeSet记录这些value。之所以用TreeSet,是因为其可以保证里面的元素是不重复的,并且是按照值的大小从小到大进行排序的。
之后遍历这个TreeSet,将它里边的所有节点连成用”,”分割的String s,之后则将
Text key = a, Text Value = new Text( s)作为输出。

CountNum类设计

Mapper:
输入为邻接关系,对于输入的一行,value中记录了一条邻接关系。第一个节点为a,则之后记录了与a相连的节点linkNodes,并且linkNodes中的任意点b,都有b>a。
我们得到所有的(node1,node2),node1 < node2 && node1,node2都属于linkNodes,那么接下来只需要寻找node1与node2是否相连。所以将(key = node1, value = node2)放入输出。为了在reduce阶段进行查找,需要知道此时map的输入邻接表,所以我们为了查找方便,将(key = a, value = “a” + linkNodes)也放入输出,并且value加个字符前缀”a”来表示这是邻接关系。
Reducer:
对于输入的的(key,value),首先根据value是否有”a”前缀判断它是待检测边还是邻接关系。如果是邻接关系,我们用一个HashMap记录这个邻接关系value中的所有邻接节点,之所以用HashMap,是因为其查找的时间复杂度为O(1)。如果没有前缀”a”,则在HashMap中查找是否有相同的key,如果找到,三角形计数加一。
在最后的cleanup函数中将计数写入输出。

CountDriver类设计

这个类用于连接上面两个map-reduce,使用3个输入参数,第1个输入参数为ToUndirectedGraph的输入文件,第2个输入参数是ToUndirectedGraph的输出文件以及CountNum的输入文件,第3个输入参数是CountNum的输出文件。

实验过程

利用scp命令将此jar传到服务器上:
这里写图片描述
通过ssh命令远程登录到集群服务器上:
这里写图片描述
通过ls命令,我们发现jar文件已经上传到集群了:
这里写图片描述
利用下面的命令执行jar文件,因为设置两个了mapreduce任务,第一个任务的输出成为第二个任务的输入,所以设置第一个任务的输出为out4_intermediate2文件,第二个任务的输出为out4_final文件:
$hadoop jar findTriangles.jar CountDriver hdfs://master01:54310/data/twitter_graph_v2.txt /user/2015st05/out4_intermediate2 /user/2015st05/out4_final
从图中可以看出有连续的两个mapreduce过程。
这里写图片描述
这里写图片描述
这里写图片描述

这里写图片描述
利用hadoop fs -cat /user/2015st05/out4_final/part-r-00000命令可以查看结果文件,结果文件截图如下:
这里写图片描述
通过$hadoop fs –get /user/2015st05/out4_final/part-r-00000 /home/results命令可以把结果文件传到本地的Linux文件系统中,通过ls可以看到:

web界面查看

如果是查看本机结果,可以先用$ifconfig查看本机IP,如果是访问集群,则需要知道集群IP。
这里集群IP地址为114.212.190.91,访问一共有两种,一种是
http://114.212.190.91:50030
还有一种是
http://114.212.190.91:50070
这里我想看出JobTracker的情况,所以访问
http://114.212.190.91:50030
会出现如下界面
这里写图片描述
之后将界面拉到最下面,选择Job Tracker History
然后就可以看看历史情况啦,找到自己的Job。
这里写图片描述

选作1

在有向图转无线图时,需要A->B&&B->A,才认为A-B。
修改的是ToUndirectedGarph类,在map阶段我们可以得到

选作2

在更大的数据上进行实验。这里的问题便是id号超过了int的表示范围,可以采用long来表示,我这里是使用String来表示ID号,数字String的大小比较可以参照下列规则:
1.长度较长的String大;
2.长度相同,用String.CompareTo进行比较。

思考

第一个Map-reduce的map个数与输入文件大小有关系,我们可以使用job.setNumReduceTasks来设置reduce的个数。而第二个map-reduce的map个数与第一个map-reduce的reduce个数是一致的,所以可以通过设置第一个map-reduce的reduce个数来控制第二个map-reduce中map的个数。当map中要处理的数据和逻辑都不少的时候,增加map个数是挺有效的,比如选做2。

出现奇怪结果想要查看Map输出时,如果不在main里边把job.setReducerClass给注释掉,那么很可能不会出现理想的Map输出结果。Reducer里边如果函数名写错了,那么Reducer过程可能没有执行,使得Mapper的输出成为了Reducer的输出。

代码可见:

github
说明为findTriangles的为最初的作业,说明为选作1的为选作1.

0 0
原创粉丝点击