【大数据分析】基于Graphx的shortestpath源码解析

简介

Graphx 集成了shortestpath 最短路径算法,具体采用的是迪杰斯特拉算法,引用库为:org.apache.spark.graphx.lib.ShortestPaths。该算法用于计算图中所有的到目标点(点集)的距离。

shortestpath的大致使用方法

val landmarks = Seq(1, 4).map(_.toLong)
val results = ShortestPaths.run(graph, landmarks)

根据上面的代码可知:
(1)landmarks 是需要被计算与 graph 所有节点距离的节点(作为目标点)。
(2)landmarks 里的节点实际上也是 graph 中的节点,只是节点 id 被抽了出来。
(3)Seq 说明 landmarks 是一个集合。

算法解析

Graphx图数据处理基础:Pregel

Pregel是Google提出的大规模分布式图计算平台,专门用来解决网页链接分析、社交数据挖掘等实际应用中涉及的大规模分布式图计算问题。目前的图计算模型基本上都遵循BSP计算模式。

(1)消息传递。基于Pregel实现的图算法基本上都通过节点与节点之间传递消息来实现。总体上可分为初始化阶段发送消息前发送消息后(接收消息)三个阶段。
(2)节点状态。休眠(inactive)和激活(active),每次Pregel仅会针对处于激活态的节点进行消息传递。
(3)算法的每次迭代都是针对所有“激活”的数据进行处理。

ShortestPaths流程简述

在这里插入图片描述


假设有一份图数据 G,它的节点为 V ,目标节点集合为 LANDMARKS,如上图所示,LANDMARKS={1,4}
针对图算法的三个阶段,ShortestPaths的实现过程如下所示:
一、初始化阶段:
(1)为每一个V赋予一个 Map,来存储它与节点 T(LANDMARKS中的节点)的距离,如果该节点也存在在LANDMARKS中,则初始值为0,否则赋予一个空Map。
(2)将G中的点全部激活(上图为红色),然后所有的 v 会同时以自身作为出发点,探索整个G,来填充自己的 Map。

二、一次迭代内的内容
(1)针对所有处于激活态的节点做处理,实际上是针对所有S或者T处于激活状态的 S->T (点-边->点)元组。
(2)对于每个S->T元组,先获取T中的Map(简写为T(Map)),将 T(Map)中的value+1后与S中的Map(简写为S(Map))做一次Merge,如果Merge的结果与S原本的结果相等,则将T(Map)作为消息传递给S。否则,则不发生消息传递
(3)发生消息传递,S收到消息,将消息中的内容与S(Map)做一次Merge。结果作为新的S(Map),此时发生消息传递的S和T都处于激活态。
(4)不发生消息传递,该S->T元组由于不发生消息传递,进入休眠。如果某一个节点B处于A->B->C的元组关系中,而A->B元组发生了消息传递,而B->C没有,则B依然处于激活状态。
(5)重复(1),(2),(3),(4)直到没有处于激活态的节点。

ShortestPath源码

package com.edata.bigdata.algorithm.networks

import org.apache.spark.graphx.{EdgeTriplet, Graph, Pregel, VertexId}

import scala.reflect.ClassTag

/**
 * @author: Alan Sword
 * @description: Compute node connectivity between all pairs(or partly) of nodes.
 */

object AllPairNodeConnectivity extends Serializable {

  /**
   * @description: A Map definition that used to create the Map attributes for each vertex
   */
  type APNCMap = Map[VertexId, Int]

  /**
   * @param x : element that used to create a APNCMap
   * @description: update the apncmap by adding 1 to each element
   * @return : APNCMap type object
   */
  private def makeAPNCMap(x: (VertexId, Int)*) = Map(x: _*)

  /**
   * @param apncmap :the map attributes that needed to update
   * @description: update the apncmap by adding 1 to each element
   * @return apncmap
   */
  private def updateAPNCMap(apncmap: APNCMap): APNCMap = apncmap.map { case (v, d) => v -> (d + 1) }

  /**
   * @param apncmap1 :the first APNCMap that needed to merge
   * @param apncmap2 :the second APNCMap that needed to merge
   * @description: merge two key set,and then merge two APNCMap by choosing the smaller of two elements with the same key
   * @return
   */
  private def mergeAPNCMap(apncmap1: APNCMap, apncmap2: APNCMap): APNCMap = {
    (apncmap1.keySet ++ apncmap2.keySet).map {
      k => k -> math.min(apncmap1.getOrElse(k, Int.MaxValue), apncmap2.getOrElse(k, Int.MaxValue))
    }(collection.breakOut)
  }

  /**
   * @param id   : vertex id
   * @param attr : the APNCMap's attributes of vertex
   * @param msg  : the message received by the vertex
   * @description: this function will be called when a vertex receive a message, and it will merge the vertex's original attributes and APNCMap-type message
   * @return
   */
  def vertexProgram(id: VertexId, attr: APNCMap, msg: APNCMap): APNCMap = {
    mergeAPNCMap(attr, msg)
  }

  /**
   * @param edge : the triple ( S->T ) in graph
   * @description: call updateAPNCMap with T's attributes as the argument,and then call mergeAPNCMap with its result and S's attrubutes as arguments
   * @return
   */
  def sendMessage(edge: EdgeTriplet[APNCMap, _]): Iterator[(VertexId, APNCMap)] = {
    val newAttr = updateAPNCMap(edge.dstAttr)
    if (edge.srcAttr != mergeAPNCMap(newAttr, edge.srcAttr))
      Iterator((edge.srcId, newAttr))
    else
      Iterator.empty
  }

  /**
   * @param graph     : All the vertexs in graph will be taken as the starting vertexs
   * @param landmarks : All the vertexs in landmarks will be taken as the target vertexs
   * @tparam VD :the type of vertex's attributes
   * @tparam ED :the type of edge's attributes
   * @description: The main running method,including several steps:
   *               1.Initialization,initialize the APNCMap attributes for each vertex & activate all the vertex.
   *               2.Sending Message,for each triple that contain active vertex,determine whether a message needs to be send,if not,inactivate the related vertex.
   *               3.Receiving Message,recieve message & active the related vertex.
   * @return
   */
  def run[VD, ED: ClassTag](graph: Graph[VD, ED], landmarks: Seq[VertexId]): Graph[APNCMap, ED] = {
    //initialization,initialize the APNCMap attributes for each vertex & active all the vertex
    val APNCGraph = graph.mapVertices { (vid, attr) =>
      if (landmarks.contains(vid)) makeAPNCMap(vid -> 0) else makeAPNCMap()
    }
    // all the vertex will receive this message, and be activated
    val initialMessage = makeAPNCMap()
    //for each triple that contain active vertex,determine whether a message needs to be send,if not,inactivate the related vertex
    //recieve message & active the related vertex
    Pregel(APNCGraph, initialMessage)(vertexProgram, sendMessage, mergeAPNCMap)
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340