2015-05-25 4 views
7

Wie Subgraph-Funktion verwenden, um ein Diagramm zu erhalten, das nur Scheitelpunkte und Kanten von der bestimmten verbundenen Komponente enthalten würde? Nehmen wir an, ich kenne die ID der verbundenen Komponente, das Endziel ist die Erstellung eines neuen Graphen basierend auf der verbundenen Komponente. Ich möchte die Scheitelpunktattribute vom ursprünglichen Diagramm beibehalten.Apache Spark GraphX ​​verbundene Komponenten

Antwort

6

Sie müssen das Diagramm mit den Komponenten-IDs an das ursprüngliche Diagramm anfügen, filtern (den Untergraphen verwenden) anhand der Komponenten-ID und verwerfen dann die Komponenten-ID.

import scala.reflect._ 
import org.apache.spark.graphx._ 
import org.apache.spark.graphx.lib.ConnectedComponents 

def getComponent[VD: ClassTag, ED: ClassTag](
    g: Graph[VD, ED], component: VertexId): Graph[VD, ED] = { 
    val cc: Graph[VertexId, ED] = ConnectedComponents.run(g) 
    // Join component ID to the original graph. 
    val joined = g.outerJoinVertices(cc.vertices) { 
    (vid, vd, cc) => (vd, cc) 
    } 
    // Filter by component ID. 
    val filtered = joined.subgraph(vpred = { 
    (vid, vdcc) => vdcc._2 == Some(component) 
    }) 
    // Discard component IDs. 
    filtered.mapVertices { 
    (vid, vdcc) => vdcc._1 
    } 
} 
+0

Danke für diese Funktion! Aber können wir nicht davon ausgehen, dass, wenn Sie die CC-ID haben, Sie wahrscheinlich bereits das CC konstruiert haben, so dass dieses als eines der 'getComponent'-Argumente eingezogen werden kann, was die potentiell teure Aufgabe der Neuberechnung speichert. Ich bin neugierig, warum diese Funktion funktioniert, aber wenn ich die Schritte manuell manuell ein "Long" oder was auch immer in als die "Komponente" setzen, schlägt es fehl. Muss es "Some" oder "VertexId" sein? – SpmP

+0

Sie haben recht - jetzt, wo ich es anschaue, ist es ziemlich seltsam, wie wir eine Komponenten-ID haben würden, bevor wir 'ConnectedComponents' ausführen. Ich glaube, ich wollte nur 'ConnectedComponents' irgendwo hin mitnehmen. Ich werde den Code überarbeiten, um vernünftiger zu sein. Für Ihre andere Frage: 'VertexId' ist ein Alias ​​für' Long'. Eine einfache alte Nummer sollte dort funktionieren. Was meinst du mit "scheitert" hier? Hast du eine Ausnahme? –

+0

Wissen Sie, wie man die Anzahl der verbundenen Komponenten in einem Graphen zählt? – ELI

2

Ich nehme Ihre Frage zu sein, ein VertexId in einem Quelldiagramm gegeben, ein neues Diagramm mit den Knoten erstellen und Kanten zu diesem VertexId aus dem Quelldiagramm verbunden.

Da, hier ist was ich tun würde:

val targetVertexId = ... 
val graph = Graph(..., ...) 
val newGraph = Graph(
    graph.vertices.filter{case (vid,attr) => vid == targetVertexId} ++ 
    graph.collectNeighbors(EdgeDirection.Either) 
    .filter{ case (vid,arr) => vid == targetVertexId} 
    .flatMap{ case (vid,arr) => arr}, 
    graph.edges 
).subgraph(vpred = { case (vid,attr) => attr != null}) 

paar Dinge zu beachten:

Sie EdgeDirection.Either-EdgeDirection.In oder EdgeDirection.Out nach Bedarf ändern können.

Die .subgraph am Ende entfernt alle Scheitelpunkte, für die das Attribut auf null festgelegt ist. Wenn das Original val graph Scheitelpunkte mit Attributen hat, die auf null festgelegt sind, wird dies nicht funktionieren. Ansonsten funktioniert das, ohne den Vertex-Attributtyp im Voraus kennen zu müssen.