【大数据分析】k-cores,一种基于图数据结构的分解方法

本文介绍了k-cores分解方法,用于处理大型图数据结构,通过选取度大于等于k的节点来构建子图。详细阐述了k-cores的概念,并提供了基于Scala和GraphX的Pregel算法实现过程。

参考

《An O(m) Algorithm for Cores Decomposition of Networks》

介绍

为了能够更好的处理大型图数据结构,有时需要将其按照要求进行分解,而k-cores便是其中一种方法。它可以从一个相对较大的图网络得到一个子图,这个子图中的所有节点的度都大于等于k。如下所示:
在这里插入图片描述

假设以上是一个由节点集 V V V ,和边集 E E E 组成的图 G = ( V , E ) G=(V,E) G=(V,E) ,外部不同颜色深度的“圈”所包含的子图,代表着计算不同k值时对应得到的子图 G s u b g r a p h , k G_{subgraph,k} Gsubgraph,k 。例如:

(1)当 k = 0 k=0 k=0 时,图 G G G 所有的节点和边都作为子图 G s u b g r a p h , 0 G_{subgraph,0} Gsubgraph,0 的节点和边。因为所有点的degree(度,包含入度和出度),都大于等于0.
(2)当 k = 1 k=1 k=1 时,可以看到右下角的那个点被排除在外,剩下部分的节点的degree都大于等于1
(3)当 k = 2 k=2 k=2 时,计算方法跟前面的类似,但是有一些需要注意的规则。例如上图中绿色箭头所指的节点 A A A,它的degree为1,所以它将会排除在 G s u b g r a p h , 2 G_{subgraph,2} Gsubgraph,2 之外。节点 B B B(红色箭头所指)由于 A A A 被排除而失去一个degree,此时它的degree等于2,这个2才是作为判断 B B B 是否 G s u b g r a p h , 2 G_{subgraph,2} Gsubgraph,2 中的标准。
(4)当 k = 3 k=3 k=3 时,同理。

所以,所谓 k k k 可以简单理解为与节点的degree相关的变量。

代码实现

算法的基本流程如下:
1、激活所有的节点。
2、针对所有激活节点相关的三元组( S → T S\rightarrow T ST ),计算 S S S T T T 的degree,分四种情况考虑。
(1)如果 S S S T T T 的 degree 都小于 0,将它们设置为deactivated状态。不发送消息。
(2)如果 S S S T T T 的 degree 都小于 k k k ,将它们的degree置为 -1。发送消息。
(3)如果 S S S(或 T T T)的degree小于 k k k ,将它的degree置为-1,而 T T T(或 S S S)的degree减去1。发送消息。
(4)如果 S S S T T T 的 degree 都大于 0,将它们设置为deactivated状态。不发送消息。
3、重复 2,直到没有激活节点。
4、使用mask得到子图
这里依然基于GraphX和Pregel来实现该算法。Pregel机制的原理可以参考《【大数据分析】基于Graphx的shortestpath源码解析》来理解。

package com.edata.bigdata.algorithm.networks

import org.apache.spark.graphx.{EdgeTriplet, Graph, Pregel, VertexId}
import scala.reflect.ClassTag

object KCores extends Serializable {

  type MsgType = Int
  private[this] var _core_num: MsgType = 0

  def core_num: MsgType = _core_num

  def core_num_=(value: MsgType): Unit = {
    _core_num = value
  }


  private def makeMsg(x: Int) = x

  def mergeMsg(msg1: MsgType, msg2: MsgType): MsgType = {
    if (msg1 < 0 || msg2 < 0) {
      -1
    } else {
      msg1 + msg2
    }
  }

  def sendMsg(edge: EdgeTriplet[MsgType, _]): Iterator[(VertexId, MsgType)] = {
    if (edge.srcAttr < 0 || edge.dstAttr < 0) {
      Iterator.empty
    } else if (edge.srcAttr < core_num && edge.dstAttr < core_num) {
      Iterator((edge.srcId, -1), (edge.dstId, -1))
    } else if (edge.srcAttr < core_num) {
      Iterator((edge.srcId, -1), (edge.dstId, 1))
    } else if (edge.dstAttr < core_num) {
      Iterator((edge.dstId, -1), (edge.srcId, 1))
    } else {
      Iterator.empty
    }
  }

  def vertexProgram(id: VertexId, attr: MsgType, msg: MsgType): MsgType = {
    if (msg < 0) {
      -1
    } else {
      math.max(attr - msg, 0)
    }
  }

  def run[VD, ED: ClassTag](graph: Graph[VD, ED],k:Int):Graph[VD,ED] = {
    core_num = k
    val g = graph.mapVertices {(vid, attr)=>
    }
    val KCGraph = g.outerJoinVertices(g.degrees)((vid, attr, newData) => newData.getOrElse(0))
    val initialMessage = makeMsg(0)
    val pregel_graph = Pregel(KCGraph, initialMessage)(vertexProgram, sendMsg, mergeMsg)
    val pregel_subgraph = pregel_graph.subgraph(vpred = (vid,v)=>v>0)
    graph.mask(pregel_subgraph)
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值