使用 GraphX 从二分网络创建单分图

Creating unipartite graph from bipartite network with GraphX

我正在试验 Spark,我是 Scala 和 GraphX 的新手。

我正在研究一个由电影和其中的演员组成的双向网络。 我的输入是一个 space 分隔的文件,每行一条边,第一列是电影 ID,第二列是演员 ID,这里是摘录:

movie actor
1 1 
2 1 
2 2 
3 1 
3 3 
3 4 
3 5 
3 6 
3 7 
4 1 

我的目标是研究演员之间的关系。为此,我想创建一个单分图演员-演员,其边缘值取决于这些演员的常见电影数量。

我首先创建一个边 RDD :

val edges: RDD[Edge[String]] = sc.textFile("file:///home/actorMovie").map { line =>
    val fields = line.split(" ")
    Edge(fields(0).toLong, fields(1).toLong)
  }

看起来不错:

edges.take(10)
res8: Array[org.apache.spark.graphx.Edge[String]] = Array(Edge(1,1,null), Edge(2,1,null), Edge(2,2,null), Edge(3,1,null), Edge(3,3,null), Edge(3,4,null), Edge(3,5,null), Edge(3,6,null), Edge(3,7,null), Edge(4,1,null))

然后从那里开始,我不知道如何将其转换为加权单部图。

您现在拥有的不是二分图。要使其成为有效的图形,您必须进行大量转换。最简单的方法是使用数据帧:

val df = spark.read
  .option("delimiter", " ") // if there is a header
  .option("header", "true")
  .csv(path)
  .toDF("movie", "actor")

一旦你像这样自连接和聚合数据:

import org.apache.spark.sql.functions._

val e = df.alias("df1")
  .join(df.alias("df2"), "movie")
  // Sort soruce and destination
  .groupBy(
     greatest("df1.actor", "df2.actor").as("srcId"), 
     least("df1.actor", "df2.actor").as("dstId"))
  .agg(count("*").as("attr"))

这可以转换为 GraphGraphFrame,正如我在此处显示的那样

要创建有效的图表,您必须对标签进行编码。例如:

val dfe = df.select(
  concat(lit("m"), $"movie").as("movie"),
  concat(lit("a"), $"actor").as("actor"))

然后您可以按照 or use GraphFrame 中的说明应用 StringIndexer 来自动执行此操作:

import graphframes._

val gf = GraphFrame.fromEdges(dfe.toDF("src", "dst"))

然后你可以使用消息传递或图形模式匹配来找到两跳邻居。