基于Spark GraphX的图形数据分析(一)
)
为什么需要图计算
- 许多大数据以大规模图或网络的形式呈现
- 许多非图结构的大数据,常会被转换为图模型进行分析
- 图数据结构很好地表达了数据之间的关联性
图(Graph)的基本概念
图是由顶点集合(vertex)及顶点间的关系集合(边edge)组成的一种网状数据结构
- 通常表示为二元组:Gragh=(V,E)
- 可以对事物之间的关系建模
应用场景
- 在地图应用中寻找最短路径
- 社交网络关系
- 网页间超链接关系
图的术语
顶点(Vertex)
边(Edge)
有向图
无向图
有环图
- 包含一系列顶点连接的回路(环路)
无环图
度
一个顶点所有边的数量
- 出度:指从当前顶点指向其他顶点的边的数量
- 入度:其他顶点指向当前顶点的边的数量
图的经典表示法
邻接矩阵
1、对于每条边,矩阵中相应单元格值为1
2、对于每个循环,矩阵中相应单元格值为2,方便在行或列上求得顶点度数
Spark GraphX 简介
- GraphX是Spark提供分布式图计算API
- GraphX特点
(1)基于内存实现了数据的复用与快速读取
(2)通过弹性分布式属性图(Property Graph)统一了图视图与表视图
(3)与Spark Streaming、Spark SQL和Spark MLlib等无缝衔接
GraphX核心抽象
弹性分布式属性图(Resilient Distributed Property Graph)
-
顶点和边都带属性的有向多重图
-
一份物理存储,两种视图
对Graph视图的所有操作,最终都会转换成其关联的Table视图的RDD操作来完成
GraphX API
- Graph[VD,ED]
- VertexRDD[VD]
- EdgeRDD[ED]
- EdgeTriplet[VD,ED]
- Edge:样例类
- VertexId:Long的别名
创建Graph
class Graph[VD, ED] {
val vertices: VertexRDD[VD]
val edges: EdgeRDD[ED]
val triplets: RDD[EdgeTriplet[VD, ED]]
}
import org.apache.spark.graphx.GraphLoader
//加载边列表文件创建图,文件每行描述一条边,格式:srcId dstId。顶点与边的属性均为1
val graph =GraphLoader.edgeListFile(sc,"file:///opt/spark/data/graphx/followers.txt")
import org.apache.spark.graphx._
val vertices:RDD[(VertexId,Int)]=sc.makeRDD(Seq((1L,1),(2L,2),(3L,3)))
val edges=sc.makeRDD(Seq(Edge(1L,2L,1),Edge(2L,3L,2)))
val graph=Graph(vertices,edges) //Graph[Int,Int] ?
属性图应用示例
构建用户合作关系属性图
(1)顶点属性
- 用户名
- 职业
(2)边属性
- 合作关系
val userGraph: Graph[(String, String), String]
构建用户社交网络关系
- 顶点:用户名、年龄
- 边:打call次数
找出大于30岁的用户
假设打call超过5次,表示真爱。请找出他(她)们
val vertexArray = Array(
(1L, ("Alice", 28)),
(2L, ("Bob", 27)),
(3L, ("Charlie", 65)),
(4L, ("David", 42)),
(5L, ("Ed", 55)),
(6L, ("Fran", 50))
)
val edgeArray = Array(
Edge(2L, 1L, 7),
Edge(2L, 4L, 2),
Edge(3L, 2L, 4),
Edge(3L, 6L, 3),
Edge(4L, 1L, 1),
Edge(5L, 2L, 2),
Edge(5L, 3L, 8),
Edge(5L, 6L, 3)
)
val vertexRDD: RDD[(Long, (String, Int))] = sc.parallelize(vertexArray)
val edgeRDD: RDD[Edge[Int]] = sc.parallelize(edgeArray)
val graph: Graph[(String, Int), Int] = Graph(vertexRDD, edgeRDD)
// Solution 1
graph.vertices.filter { case (id, (name, age)) => age > 30 }.collect.foreach {
case (id, (name, age)) => println(s"$name is $age")
}
// Solution 2
graph.vertices.filter(v => v._2._2 > 30).collect.foreach(v => println(s"${v._2._1} is ${v._2._2}"))
// Solution 3
for ((id,(name,age)) <- graph.vertices.filter { case (id,(name,age)) => age > 30 }.collect) {
println(s"$name is $age")
}
for (triplet <- graph.triplets.collect) {
println(s"${triplet.srcAttr._1} likes ${triplet.dstAttr._1}")
}
for (triplet <- graph.triplets.filter(t => t.attr > 5).collect) {
println(s"${triplet.srcAttr._1} loves ${triplet.dstAttr._1}")
}
查看图信息
- 顶点数量
- 边数量
- 度、入度、出度
class Graph[VD, ED] {
val numEdges: Long
val numVertices: Long
val inDegrees: VertexRDD[Int]
val outDegrees: VertexRDD[Int]
val degrees: VertexRDD[Int]
}