spark Graph 的PregelAPI 理解和使用

图本质上是一种递归的数据结构,可以使用Spark GraphX 的PregelAPI接口对图数据进行批量计算,

之前一直不怎么理解Pregel计算模型,因此花点时间整理一下,该api的理解以及使用方法等。

1、Pregel的计算模型

Pregel接口的官方定义:

  /**
* Execute a Pregel-like iterative vertex-parallel abstraction. The
* user-defined vertex-program `vprog` is executed in parallel on
* each vertex receiving any inbound messages and computing a new
* value for the vertex. The `sendMsg` function is then invoked on
* all out-edges and is used to compute an optional message to the
* destination vertex. The `mergeMsg` function is a commutative
* associative function used to combine messages destined to the
* same vertex.
*
* On the first iteration all vertices receive the `initialMsg` and
* on subsequent iterations if a vertex does not receive a message
* then the vertex-program is not invoked.
*
* This function iterates until there are no remaining messages, or
* for `maxIterations` iterations.
*
* @param A the Pregel message type
*
* @param initialMsg the message each vertex will receive at the on
* the first iteration
*
* @param maxIterations the maximum number of iterations to run for
*
* @param activeDirection the direction of edges incident to a vertex that received a message in
* the previous round on which to run `sendMsg`. For example, if this is `EdgeDirection.Out`, only
* out-edges of vertices that received a message in the previous round will run.
*
* @param vprog the user-defined vertex program which runs on each
* vertex and receives the inbound message and computes a new vertex
* value. On the first iteration the vertex program is invoked on
* all vertices and is passed the default message. On subsequent
* iterations the vertex program is only invoked on those vertices
* that receive messages.
*
* @param sendMsg a user supplied function that is applied to out
* edges of vertices that received messages in the current
* iteration
*
* @param mergeMsg a user supplied function that takes two incoming
* messages of type A and merges them into a single message of type
* A. ''This function must be commutative and associative and
* ideally the size of A should not increase.''
*
* @return the resulting graph at the end of the computation
*
*/
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)
}

方法的注释根据自己的实验理解如下:

执行类似Pregel的迭代顶点并行抽象。

在一次迭代计算中,图的各个顶点收到默认消息或者上一轮迭代发送的消息后;

首先调用mergeMsg函数将具有相同目的地的消息合并成一个消息;

然后调用vprog顶点函数计算出新的顶点属性值;

然后再调用sendMsg 函数向出边顶点发送下一轮迭代的消息;

迭代计算直到没有消息剩余或者达到最大迭代次数退出。

在首轮迭代的时候,所有的顶点都会接收到initialMsg消息,在次轮迭代的时候,如果顶点没有接收到消息,verteProgram则不会被调用。

这些函数迭代会一直持续到没有剩余消息或者达到最大迭代次数maxIterations

VD : 顶点的属性的数据类型。

ED : 边的属性的数据类型

VertexId : 顶点ID的类型

A : Pregel message的类型。

graph:计算的输入的图

initialMsg : 图的每个顶点在首轮迭代时收到的初始化消息

maxIterations:最大迭代的次数

vprog

vprog是用户定义的顶点程序,会运行在每一个顶点上,该vprog函数的功能是负责接收入站的message,

并计算出的顶点的新属性值。

在首轮迭代时,在所有的顶点上都会调用程序vprog函数,传人默认的defaultMessage;在次轮迭代时,只有接收到message消息的顶点才会调用vprog函数。

      vprog: (VertexId, VD, A) => VD
输入参数: 顶点ID ,该顶点对应的顶点属性值,本轮迭代收到的message
输出结果: 新的顶点属性值

sendMsg

用户提供的函数,应用于以当前迭代计算收到消息的顶点为源顶点的边edges;sendMsg函数的功能

是发送消息,消息的发送方向默认是沿着出边反向(向边的目的顶点发送消息)。

sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)],
输入参数是 EdgeTriplet :当前迭代计算收到消息的顶点为源顶点的边edges的EdgeTriplet对象。
输出结果: 下一迭代的消息。

mergeMsg

用户提供定义的函数,将具有相同目的地的消息合并成一个;如果一个顶点,收到两个以上的A类型的消息message,该函数将他们合并成一个A类型消息。 这个函数必须是可交换的和关联的。理想情况下,A类型的message的size大小不应增加。

mergeMsg: (A, A) => A)

输入参数:当前迭代中,一个顶点收到的2个A类型的message。
输出结果:A类型的消息

下面的例子是使用Pregel计算单源最短路径,在图中节点间查找最短的路径是非常常见的图算法,所谓“单源最短路径”,就是指给定初始节点StartV,

计算图中其他任意节点到该节点的最短距离。我简化了官方的示例,使我们可以更简单的理解pregel计算模型。

package graphxTest

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
import org.apache.spark.graphx.{Edge, Graph, VertexId} /**
* Created by Mtime on 2018/1/25.
*/
object GraphxPregelTest {
val spark = SparkSession
.builder
.appName(s"${this.getClass.getSimpleName}").master("local[2]")
.getOrCreate()
val sc = spark.sparkContext /**
* 计算最短路径
**/
def shortestPath(): Unit = {
//生成一个图对象
val graph: Graph[Long, Double] = genGraph
//打印出图的值
graph.triplets.foreach(t => {
println(s"t.srcId=${t.srcId} t.dstId=${t.dstId} t.srcAttr=${t.srcAttr} t.dstAttr=${t.dstAttr}")
}) val sourceId: VertexId = 1 // 计算顶点1到图各个顶点的最短路径
// Initialize the graph such that all vertices except the root have distance infinity.
val initialGraph = graph.mapVertices((id, att) =>
if (id == sourceId) 0.0 else Double.PositiveInfinity) println("------------------------------")
//打印出图的值
initialGraph.triplets.foreach(t => {
println(s"t.srcId=${t.srcId} t.dstId=${t.dstId} t.srcAttr=${t.srcAttr} t.dstAttr=${t.dstAttr}")
}) val sssp:Graph[Double,Double] = initialGraph.pregel(Double.PositiveInfinity)(
(vid, vidAttr, message) => math.min(vidAttr, message), // Vertex Program
triplet => {
// Send Message
if (triplet.srcAttr + triplet.attr < triplet.dstAttr) {
Iterator((triplet.dstId, triplet.srcAttr + triplet.attr))
} else {
Iterator.empty
}
},
(message_a, message_b) => math.min(message_a, message_b) // Merge Message
)
println("------------------------------")
//打印出计算结果
println(sssp.vertices.collect.mkString("\n"))
} /**
* 初始化图对象
*
* @return
*/
private def genGraph(): Graph[Long, Double] = {
val vertices: RDD[(VertexId, Long)] =
sc.parallelize(Array(
(1L, 0L),
(2L, 0L),
(3L, 0L),
(4L, 0L),
(5L, 0L),
(6L, 0L))
)
// Create an RDD for edges
val edges: RDD[Edge[Double]] =
sc.parallelize(Array(
Edge(1L, 2L, 1.0),
Edge(1L, 4L, 1.0),
Edge(1L, 5L, 1.0),
Edge(2L, 3L, 1.0),
Edge(4L, 3L, 1.0),
Edge(5L, 4L, 1.0),
Edge(3L, 6L, 1.0)
)
)
val graph: Graph[Long, Double] = Graph(vertices, edges, 0)
graph
} def main(args: Array[String]) {
shortestPath
}
}

spark Graph 的PregelAPI 理解和使用的更多相关文章

  1. Spark机器学习 Day2 快速理解机器学习

    Spark机器学习 Day2 快速理解机器学习 有两个问题: 机器学习到底是什么. 大数据机器学习到底是什么. 机器学习到底是什么 人正常思维的过程是根据历史经验得出一定的规律,然后在当前情况下根据这 ...

  2. Graph Cuts初步理解

    一些知识点的初步理解_8(Graph Cuts,ing...) Graph cuts是一种十分有用和流行的能量优化算法,在计算机视觉领域普遍应用于前背景分割(Image segmentation).立 ...

  3. spark rdd 宽窄依赖理解

    == 转载 == http://blog.csdn.net/houmou/article/details/52531205 Spark中RDD的高效与DAG图有着莫大的关系,在DAG调度中需要对计算过 ...

  4. 【Spark】Spark-reduceByKey-深入理解

    Spark-reduceByKey-深入理解 spark.apache.org_百度搜索 Apache Spark™ - Lightning-Fast Cluster Computing reduce ...

  5. 大话Spark(4)-一文理解MapReduce Shuffle和Spark Shuffle

    Shuffle本意是 混洗, 洗牌的意思, 在MapReduce过程中需要各节点上同一类数据汇集到某一节点进行计算,把这些分布在不同节点的数据按照一定的规则聚集到一起的过程成为Shuffle. 在Ha ...

  6. 对spark算子aggregateByKey的理解

    案例 aggregateByKey算子其实相当于是针对不同“key”数据做一个map+reduce规约的操作. 举一个简单的在生产环境中的一段代码 有一些整理好的日志字段,经过处理得到了RDD类型为( ...

  7. 通过案例对 spark streaming 透彻理解三板斧之二:spark streaming运行机制

    本期内容: 1. Spark Streaming架构 2. Spark Streaming运行机制 Spark大数据分析框架的核心部件: spark Core.spark  Streaming流计算. ...

  8. spark partition 理解 / coalesce 与 repartition的区别

    一.spark 分区 partition的理解: spark中是以vcore级别调度task的. 如果读取的是hdfs,那么有多少个block,就有多少个partition 举例来说:sparksql ...

  9. Spark(一): 基本架构及原理

    Apache Spark是一个围绕速度.易用性和复杂分析构建的大数据处理框架,最初在2009年由加州大学伯克利分校的AMPLab开发,并于2010年成为Apache的开源项目之一,与Hadoop和St ...

随机推荐

  1. Eclipse快捷键系列

    查看Eclipse自定义的快捷键或者自己定义快捷键的方式 Window --> preference --> general --> Keys 在光标所在行之后插入一行,省去了将光标 ...

  2. .net从网络接口地址获取json,然后解析成对象(一)

    整理代码,今天遇到一个问题,就是从一个场景接口获取json,然后解析成对象.之前的时候都好好的,这次返回的json字符串里,由于字符编码的问题,格式上不能转换.一直以为是解析的过程编码有误,试了utf ...

  3. wireshark源码分析 一

    因为手头的项目需要识别应用层协议,于是想到了wireshark,打算在项目中集成wireshark协议分析代码.在官网上下了最新版的wireshark源代码,我的天啊,200多M,这么多代码文件怎么看 ...

  4. spring学习 十一 AspectJ-based的通知入门 不带参数的通知

    AspectJ-Based方式的AOP,通知类不需要实现任何接口,且前置通知,后置通知,环绕通知,异常通知都可以写在一个类中,下面先实现一个简单的,不带参数的通知. 第一步定义通知类,通知类中的通知( ...

  5. setInterval与setTimeout 的区别

    setInterval在执行完一次代码之后,经过了那个固定的时间间隔,它还会自动重复执行代码,而setTimeout只执行一次那段代码     用法: setInterval("alert( ...

  6. 20155312 实验一《Java开发环境的熟悉》实验报告

    (一)命令行下Java程序开发 截图如下: 打印学号: 遇到的问题及 编译时如果还使用javac -d bin 文件名,就会出错 解决:package包是将编译文件放入指定包中 注意:代码中有pack ...

  7. vue父传子

    父组件传递数据给子组件用props,父组件中使用子组件,子组件用props接收父组件数据. Home父组件代码: <template> <div> {{test}} <! ...

  8. windows下 python2 和python3 共存

    目前我们在国内网站上看到的两者共存的方法就是将其中一个的python.exe重命名.虽说在一定程度上可行,但存在一个重大的隐患,就是修改了名字的那个python对应的pip将无法使用. 下面说一下具体 ...

  9. 利用url传多个参数

    刚开始接触jsp,比较偏向于用button标签的onclick方法进行页面的跳转.但是关于页面跳转的各种问题真是叫人头大,以下记录,仅仅为自己以后查看. Qone 用url传参的时候遇到中文怎么办 编 ...

  10. 第21章:MongoDB-聚合操作--聚合管道--$geoNear

    ①$geoNear 使用“$geoNear”可以得到附近的坐标点. ②范例:准备测试数据