Introducción al código fuente de la función pregel y cada parámetro:
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)
}
parámetro | Descripción |
---|---|
initialMsg | Cuando se inicializa el gráfico, cuando comienza el cálculo del modelo, todos los nodos recibirán un mensaje primero |
maxIteraciones | El número máximo de iteraciones |
activeDirection | Especifica la dirección para enviar el mensaje. |
vprog | El nodo llama al mensaje para fusionar los datos agregados con los atributos del nodo. |
sendMsg | Los nodos activos llaman a este método para enviar mensajes |
mergeMsg | Si un nodo recibe varios mensajes, mergeMsg se usa para agregar los mensajes múltiples en un solo mensaje. Si el nodo recibe solo un mensaje, esta función no se llama |
Ejemplo: encuentra la distancia más corta desde el vértice 5 a otros vértices
Antes de entender el caso, primero debemos aclarar dos puntos de conocimiento sobre el vértice:
- Hay dos estados de vértices:
(1), estado de pasivación [similar a inactividad, no hacer nada]
(2), estado activo [trabajo] - El vértice puede estar en estado activo, existen condiciones:
(1), el mensaje se recibió con éxito o
(2), cualquier mensaje se envió con éxito
//1、创建SparkContext
val spark: SparkConf = new SparkConf().setAppName("PregelDemo")
.setMaster("local[*]")
val sc = new SparkContext(spark)
//2、创建顶点
val vertexArray = Array(
(1L, ("Alice", 28)),
(2L, ("Bob", 27)),
(3L, ("Charlie", 65)),
(4L, ("David", 42)),
(5L, ("Ed", 55)),
(6L, ("Fran", 50))
)
val vertexRDD: RDD[(VertexId, (String,Int))] = sc.makeRDD(vertexArray)
//3、创建边,边的属性代表 相邻两个顶点之间的距离
val edgeArray = Array(
Edge(2L, 1L, 7),
Edge(2L, 4L, 2),
Edge(3L, 2L, 4),
Edge(3L, 6L, 3),
Edge(4L, 1L, 1),
Edge(2L, 5L, 2),
Edge(5L, 3L, 8),
Edge(5L, 6L, 3)
)
val edgeRDD: RDD[Edge[Int]] = sc.makeRDD(edgeArray)
//4、创建图(使用aply方式创建)
val graph1 = Graph(vertexRDD, edgeRDD)
/* ************************** 使用pregle算法计算,顶点5 到 各个顶点的最短距离 ************************** */
//被计算的图中 起始顶点id
val srcVertexId = 5L
val initialGraph: Graph[Double, PartitionID] = graph1.mapVertices{
case (vid,(name,age)) => if(vid==srcVertexId) 0.0 else Double.PositiveInfinity}
// initialGraph.vertices.collect().foreach(println)
//5、调用pregel
val pregelGraph: Graph[Double, PartitionID] = initialGraph.pregel(
Double.PositiveInfinity,
Int.MaxValue,
EdgeDirection.Out
)(
(vid: VertexId, vd: Double, distMsg: Double) => {
val minDist: Double = math.min(vd, distMsg)
println("vprog: " + vid + " " + vd + " " + distMsg + " " + minDist)
minDist
},
(edgeTriplet: EdgeTriplet[Double,PartitionID]) => {
if (edgeTriplet.srcAttr + edgeTriplet.attr < edgeTriplet.dstAttr) {
println("sendMsg " + edgeTriplet.srcId + " " + edgeTriplet.srcAttr+" "+
edgeTriplet.dstId + " " + edgeTriplet.dstAttr+" "+edgeTriplet.attr)
Iterator[(VertexId,Double)]((edgeTriplet.dstId,edgeTriplet.srcAttr+edgeTriplet.attr))
} else {
Iterator.empty
}
},
(msg1: Double, msg2: Double) => {
println("msg1: "+msg1+"msg2: "+msg2)
math.min(msg1, msg2)
}
)
println("输出结果:")
pregelGraph.triplets.collect().foreach(println)
println()
pregelGraph.vertices.collect().foreach(println)
El resultado es el siguiente (omita la impresión de otros procesos intermedios):
(1,15.0)
(2,12.0)
(3,8.0)
(4,14.0)
(5,0.0)
(6,3.0)
pregel 原理分析
Antes de llamar al método pregel, inicialice las propiedades de cada vértice del gráfico como se muestra en la siguiente figura: la distancia desde el vértice 5 a sí mismo es 0, así que configúrelo en 0, y todos los demás vértices se establecen en infinito positivo Doble.
Cuando se llama al método pregel:
Primero, todos los vértices recibirán un mensaje inicial initialMsg , de modo que todos los vértices estén en estado activo (nodos marcados en rojo).
Comienza la primera iteración:
Todos los vértices usan la dirección del borde de EdgeDirection.Out para llamar al método sendMsg para enviar un mensaje al vértice de destino. Si el atributo del vértice de origen + el atributo del borde <el atributo del vértice de destino, el mensaje se envía. De lo contrario, no se enviará.
Solo se envían dos lados con éxito:
5—> 3 (0 + 8 <Doble.Infinito, éxito),
5—> 6 (0 + 3 <Doble.Infinito, éxito)
3—> 2 (Doble.Infinito + 4> Doble .Infinito, falla)
3—> 6 (Doble.Infinito + 3> Doble.Infinito, falla)
2—> 1 (Doble.Infinito + 7> Doble.Infinito, falla)
2—> 4 (Doble.Infinito + 2> Doble.Infinito, falla)
2—> 5 (Doble.Infinito + 2> Doble.Infinito, falla)
4—> 1 (Doble.Infinito + 1> Doble.Infinito, falla)
Una vez completada la ejecución del método sendMsg , de acuerdo con la condición de que el vértice esté en estado activo, el vértice 5 envió mensajes con éxito al vértice 3 y al vértice 6 respectivamente, y el vértice 3 y el vértice 6 también recibieron correctamente el mensaje. Entonces, solo tres vértices 5, 3 y 6 están activos en este momento, y todos los demás vértices están pasivados. Luego, tanto el vértice 3 como el vértice 6 que recibieron el mensaje llaman al método vprog para fusionar el mensaje recibido con sus propios atributos. Como se muestra en la Figura 2 a continuación. El final de la primera iteración.
Comienza la segunda iteración:
El vértice 3 no pudo enviar un mensaje al vértice 6 y el vértice 3 envió un mensaje al vértice 2 con éxito. En este momento, el vértice 3 envió correctamente el mensaje y el vértice 2 recibió correctamente el mensaje, por lo que el vértice 2 y el vértice 3 se activaron. y otros vértices se pasivaron. Luego, el vértice 2 llama al método vprog para fusionar el mensaje recibido con sus propios atributos. Consulte la Figura 3. Hasta ahora, la segunda iteración ha terminado.
Comienza la tercera iteración:
El vértice 3 envía mensajes al vértice 2 falla y al vértice 6 falla, el vértice 2 envía mensajes al vértice 1 éxito, al vértice 4 éxito y al vértice 5 falla, por lo que el vértice 2, el vértice 1 y el vértice 4 se activan y otros vértices tienen un estado aburrido . El vértice 1 y el vértice 4 llaman respectivamente al método vprog para fusionar el mensaje recibido con sus propios atributos. Ver figura 4. Hasta ahora, la tercera iteración ha terminado.
Comienza la cuarta iteración:
El vértice 2 no pudo enviar mensajes al vértice 1 y el vértice 4 falló. El vértice 4 envía un mensaje al vértice 1 con éxito, el vértice 1 y el vértice 4 entran en estado activo y otros vértices entran en estado pasivado. Vertex 1 llama al método vprog para fusionar el mensaje recibido con sus propios atributos
Comienza la quinta iteración:
El vértice 4 no envía un mensaje al vértice 1 nuevamente, el vértice 4 y el vértice 1 entran en el estado de pasivación, en este momento todo el gráfico entra en el estado de pasivación. Terminar aqui