查找特定节点的连接组件而不是整个图形(GraphFrame / GraphX)

时间:2016-05-26 14:41:45

标签: apache-spark spark-dataframe spark-graphx graphframes

我在Spark中创建了一个GraphFrame,图表目前看起来如下:

基本上,会有很多这样的子图,其中每个子图将彼此断开连接。给定一个特定的节点ID,我想找到子图中的所有其他节点。例如,如果给出节点ID 1,则图形将遍历并返回2,10,20,3,30。

我创造了一个主题,但它没有给出正确的结果。

testgraph.find("(a)-[]->(b); (c)-[]->(b)").filter("(a.id = '1')").show()

不幸的是,连通组件功能会考虑整个图表。是否可以使用 GraphFrame / GraphX 获取给定特定节点ID的断开连接的子图中的所有节点?

1 个答案:

答案 0 :(得分:0)

可以使用BFS遍历来获取与特定顶点相关的连接组件,该遍历从该顶点开始,并在多个跃点上收集其所有邻居。 这可以通过GraphX提供的Pregel API轻松完成,我们应该在其中实现一个vertexProgram,sendMessage和mergeMes​​sages函数。该算法在收到初始消息时触发。中心向邻居发送一条消息,该消息将传播到邻居,依此类推,直到覆盖连接的组件。每个接收到味精的顶点都会被检查,以免在以后的迭代中被激活。

这是此方法的实现:

import org.apache.spark.graphx._
import org.apache.spark.{SparkConf, SparkContext}

object ConnectedComponent extends  Serializable {

    def main(args = Array[String]) = {
        
        val conf = new SparkConf().setAppName("ConnectedComponent").setMaster("local")
        val sc = new SparkContext(conf)
        val vRDD = sc.objectFile[(VertexId,Int)]("/path/to/vertex/rdd/file/")
        val eRDD = sc.objectFile[Edge[Int]]("/path/to/edge/rdd/file/")
        val graph = Graph(vRDD, eRDD)
        val centerOfCC = graph.pickRandomVertex()
        var cc = extractCC(graph, center)
        cc.vertices.collect.foreach(println)

        sc.stop()
    }

    def extractCC(g: Graph[Int, Int], center: VertexId): Graph[Int, Int] = {
        /* Return a subgraph of the input graph containing 'center'  with the connected component
         */
        val initialGraph = g.mapVertices((id, attr) => VertexData(attr, false, false, center))
        val connectedComponent = initialGraph.pregel(initialMsg = 0)(vprog, sendMsg, mergeMsgs)
                                .subgraph(vpred = (id, attr) => attr.checked == true)
                                .mapVertices((id, vdata) => vdata.attr)
        connectedComponent
    }


    case class VertexData( var attr : Int, // label of the vertex
                    var checked : Boolean, // check visited vertices 
                    var propagate : Boolean, // allow forwarding msgs or not
                    var center: VertexId) // ID of the connectedComponent center
    def vprog(id:VertexId, vdata: VertexData, msg: Int): VertexData = {

        val attr : Int = vdata.attr 
        var checked : Boolean = vdata.checked
        var propagate : Boolean = vdata.propagate
        val center : VertexId = vdata.center

        if (checked==false && msg == 0 && id==center) {
          propagate = true
          checked = true
        }
        else if(checked==false && msg == 1) {
          propagate = true
          checked = true
        }
        else if(checked == true && msg == 1){
          propagate = false
        }
        new VertexData(attr, checked, propagate, center)
    }

    def sendMsg(triplet: EdgeTriplet[VertexData, Int]):Iterator[(VertexId, Int)] = {
        var it : Iterator[(VertexId, Int)] = Iterator()
        if(triplet.dstAttr.propagate==true)
          it = it ++ Iterator((triplet.srcId, 1))
        if(triplet.srcAttr.propagate==true)
          it = it ++ Iterator((triplet.dstId, 1))
        it
    }

    def mergeMsgs(a: Int, b: Int): Int = math.max(a, b)
}
相关问题