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

本文介绍了Apache Spark GraphX中使用迪杰斯特拉算法计算图中节点到目标点距离的方法,包括`ShortestPaths`操作的步骤,以及Pregel在大规模图计算中的应用。详细解析了初始化、消息传递和算法迭代的过程。

简介

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处于激活态。下一次迭代会将与S相关的三元组进行(2)
(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 ShortestPath 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)
  }
}

针对基础大学版导游小游戏的源代码下载及相关实现,以下是详细的解答: --- ### 基础大学版导游小游戏概述 此类小游戏通常用于展示校园地图、建筑分布以及提供简单的导航功能。其实现主要依赖于图形界面开发工具包(如Java Swing或JavaFX)、数据存储机制(如JSON文件或小型数据库SQLite)以及基本算法(路径规划等)。以下为一种基于Java的简单实现方案[^1]。 --- ### 技术栈与核心模块分析 #### 1. **前端界面** 采用Java Swing或JavaFX构建用户交互界面,包括地图显示区域、按钮控件和信息提示框。 ```java import javax.swing.*; public class GuideGameUI { public static void main(String[] args) { JFrame frame = new JFrame("大学导游小游戏"); frame.setSize(800, 600); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); JLabel label = new JLabel("欢迎来到虚拟校园!"); JButton button = new JButton("开始探索"); panel.add(label); panel.add(button); frame.add(panel); frame.setVisible(true); } } ``` #### 2. **数据管理** 通过JSON文件保存校园建筑物的位置坐标及其相关信息。例如: ```json { "buildings": [ {"name": "教学楼A", "x": 100, "y": 200}, {"name": "图书馆B", "x": 300, "y": 400}, {"name": "食堂C", "x": 500, "y": 300} ] } ``` 可使用第三方库`Jackson`解析JSON文件并加载到内存中。 #### 3. **路径规划** 对于两点之间的最短路径计算,可以引入Dijkstra算法或Floyd-Warshall算法。示例代码如下: ```java public class PathFinder { private int[][] graph; public PathFinder(int[][] adjacencyMatrix) { this.graph = adjacencyMatrix; } public List<Integer> findShortestPath(int start, int end) { PriorityQueue<Node> pq = new PriorityQueue<>(Comparator.comparingInt(node -> node.distance)); boolean[] visited = new boolean[graph.length]; int[] distances = new int[graph.length]; Arrays.fill(distances, Integer.MAX_VALUE); distances[start] = 0; pq.offer(new Node(start, 0)); while (!pq.isEmpty()) { Node current = pq.poll(); if (visited[current.vertex]) continue; visited[current.vertex] = true; for (int neighbor = 0; neighbor < graph.length; neighbor++) { if (graph[current.vertex][neighbor] != 0 && !visited[neighbor]) { int distance = distances[current.vertex] + graph[current.vertex][neighbor]; if (distance < distances[neighbor]) { distances[neighbor] = distance; pq.offer(new Node(neighbor, distance)); } } } } // 返回从start到end的具体路径逻辑省略... return null; } private static class Node { int vertex; int distance; Node(int v, int d) { this.vertex = v; this.distance = d; } } } ``` --- ### 源码获取途径 目前网络上有许多开源项目可供学习参考。如果希望直接获得完整的“基础大学版导游小游戏”源代码,可通过以下渠道搜索: - GitHub仓库:输入关键词“Campus Tour Game Java”进行检索; - 优快云资源区:部分博主分享过类似的毕业设计作品,需注意版权问题; - 开发论坛:Stack Overflow 或者国内的技术社区(如掘金、思否)可能存在相关讨论帖。 --- ### 注意事项 在下载他人提供的源代码前,请务必确认其授权许可类型,避免侵犯知识产权风险。另外,建议自行修改和完善现有代码以满足个性化需求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值