spark-graphx以及图的相关介绍

首先介绍图:一、图的基本概念图是由顶点集合(vertex)及顶点间的关系集合组成的一种数据结构: Graph=( V, E ) V表示顶点的集合,E表示图的边的集合即顶点之间关系的集合。其中 V = { x | x  某个数据对象} 是顶点的有穷非空集合; E = {(x, y) | x, y  V } 或 E = {<x, y> | x, y  V && Path (x, y)} 是顶点之间关系的有穷集合,也叫做边(edge)集合。Path (x, y)表示从 x 到 y 的一条单向通路, 它是有方向的。 有向图与无向图 在有向图中,顶点对<x, y>是有序的。在无向图中,顶点对(x, y)是无序的。完全图 若有 n 个顶点的无向图有 n(n-1)/2 条边, 则此图为完全无向图。有 n 个顶点的有向图有n(n-1) 条边, 则此图为完全有向图。邻接顶点 如果 (u, v) 是 E(G) 中的一条边,则称 u 与 v 互为邻接顶点。某些图的边具有与它相关的数, 称之为权。这种带权图叫做网络。子图 设有两个图 G=(V, E) 和 G‘=(V’, E‘)。若 V’ V 且 E‘E, 则称 图G’ 是 图G 的子图顶点的度 一个顶点v的度是与它相关联的边的条数。记作TD(v)。在有向图中, 顶点的度等于该顶点的入度与出度之和。顶点 v 的入度是以 v 为终点的有向边的条数, 记作 ID(v); 顶点 v 的出度是以 v 为始点的有向边的条数, 记作 OD(v)。路径 在图 G=(V, E) 中, 若从顶点 vi 出发, 沿一些边经过一些顶点 vp1, vp2, …, vpm,到达顶点vj。则称顶点序列 ( vi vp1 vp2 ... vpm vj ) 为从顶点vi 到顶点 vj 的路径。它经过的边(vi, vp1)、(vp1, vp2)、...、(vpm, vj)应是属于E的边。路径长度非带权图的路径长度是指此路径上边的条数。带权图的路径长度是指路径上各边的权之和。回路 若路径上第一个顶点 v1 与最后一个顶点vm 重合, 则称这样的路径为回路或环。连通图与连通分量 在无向图中, 若从顶点v1到顶点v2有路径, 则称顶点v1与v2是连通的。如果图中任意一对顶点都是连通的, 则称此图是连通图。非连通图的极大连通子图叫做连通分量。强连通图与强连通分量 在有向图中, 若对于每一对顶点vi和vj, 都存在一条从vi到vj和从vj到vi的路径, 则称此图是强连通图。非强连通图的极大强连通子图叫做强连通分量。生成树 一个连通图的生成树是它的极小连通子图,在n个顶点的情形下,有n-1条边。但有向图则可能得到它的由若干有向树组成的生成森林。



上图可以看成是一个大图,里面有两个子图。

现在测试图的可达性:即一个图中每个顶点之间是否存在着关系,即一个顶点经过N条路径后可以到达另外一个顶点。

代码实现:spark-rdd

var rdd = sc.parallelize( Array((1,2),(1,3),(2,4),(3,4),(4,7),
  (2,5),(3,6),(7,5),(7,6),(6,8),(5,8),(9,10),(10,11)))
val rdd_ = rdd.map(x =>( x._2,x._1))
var oldCount = rdd.count()
var newCount = -1L
while( oldCount != newCount ) {
  oldCount = newCount
  rdd = rdd.union( rdd.join( rdd_ ).map( x => ( x._2._2,x._2._1 ) ) ).distinct( ).cache( )
  newCount = rdd.count( )
}
newCount = 29
 结果集:Array((7,8), (1,6), (7,6), (1,4), (6,8), (1,2), (4,7), (1,3), (2,6), (9,11), (3,7), (2,7), (4,5), (4,6), (3,6), (5,8), (3,4), (10,11), (9,10), (3,5), (2,5), (3,8), (2,8), (7,5), (1,5), (1,8), (1,7), (2,4), (4,8))

其实spark-graphx中提供了相关的API,即图的连通性,也就是求一个图的连通图:


val end: RDD[(VertexId, Int)] = sc.parallelize(Array(
          (1L, 1), (2L, 1), (3L,1), (4L, 1), (5L,1),(6L, 1),
      (7L,1),(8L,1),(9L,1),(10L,1),(11L,1)))
        val link: RDD[Edge[Double]] = sc.parallelize(Array(
          Edge(1L, 2L, 7.0), Edge(1L, 3L, 9.0), Edge(2L, 4L, 15.0),Edge(3L, 4L, 11.0),
          Edge(4L, 7L, 14.0),Edge(2L, 5L, 11.0),Edge(3L, 6L, 11.0), Edge(7L, 5L, 6.0),
          Edge(7L, 6L, 10.0), Edge(6L, 8L, 9.0), Edge(5L, 8L, 2.0),Edge(9L, 10L, 2.0),Edge(10L, 11L, 2.0)))
        val graph:Graph[Int,Double] = Graph( end, link )
//    val graph = GraphLoader.edgeListFile(sc,"hdfs://master:9000/user/graph",false,2)
    val connect : Graph[VertexId, Double] = graph.connectedComponents()
    val count = connect.vertices.collect()
结果集:Array((4,1), (6,1), (8,1), (10,9), (2,1), (11,9), (1,1), (3,1), (7,1), (9,9), (5,1))
其中点属性相同的点表示在同一张图中。
下面分别取出每个子图:
val vert = connect.vertices.map( vertex => vertex._2).distinct().collect()//1,9
val graphs :ArrayBuffer[Graph[VertexId,Double]] = null
for( i <- 0 to vert.length-1 ){
  graphs += connect.subgraph( vpred = (id, value) => if( value == i) true else false)
}
下面简单介绍connectedComponents的实现原理:见源码部分:
def run[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]): Graph[VertexId, ED] = {
  val ccGraph = graph.mapVertices { case (vid, _) => vid }
  def sendMessage(edge: EdgeTriplet[VertexId, ED]): Iterator[(VertexId, VertexId)] = {
    if (edge.srcAttr < edge.dstAttr) {
      Iterator((edge.dstId, edge.srcAttr))
    } else if (edge.srcAttr > edge.dstAttr) {
      Iterator((edge.srcId, edge.dstAttr))
    } else {
      Iterator.empty
    }
  }
  val initialMessage = Long.MaxValue
  Pregel(ccGraph, initialMessage, activeDirection = EdgeDirection.Either)(
    vprog = (id, attr, msg) => math.min(attr, msg),
    sendMsg = sendMessage,
    mergeMsg = (a, b) => math.min(a, b))
} // end of connectedComponents
从spark1.4之后采用的是发送消息的模型。
接触的spark-graphx,可以说是graphx部分的源码熟读了。如果有不正确的或者更好的方法希望大家能够指出,静候您的指教。后面会补充一些其他的关于图计算的算法,包括类似淘宝二条邻,最短路径(带出路径,打算自己实现,虽然graphx已经实现了)等


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值