随笔 - 47  文章 - 0 评论 - 0 trackbacks - 0

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机制后期再做记录。

  

 

posted on 2020-03-10 22:18  知己一生  阅读(144)  评论(0编辑  收藏