Spark复习十:图聚合操作(aggregateMessages )和 Pregel 和 Pregel API以及操作案例分析

1.图聚合操作aggregateMessages:

1.1 聚合操作:

aggregateMessages:许多图分析任务中的一个关键步骤是聚集每个顶点的邻域信息,

在GraphX中最核心的聚合操作就是aggregateMessages.它主要功能是向邻边发消息,合并邻边收到的消息.

1.2.sendMsgmergeMsg :

sendMsg:
sendMsg 函数以EdgeContext作为输入参数 , 没有返回值
EdgeContext 提供了两个消息的发送函数
sendToSrc: 将Msg类型的消息发送给源顶点
sendToDst: 将Msg类型的消息发送给目标顶点
mergeMsg  :
每个顶点收到的所有消息都会被聚集起来传递给 mergeMsg 函数
mergeMsg函数定义了如何将顶点收到的所有消息转换成我们需要的结果
 

3. 图的聚合操作案例演示:

package aggregate

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.graphx.{Edge, EdgeContext, Graph}

object aggreTest2 {

  def sendMsg(ec:EdgeContext[Int,String,Int]):Unit = {
    ec.sendToDst( ec.srcAttr +1)
  }

  def mergeMsg(a: Int , b:Int) :Int = {
    math.max(a,b)
  }

  def sumEdgeCount( g:Graph[Int,String]):Graph[Int,String] = {
    val verts = g.aggregateMessages[Int]( sendMsg , mergeMsg)

    //verts.collect.foreach(println(_))

    val g2 = Graph(verts ,g.edges)


   //(4,(1,0))
    println( "*************************************")
    //g2.vertices.join(g.vertices).map( x => x._2._1 - x._2._2).reduce(_+_).collect.foreach(println(_))
    val check = g2.vertices.join(g.vertices).map( x => x._2._1 - x._2._2).reduce(_+_)
    println(check)
    println( "*************************************")
    if(check > 0)
      sumEdgeCount(g2)
    else
      g
  }



  def main(args: Array[String]): Unit = {

    //设置运行环境
    val conf = new SparkConf().setAppName("SimpleGraphX").setMaster("local")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")

    // 构建图
    val myVertices = sc.parallelize(Array((1L, "张三"), (2L, "李四"), (3L, "王五"), (4L, "钱六"),
      (5L, "领导")))
    val myEdges = sc.makeRDD(Array( Edge(1L,2L,"朋友"),
      Edge(2L,3L,"朋友") , Edge(3L,4L,"朋友"),
      Edge(4L,5L,"上下级"),Edge(3L,5L,"上下级")
    ))

    val myGraph = Graph(myVertices,myEdges)

    val initGraph = myGraph.mapVertices((_,_)=>0)

     sumEdgeCount(initGraph).vertices.collect.foreach(println(_))



  }

}

2.Pregel API:

2.1 Pregel 和 Pregel API:

Pregel
在Hadoop兴起之后,google又发布了三篇研究论文,分别阐述了了Caffeine、Pregel、Dremel三种技术,这三种技术也被成为google的新“三驾马车”,其中的Pregel是google提出的用于大规模分布式图计算框架。主要用于图遍历(BFS)、 最短路径(SSSP )、 PageRank计算等等计算
Pregel API
图本质上是递归的数据结构,因为顶点的属性依赖于它们的邻居的属性,而邻居的属性又依赖于它们的邻居的属性。因此,许多重要的图算法会迭代地重新计算每个顶点的属性,直到达到一个定点条件。提出了一系列图形并行抽象来表达这些迭代算法。GraphX 根据谷歌的思路实现了 自己的 Pregel API
 

 2.2 整体同步并行计算模型 BSP:

生成消息并传递给下一个超步。直到当前超步结束并将所有消息 传给下一个超步后下一个超步才会开始这就是同步屏障

2.3 Pregel API完成一个超步的内部细节:

2.4 pregel函数:

2.5 pregel 的 activeDirection 参数:

对于 一条 边 的 两个 顶点 srcId 和 dstId:
            EdgeDirection. Out—— 当 srcId 收到 来自 上一 轮 迭代 的 消息 时, 就会 调用 sendMsg, 这 意味着 把 这条 边 当作srcId 的“ 出 边”。
            EdgeDirection. In—— 当 dstId 收到 来自 上一 轮 迭代 的 消息 时, 就会 调用 sendMsg, 这 意味着 把 这条 边 当作 dstId 的“ 入 边”。
           EdgeDirection. Either—— 只要 srcId 或 dstId 收到 来自 上一 轮 迭代 的 消息 时, 就会 调用 sendMsg。
EdgeDirection. Both—— 只有 srcId 和 dstId 都 收到 来自 上一 轮 迭代 的 消息 时, 才会 调用 sendMsg。

2.6Pregel案例:

package pregel

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.graphx.{Edge, Graph, VertexId}
import org.apache.spark.graphx.util.GraphGenerators

object GraphXTest1 {

  def main(args: Array[String]): Unit = {
    //设置运行环境
    val conf = new SparkConf().setAppName("Pregel API GraphX").setMaster("local")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")

    // 构建图
    val myVertices = sc.parallelize(Array((1L, 0), (2L, 0), (3L, 0), (4L, 0),
      (5L, 0)))
    val myEdges = sc.makeRDD(Array( Edge(1L,2L,2.5),
      Edge(2L,3L,3.6) , Edge(3L,4L,4.5),
      Edge(4L,5L,0.1),Edge(3L,5L,5.2)
    ))
    val myGraph = Graph(myVertices,myEdges)

    val sourceId: VertexId = 1L // The ultimate source
    // Initialize the graph such that all vertices except the root have distance infinity.
    val initialGraph = myGraph.mapVertices((id, _) =>
      if (id == sourceId) 0.0 else Double.PositiveInfinity)


    val sssp: Graph[Double, Double] = initialGraph.pregel(Double.PositiveInfinity)(
      (id, dist, newDist) => math.min(dist, newDist), // Vertex Program
      triplet => {  // Send Message
        if (triplet.srcAttr + triplet.attr < triplet.dstAttr) {
          Iterator((triplet.dstId, triplet.srcAttr + triplet.attr))
        } else {
          Iterator.empty
        }
      },
      (a, b) => math.min(a, b) // Merge Message
    )

    sssp.vertices.collect.foreach(println(_))
  }


}
发布了28 篇原创文章 · 获赞 54 · 访问量 1103

猜你喜欢

转载自blog.csdn.net/csdnliu123/article/details/105622013
今日推荐