在GraphX中删除没有传出边的顶点

时间:2018-05-15 09:29:22

标签: scala apache-spark spark-graphx

我有一个大图(几百万个顶点和边)。我想删除没有传出边的所有顶点(&边)。我有一些有效的代码,但它很慢,我需要做几次。我相信我可以使用一些现有的GraphX方法来加快它的速度。

这是我的代码。

val users: RDD[(VertexId, String)] = sc.parallelize(Array((1L, "1"), (2L, "2"), (3L, "3"), (4L, "4")))
  val relationships: RDD[Edge[Double]] = sc.parallelize(
    Array(
      Edge(1L, 3L, 500.0),
      Edge(3L, 2L, 400.0),
      Edge(2L, 1L, 600.0),
      Edge(3L, 1L, 200.0),
      Edge(2L, 4L, 200.0),
      Edge(3L, 4L, 500.0)
    ))

val graph = org.apache.spark.graphx.Graph(users, relationships)

val lst = graph.outDegrees.map(x => x._1).collect
var set:scala.collection.mutable.HashSet[Long] = new scala.collection.mutable.HashSet()
for(a<- lst) {set.add(a)}
var subg = graph.subgraph(vpred = (id, attr) => set.contains(id))
//since vertex 4 has no outgoing edges, subg.edges should return 4 and subg.vertices = 3 

我不知道如何实现这一目标。任何帮助表示赞赏!

编辑:我可以使用HashSet完成它,但我认为它仍然可以改进。

4 个答案:

答案 0 :(得分:0)

对代码的第一个优化是使lst成为一个集而不是一个数组,这将使查找O(1)而不是O(n)

但是这不可扩展,因为您正在收集驱动程序上的所有内容,然后将其发送回执行程序。正确的方法是使用joinVertices致电outDegrees,然后映射到原始图表。

答案 1 :(得分:0)

您可以使用过滤的顶点直接定义另一个图形。 像这样:

val lst = graph.outDegrees.map(x => x._1).collect
var graph2 = Graph(graph.vertices.filter(v => lst.contains(v)), graph.edges)

答案 2 :(得分:0)

如果您不想使用子图,这是使用三元组查找那些也是源顶点的目标顶点的另一种方法。

val graph = org.apache.spark.graphx.Graph(users, relationships)
val AsSubjects = graph.triplets.map(triplet => (triplet.srcId,(triplet)))
val AsObjects = graph.triplets.map(triplet => (triplet.dstId,(triplet)))
val ObjectsJoinSubjects = AsObjects.join(AsSubjects)
val ObjectsJoinSubjectsDistinct = ObjectsJoinSubjects.mapValues(x => x._1).distinct()
val NewVertices = ObjectsJoinSubjectsDistinct.map(x => (x._2.srcId, x._2.srcAttr)).distinct()
val NewEdges = ObjectsJoinSubjectsDistinct.map(x => new Edge(x._2.srcId, x._2.dstId, x._2.attr))
val newgraph = Graph(NewVertices,NewEdges)

我不确定这是否比子图提供了改进,因为我的解决方案使用了很昂贵的distinct()。我使用您提供的图表进行测试,我的解决方案实际上需要更长时间。但是,我觉得这是一个小例子。因此,我建议您使用更大的图表进行测试,并告诉我们这是否更好。

答案 3 :(得分:0)

你可以通过这个来找到所有的零度退出验证。

val zeroOutDeg = graph.filter(graph => {
   val degrees: VertexRDD[Int] = graph.outDegrees
   graph.outerJoinVertices(degrees) {(vid, data, deg => deg.getOrElse(0)}
   }, vpred = (vid: VertexId, deg:Int) => deg == 0)