基于GraphX从二分网络构建加权演员单分图的技术求助
从电影-演员二分图转换为演员加权单分图
刚上手Spark、Scala和GraphX的话,从电影-演员二分图转成演员间的加权单分图确实需要几个关键步骤,我来帮你拆解清楚,一步步实现:
首先要注意,你当前的代码没有过滤表头行(示例里的movie actor),导致生成了一条无效的Edge(1,1,null),所以第一步先修正数据读取:
1. 读取并清洗原始数据
先过滤掉表头,把数据转换成(电影ID, 演员ID)的键值对RDD:
import org.apache.spark.graphx.{Edge, Graph} // 读取文件,过滤表头行,生成(movieId, actorId)的RDD val movieActorPairs = sc.textFile("file:///home/actorMovie") .filter(line => !line.startsWith("movie")) // 跳过表头 .map(line => { val fields = line.split(" ") (fields(0).toLong, fields(1).toLong) })
2. 按电影分组生成演员列表
接下来,把同一个电影的所有演员聚合到一起,这样我们就能找到每部电影里的演员组合:
// 按电影ID分组,得到每个电影对应的所有演员ID集合 val movieActors = movieActorPairs.groupByKey()
3. 生成演员两两组合
对每部电影的演员列表,生成所有无序的演员对(比如演员A和B,只生成一次(A,B)而不是(A,B)和(B,A)),避免后续重复统计:
// 遍历每个电影的演员列表,生成i<j的演员对 val actorPairs = movieActors.flatMap { case (_, actors) => val actorList = actors.toList // 双重循环生成所有不重复的演员对 for { i <- actorList.indices j <- i + 1 until actorList.size } yield { val (a1, a2) = (actorList(i), actorList(j)) // 保证对的顺序统一,避免(A,B)和(B,A)被当成不同的对 if (a1 < a2) (a1, a2) else (a2, a1) } }
4. 统计共同参演次数(边的权重)
现在每对演员每共同参演一部电影就会出现一次,我们只需要统计每对的出现次数,这个次数就是边的权重:
// 统计每对演员的共同参演电影数 val weightedActorPairs = actorPairs .map(pair => (pair, 1)) // 给每个对标记计数1 .reduceByKey(_ + _) // 按对聚合,累加计数
5. 构建演员加权单分图
最后把统计后的结果转换成GraphX的Edge结构,构建单分图:
// 转换为GraphX的Edge,权重是共同参演次数 val actorEdges = weightedActorPairs.map { case ((srcId, dstId), weight) => Edge(srcId, dstId, weight) } // 构建演员单分图,defaultValue是顶点的默认属性(可以根据需求修改,比如演员名字等) val actorGraph = Graph.fromEdges(actorEdges, defaultValue = 0)
验证结果
你可以通过以下代码查看生成的边:
actorEdges.collect().foreach(println)
针对你的示例数据,输出应该类似:
Edge(1,2,1) Edge(1,3,1) Edge(1,4,1) Edge(1,5,1) Edge(1,6,1) Edge(1,7,1) Edge(3,4,1) Edge(3,5,1) ...
比如Edge(1,2,1)表示演员1和2共同参演了1部电影(就是电影2),完全符合你的需求。
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

