2021SC@SDUSC

目录

2021SC@SDUSC

聚合操作

1.聚合消息

2.计算度数


聚合操作

在很多Graph的分析任务中,聚合兄弟顶点的信息是关键步骤。例如,想要知道每个 用户的粉丝数以及这些粉丝的平均年龄,这就会用到聚合操作。很多迭代图的算法(例如, PageRank、Shortest Path > Connected component)都会多次聚合相邻顶点的属性。

1.聚合消息

GraphX的核心聚合操作是aggregateMessages,这个操作应用用户定义的sendMsg函数到 Graph的每个EdgeTriplet上,然后使用mergeMsg函数在目的顶点上聚合。aggregateMessages 的接口定义见下列代码清单。

class Graph[VDr ED] {

def aggregateMessages[Msg: ClassTag]( sendMsg: EdgeContext[VD, ED, Msg] => Unit,
 mergeMsg: (Msg, Msg) => Msg, tripletFields: TripletFields = TripletFields.All)

:VertexRDD[Msg]

注 GrapliX的早期版本提供了 mapReduceTriplets来处理聚合操作。
aggregateMessages相 比于mapReduceTriplets有很大的性能提升,
所以Spark官网建议将mapReduceTriplets 迁移到 aggregateMessageso


现在我们来计算每个用户的粉丝的平均年龄,见下列代码清单。


import org.apache.spark.graphx.util.GraphGenerators

//创建一个graph,使用age作为顶点属性。为简单起见,使用随机的graph

val graph: Graph[Double, Int]=

GraphGenerators.logNormalGraph(sc, numVertices = 100).mapVertices( (id, _)=> id.toDouble )

//计算年龄比用户自己大的粉丝的数量和所有粉丝的年龄总和

val olderFollowers: VertexRDD[(Int, Double)] = graph.aggregateMessages[(Int, Double)]( triplet =〉{ // Map函数

if (triplet.srcAttr > triplet.dstAttr)(

//每个用户计数为1,将计数与年龄一起发送给目的顶点 triplet.sendToDst(1, triplet.srcAttr)

}

},

//累加计数与年龄

(a, b) => (a._1 + b._l, a._2 + b._2) // Reduce函数

)

//每个顶点收到的消息,用粉丝总年龄除以粉丝总数.得到粉丝平均年龄

val avgAgeOfOlderFollowers: VertexRDD[Double]=

olderFollowers.mapValues( (id, value) => value match { case (count, totalAge)



=> totalAge / count })

//显示计算结果

avgAgeOfOlderFollowers.collect.foreach(printin())

2.计算度数

一种常见的聚合任务是计算每个顶点的度,即每个顶点相邻的边数。人们常常需要知道 每个顶点的出度、入度以及度数。GraphOps中包含了计算每个顶点的度数的操作集合。以计 算图中所有顶点的最大出度、最大入度以及最大度数为例,见下列代码清单。

//首先定义一个reduce函数用于计算最大度数

def max(a: (Vertexld, Int), b: (Vertexld, Int)): (Vertexld, Int) = {

if (a._2 > b._2) a else b

}

//计算每种度数的最大值的顶点

val maxInDegree: (Vertexld, Int) - graph.inDegrees»reduce(max)

val maxOutDegree: (Vertexld, Int) = graph.outDegrees.reduce(max)

val maxDegrees: (Vertexld, Int) = graph.degrees.reduce(max)
  1. 收集相邻顶点

在有些情况下需要收集每个顶点的相邻顶点以及相邻顶点的属性,可以使用collectNeigh- borlds 和 collectNeighbors,见下列代码清单。

class GraphOps[VD, ED] {

def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array

[Vertexld]]

def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[ Array

[(Vertexld, VD)]]

}

由于这些聚合操作都通过复制信息,并且需要大量的通信,所以十分消耗资源。尽可能 将这些操作转换为使用aggregateMessages。