弹性分布式属性图
GraphX的核心抽象是弹性分布式属性图,它是一个有向多重图,带有连接到每个顶点和边的用户定义的对象。 有向多重图中多个并行的边共享相同的源和目的顶点。属性图扩展了Spark RDD的抽象,有Table和Graph两种视图,但是只需要一份物理存储。两种视图都有自己独有的操作符,从而使我们同时获得了操作的灵活性和执行的高效率。
GraphX图的分布式存储采用点分割模式(每条边只存储在一台机器上),用三个RDD存储图数据信息。
1.VertexTable(id, data):id为顶点id, data为顶点属性
2.EdgeTable(pid, src, dst, data):pid 为分区id ,src为源顶点id ,dst为目的顶点id,data为边属性
3.RoutingTable(id, pid):id 为顶点id ,pid 为分区id
图的构建
GraphX的Graph对象是用户操作图的入口。构建图的过程分为三步:构建边EdgeRDD、构建顶点VertexRDD、生成Graph对象。
通过调用GraphImpl的apply方法来构建Graph。
构建边RDD:
在apply调用fromEdgeRDD之前,代码会调用EdgeRDD.fromEdges构建边RDD,分区优化。
遍历RDD[Edge[ED]]每个分区并调用toEdgePartition对分区内的边作相应处理。
toEdgePartition():对边进行排序(按srcId),排序是为了遍历时顺序访问,加快访问速度;填充localSrcIds, localDstIds, data, index, global2local, local2global, vertexAttrs;可以通过根据本地下标取取VertexId,也可以根据VertexId取本地下标,取相应的属性。
构建顶点RDD:
在代码会调用了EdgeRDD.fromEdges后,边RDD就构建完成,此时apply调用fromEdgeRDD中的VertexRDD.fromEdges来构建顶点RDD。
构建的过程如下:
1.创建路由表:根据EdgeRDD,map其分区,对edge partition中的数据转换成RoutingTableMessage数据结构,一个包含vid和int的tuple(VertexId, Int)。 int的32~31位表示一个标志位(01: isSrcId 10: isDstId),30~0位表示边分区ID
2.根据路由表生成分区对象vertexPartitions。在新分区中,map分区中的每条数据,从RoutingTableMessage解出数据:vid, edge pid, isSrcId/isDstId。这个三个数据项重新封装到三个数据结构中:pid2vid,srcFlags,dstFlags
3.生成ShippableVertexPartition:上面routingTables, 重新封装路由表里的数据结构为:ShippableVertexPartition
4.创建VertexRDDImpl对象new VertexRDDImpl(vertexPartitions)
生成Graph对象:
把edgeRDD和vertexRDD拿过来组成Graph GraphImpl(vertices, new ReplicatedVertexView(edges.asInstanceOf[EdgeRDDImpl[ED, VD]]))