Spark GraphX Pregel 應用

一、Pregel介紹

Pregel是一種基於BSP模型實現的並行圖處理系統。

BSP(Bulk Synchronous Parallel Computing Model,塊同步並行計算模型,又稱“大同步”模型)計算過程包括一系列全局超步(所謂的超步就是計算中的一次迭代),每個超步主要包括三個組件:

  1. 局部計算:每個參與的處理器都有自身的計算任務。
  2. 通訊:處理器羣相互交換數據。
  3. 柵欄同步(Barrier Synchronization):當一個處理器遇到“路障”(或柵欄),會等到其他所有處理器完成它們的計算步驟。

爲了解決大型圖的分佈式計算問題,Pregel搭建了一套可擴展的、有容錯機制的平臺,該平臺提供了一套非常靈活的API,可以描述各種各樣的圖計算。

Pregel作爲分佈式圖計算的計算框架,主要用於圖遍歷、最短路徑、PageRank計算等等。

  • Pregel計算模型以有向圖作爲輸入
  • 有向圖的每個頂點都有一個String類型的頂點ID
  • 每個頂點都有一個可修改的用戶自定義值與之關聯
  • 每條有向邊都和其源頂點關聯,並記錄了其目標頂點ID
  • 邊上有一個可修改的用戶自定義值與之關聯
  • 在每個超步S中,圖中的所有頂點都會並行執行相同的用戶自定義函數。
  • 每個頂點可以接收前一個超步(S-1)中發送給它的消息,修改其自身及其出射邊的狀態,併發送消息給其他頂點,甚至是修改整個圖的拓撲結構。
  • 在這種計算模式中,“邊。”並不是核心對象,在邊上面不會運行相應的計算,只有頂點纔會執行用戶自定義函數進行相應計算

採用消息傳遞模型主要基於以下兩個原因:

  1. 消息傳遞具有足夠的表達能力,沒有必要使用遠程讀取或共享內存的方式.
  2. 有助於提升系統整體性能.

二、Pregel的計算過程

Pregel的計算過程是由一系列被稱爲“超步”的迭代組成的。

在每個超步中,每個頂點上面都會並行執行用戶自定義的函數,該函數描述了一個頂點V在一個超步S中需要執行的操作。

該函數可以讀取前一個超步(S-1)中其他頂點發送給頂點V的消息,執行相應計算後,修改頂點V及其出射邊的狀態,然後沿着頂點V的出射邊發送消息給其他頂點,而且,一個消息可能經過多條邊的傳遞後被髮送到任意已知ID的目標頂點上去。

這些消息將會在下一個超步(S+1)中被目標頂點接收,然後像上述過程一樣開始下一個超步(S+1)的迭代過程。

在Pregel計算過程中,一個算法什麼時候可以結束,是由所有頂點的狀態決定的。

在第0個超步,所有頂點處於活躍狀態。

當一個頂點不需要繼續執行進一步的計算時,就會把自己的狀態設置爲“停機”,進入非活躍狀態。

當一個處於非活躍狀態的頂點收到來自其他頂點的消息時,Pregel計算框架必須根據條件判斷來決定是否將其顯式喚醒進入活躍狀態。

當圖中所有的頂點都已經標識其自身達到“非活躍(inactive)”狀態,並且沒有消息在傳送的時候,算法就可以停止運行。
 

以上是搬運工... 轉載:https://blog.csdn.net/qq_38265137/article/details/80547763

三、Spark Graphx Pregel 應用

package net.ben

import org.apache.spark.graphx.{Edge, EdgeDirection, Graph}
import org.apache.spark.sql.SparkSession

object PregelDemo {
  /**
   * 數字的頂點的編號,並非頂點的值
   * 
   * 1L --\
   * 2L --- 4L -- 6L
   * 3L --/     /
   * 5L -------/
   * 
   * 編號爲4L的頂點,它的值是頂點1L,2L,3L的值的和
   * 1L + 2L + 3L = 4L
   * 
   * 編號爲6L的頂點,它的值是頂點4L,5L的值的和
   * 4L + 5L = 6L
   */
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("Spark GraphX Pregel Demo").master("local").getOrCreate()
    val sc = spark.sparkContext

    val vertices = sc.parallelize(Array((6L, 0), (4L, 0), (1L, 1000), (2L, 550), (5L, 300), (3L, 300)))
    // 有向圖,Edge(src, dst, attr),
    val edges = sc.parallelize(Array(Edge(1L, 4L, 1), Edge(2L, 4L, 1), Edge(3L, 4L, 1), Edge(4L, 6L, 1), Edge(5L, 6L, 1)))

    val graph = Graph(vertices, edges)
    val result = graph.pregel(0, activeDirection = EdgeDirection.Out)(
      (_, vd, msg) => msg + vd, // vertexProgram 用戶自定義函數,計算頂點值
      t => Iterator((t.dstId, t.srcAttr)), // sendMsg 用戶自定義函數,發送消息給下一超步
      (x, y) => x + y // mergeMsg 用戶自定義函數,合併上一超步的消息
    )
    result.vertices.collect().foreach(println)

    spark.stop
  }
}

輸出結果:

(4,1850)
(1,1000)
(6,2150)
(3,300)
(5,300)
(2,550)

參考文獻:

https://blog.csdn.net/qq_38265137/article/details/80547763

http://spark.apache.org/docs/latest/graphx-programming-guide.html#pregel-api

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章