Pregel的计算模型
def pregel[A: ClassTag](
initialMsg: A,
maxIterations: Int = Int.MaxValue,
activeDirection: EdgeDirection = EdgeDirection.Either)(
vprog: (VertexId, VD, A) => VD,
sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)],
mergeMsg: (A, A) => A)
: Graph[VD, ED] = {
Pregel(graph, initialMsg, maxIterations, activeDirection)(vprog, sendMsg, mergeMsg)
}
pregel有两个参数列表。
/**
* Execute a Pregel-like iterative vertex-parallel abstraction. The
* user-defined vertex-program `vprog` is executed in parallel on
* each vertex receiving any inbound messages and computing a new
* value for the vertex. The `sendMsg` function is then invoked on
* all out-edges and is used to compute an optional message to the
* destination vertex. The `mergeMsg` function is a commutative
* associative function used to combine messages destined to the
* same vertex.
*
* On the first iteration all vertices receive the `initialMsg` and
* on subsequent iterations if a vertex does not receive a message
* then the vertex-program is not invoked.
*
* This function iterates until there are no remaining messages, or
* for `maxIterations` iterations.
这里的泛型A在本程序中是Double类型
首先initialGraph.pregel(Double.PositiveInfinity)
这里传递了一个参数:initialMsg:在第一次迭代的时候顶点收到的消息,为无穷大Double.PositiveInfinity。这里也可以写成initialGraph.pregel[Double](Double.PositiveInfinity)
然后vprog:用户定义的顶点程序运行在每一个顶点中,负责接收进来的信息,和计算新的顶点值。在第一次迭代的时候,所有的顶点程序将会被默认的initialMsg调用,在次轮迭代中,顶点程序只有接收到message才会被调用。
显而易见的是:两个消息来的时候,取它们当中路径的最小值。
initialGraph(vertexRDD, edgeRDD,属性)这个属性是每个顶点到原点5的距离。
SendMessage函数的原理是:
我们再回顾一下triplet的形式
这里vertices形式如下(2,Infinity),(1,Infinity)
Edges形式如下:
假设我们当前处理的triplet的 A对应点2,B对应点1
所以triplet.srcAttr
triplet.attr
triplet.dstAttr就是点1到原点5的距离。
如果triplet.srcAttr + triplet.attr < triplet.dstAttr)
即如果和更小,则通过Iterator发送该信息到目标顶点的函数。
Iterator((triplet.dstId, triplet.srcAttr + triplet.attr))
该信息的结构为(目标节点id,消息(即最短距离)),否则不发送。
注意到Pregel图算法整体思路是通过迭代计算每个顶点的属性直到到达定点条件。
第一次迭代,初始消息发的是无穷大,这个反正最后都会被math.min(a,b)给弄掉的。
下一次迭代的时候,对于下面几条边对应的triple暂时都不会有新的消息出来,还都是无穷大
比如
Edge(5,2,2)
可以看出triplet.srcAttr + triplet.attr < triplet.dstAttr)
Iterator((triplet.dstId, triplet.srcAttr + triplet.attr))
这样,再到下一轮的迭代中,节点处理函数vprog:
dist为原节点属性(Double)点2原来的节点属性是Inf,newDist为消息2。
所以,就会更新新的节点2属性值为2。
。。。。以此类推。