GraphX 与 Spark 其他组件相比相对独立,拥有自己的核心数据结构与算子。

GraphX架构


GraphX的整体架构可以分为三个部分:

  • 算法层。基于 Pregel 接口实现了常用的图算法。包括 PageRank、SVDPlusPlus、TriangleCount、 ConnectedComponents、 StronglyConnectedConponents 等算法

  • 接口层。在底层 RDD 的基础之上实现了 Pregel 模型 BSP 模式的计算接口

  • 底层。图计算的核心类,包含:VertexRDD、EdgeRDD、RDD[EdgeTriplet]

GraphX存储模式

巨型图的存储总体上有边分割和点分割两种存储方式。2013年,GraphLab2.0将其存储方式由边分割变为点分割,在性能上取得重大提升,目前基本上被业界广泛接受并使用。

  • 边分割(Edge-Cut):每个顶点都存储一次,但有的边会被打断分到两台机器上。这样做的好处是节省存储空间;坏处是对图进行基于边的计算时,对于一条两个顶点被分到不同机器上的边来说,要跨机器通信传输数据,内网通信流量大

  • 点分割(Vertex-Cut):每条边只存储一次,都只会出现在一台机器上。邻居多的点会被复制到多台机器上,增加了存储开销,同时会引发数据同步问题。好处是可以大幅减少内网通信量


虽然两种方法互有利弊,但现在是点分割占上风,各种分布式图计算框架都将自己底层的存储形式变成了点分割。主要原因有以下两个:

  • 磁盘价格下降,存储空间不再是问题,而内网的通信资源没有突破性进展,集群计算时内网带宽是宝贵的,时间比磁盘更珍贵。这点就类似于常见的空间换时间的策略;

  • 在当前的应用场景中,绝大多数网络都是“无尺度网络”,遵循幂律分布,不同点的邻居数量相差非常悬殊。而边分割会使那些多邻居的点所相连的边大多数被分到不同的机器上,这样的数据分布会使得内网带宽更加捉襟见肘,于是边分割存储方式被渐渐抛弃了;

GraphX核心数据结构

核心数据结构包括:graph、vertices、edges、triplets

GraphX API 的开发语言目前仅支持 Scala。GraphX 的核心数据结构 Graph 由 RDD 封装而成。

Graph

GraphX 用属性图的方式表示图,顶点有属性,边有属性。存储结构采用边集数组的形式,即一个顶点表,一个边表,如下图所示:


顶点 ID 是非常重要的字段,它不光是顶点的唯一标识符,也是描述边的唯一手段。

顶点表与边表实际上就是 RDD,它们分别为 VertexRDD 与 EdgeRDD。在 Spark 的源码中,Graph 类如下:


  • vertices 为顶点表,VD 为顶点属性类型

  • edges 为边表,ED 为边属性类型

  • 可以通过 Graph 的 vertices 与 edges 成员直接得到顶点 RDD 与边 RDD

  • 顶点 RDD 类型为 VerticeRDD,继承自 RDD[(VertexId, VD)]

  • 边 RDD 类型为 EdgeRDD,继承自 RDD[Edge[ED]]

vertices

vertices对应着名为 VertexRDD 的RDD。这个RDD由顶点id和顶点属性两个成员变量。


VertexRDD继承自 RDD[(VertexId, VD)],这里VertexId表示顶点id,VD表示顶点所带的属性的类别。

VertexId 实际上是一个Long类型的数据。


edges

edges对应着EdgeRDD。这个RDD拥有三个成员变量,分别是源顶点id、目标顶点id以及边属性。


Edge代表边,由 源顶点id、目标顶点id、以及边的属性构成。


triplets

triplets 表示边点三元组,如下图所示(其中圆柱形分别代表顶点属性与边属性):


通过 triplets 成员,用户可以直接获取到起点顶点、起点顶点属性、终点顶点、终点顶点属性、边与边属性信息。triplets 的生成可以由边表与顶点表通过 ScrId 与 DstId 连接而成。

triplets对应着EdgeTriplet。它是一个三元组视图,这个视图逻辑上将顶点和边的属性保存为一个RDD[EdgeTriplet[VD, ED]]。