Spark中完成图挖掘经常以GraphX作为工具,我们以金融领域中常见的集团派系图谱为例子,学习Spark完成图挖掘工作。
为了更直接表达,我们可以先看一张自己造的派系图谱。

转化成输入数据之后为:
实际控制关系为:
{"_from": 3,"_to": 1,"src_name": "尹明善","dst_name": "重庆力帆控股有限公司","attr": "实际控制"}
投资关系为:
{"_from": 1,"_to": 2,"src_name": "重庆力帆控股有限公司","dst_name": "力帆实业( 集团) 股份有限公司","ratio": 0.47}
{"_from": 2,"_to": 5,"src_name": "力帆实业( 集团) 股份有限公司","dst_name": "重庆力帆三轮摩托车有限公司","ratio": 0.51}
{"_from": 8,"_to": 7,"src_name": "中国长安汽车集团有限公司","dst_name": "重庆长安汽车股份有限公司","ratio": 0.19}
{"_from": 9,"_to": 10,"src_name": "不知名公司A","dst_name": "不知名公司B","ratio": 0.024}
任职关系为:
{"_from": 4,"_to": 2,"src_name": "牟刚","dst_name": "重庆力帆控股有限公司","attr": "法定代表人"}
{"_from": 6,"_to": 7,"src_name": "张宝林","dst_name": "重庆长安汽车股份有限公司","attr": "董事长"}
假设我们规定,投资比例 < 10%,那么该投资关系不被纳入集团派系中,那么代码为:
package com.zhangjunwei
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import org.json4s.jackson.JsonMethods.{parse}
import com.zhangjunwei.utils.Parser.getJsonValue
import org.apache.spark.graphx._
object GroupFaction {
def main(args: Array[String]): Unit = {
System.setProperty("hadoop.home.dir", "D:/winutils/")
val sparkConf = new SparkConf()
sparkConf.setAppName("GroupFaction")
sparkConf.setMaster("local")
val sparkContext = new SparkContext(sparkConf)
// 读取投资数据
val invest: RDD[String] = sparkContext.textFile("input/GroupFaction/invest")
// 读取任职数据
val officer: RDD[String] = sparkContext.textFile("input/GroupFaction/officer")
// 读取实际控制人数据
val actual_controller: RDD[String] = sparkContext.textFile("input/GroupFaction/actual_controller")
// 过滤投资比例 <= 10%的数据
val invest_relation: RDD[String] = invest.filter(line => {
val jv = parse(line)
val ratio = getJsonValue(jv, "ratio").toDouble
if (ratio > 0.1) true else false
})
// 聚合所有符合条件的关系
val relations: RDD[String] = invest_relation.union(officer).union(actual_controller)
// 构造GraphX中Edge对象
val edges = relations.map(relation => {
val jv = parse(relation)
val from = getJsonValue(jv, "_from").toLong
val to = getJsonValue(jv, "_to").toLong
Edge(from, to, relation)
})
// 根据边构造图
val graph: Graph[String, String] = Graph.fromEdges(edges, defaultValue = "")
// 获取联通分量
val connetedGraph: Graph[VertexId, String] = graph.connectedComponents()
// 将同一连通分量中各个边聚合
val tripleGroup: RDD[(VertexId, Set[EdgeTriplet[VertexId, String]])] = connetedGraph.triplets.map(t => (t.srcAttr, Set(t)))
.reduceByKey(_ ++ _).repartition(1)
// 对同一联通分量进行格式处理
val groups: RDD[(String, Set[String])] = tripleGroup.map { case (vertexId, edges) => {
val edges_attr: Set[String] = edges.map(e => e.attr)
("集团派系/" + vertexId.toString, edges_attr)
}
}
//保存结果
groups.saveAsTextFile("output/group")
}
}
这里的关键在于connectedComponents的算法。它会返回一个图中联通分量,其中vertexId为该联通分量中最小的顶点ID。
connectedComponents的算法原理使用pregel机制。关于pregel机制后期再做记录。
浙公网安备 33010602011771号