GraphX中顶点和边的RDD操作

  GraphX 公开了存储在图中的顶点和边的 RDD 视图。但是,由于 GraphX 在优化的数据结构中维护了顶点和边,并且这些数据结构提供了额外的功能,所以顶点和边分别返回为 VertexRDDVertexRDD 和 EdgeRDDEdgeRDD。

一、顶点RDD(VertexRDDs)

  VertexRDD[A] 扩展了 RDD[(VertexId, A)] 并添加了每个 VertexId 仅出现一次的附加约束。此外,VertexRDD[A] 表示一组顶点,每个顶点都具有类型 A 的属性。在内部,这是通过将顶点属性存储在可重用的哈希映射数据结构中来实现的。因此,如果两个 VertexRDD 是从相同的基础 VertexRDDVertexRDD 派生的(例如,通过 filter 或 mapValues),它们可以在恒定时间内连接,而无需哈希评估。为了利用这种索引数据结构,VertexRDDVertexRDD 开源了以下附加功能:

class VertexRDD[VD] extends RDD[(VertexId, VD)] {
  // 过滤顶点集但保留内部索引
  def filter(pred: Tuple2[VertexId, VD] => Boolean): VertexRDD[VD]

  // 在不更改 id 的情况下转换值(保留内部索引) 
  def mapValues[VD2](map: VD => VD2): VertexRDD[VD2]
  def mapValues[VD2](map: (VertexId, VD) => VD2): VertexRDD[VD2]

  // 根据 VertexId 显示此集合唯一的顶点
  def minus(other: RDD[(VertexId, VD)])

  // 从这个集合中删除出现在另一个集合中的顶点 
  def diff(other: VertexRDD[VD]): VertexRDD[VD]

  // 利用内部索引来加速连接的连接运算符
  def leftJoin[VD2, VD3](other: RDD[(VertexId, VD2)])(f: (VertexId, VD, Option[VD2]) => VD3): VertexRDD[VD3]
  def innerJoin[U, VD2](other: RDD[(VertexId, U)])(f: (VertexId, VD, U) => VD2): VertexRDD[VD2]

  // 使用这个 RDD 上的索引来加速对输入 RDD 的 `reduceByKey` 操作。 
  def aggregateUsingIndex[VD2](other: RDD[(VertexId, VD2)], reduceFunc: (VD2, VD2) => VD2): VertexRDD[VD2]
}

  例如,请注意过滤器运算符如何返回 VertexRDD。 过滤器实际上是使用 BitSet 实现的,从而重用索引并保留与其他 VertexRDD 进行快速连接的能力。 同样,mapValues 运算符不允许 map 函数更改 VertexId,从而可以重用相同的 HashMap 数据结构。 leftJoin 和 innerJoin 都能够识别何时连接来自同一个 HashMap 的两个 VertexRDD,并通过线性扫描而不是昂贵的点查找来实现连接。

  aggregateUsingIndex 运算符对于从 RDD[(VertexId, A)] 高效构造新的 VertexRDD 很有用。 从概念上讲,如果我在一组顶点上构造了一个 VertexRDD[B],它是某些 RDD[(VertexId, A)] 中顶点的超集,那么我可以重用索引来聚合,然后索引 RDD[(VertexId, A)]。 例如:

val setA: VertexRDD[Int] = VertexRDD(sc.parallelize(0L until 100L).map(id => (id, 1)))
val rddB: RDD[(VertexId, Double)] = sc.parallelize(0L until 100L).flatMap(id => List((id, 1.0), (id, 2.0)))
// rddB有200个节点
rddB.count
val setB: VertexRDD[Double] = setA.aggregateUsingIndex(rddB, _ + _)
//  setB有100个节点
setB.count
// 现在加入A和B会很快
val setC: VertexRDD[Double] = setA.innerJoin(setB)((id, a, b) => a + b)

 

 

二、边RDD(EdgeRDDs)

  扩展 RDD[Edge[ED]] 的 EdgeRDD[ED] 将边缘组织在使用 PartitionStrategy 中定义的各种分区策略之一进行分区的块中。 在每个分区内,边缘属性和邻接结构分别存储,以便在更改属性值时最大限度地重复使用。

  EdgeRDDEdgeRDD 开源的三个附加功能是:

// 在保留结构的同时变换边缘属性
def mapValues[ED2](f: Edge[ED] => ED2): EdgeRDD[ED2]
// 反转边重用属性和结构
def reverse: EdgeRDD[ED]
// 加入两个使用相同分区策略分区的 `EdgeRDD`。
def innerJoin[ED2, ED3](other: EdgeRDD[ED2])(f: (VertexId, VertexId, ED, ED2) => ED3): EdgeRDD[ED3]

  在大多数应用程序中,我们发现对 EdgeRDD 的操作是通过图运算符完成的,或者依赖于 RDD 基类中定义的操作。

posted @ 2022-03-03 16:46  干了这瓶老干妈  阅读(258)  评论(0编辑  收藏  举报
Live2D