Spark GraphX初探
1. Graphx概念
针对某些领域,如社交网络、语言建模等,graph-parallel系统可以高效地执行复杂的图形算法,比一般的data-parallel系统更快。

Graphx是将graph-parallel的data-parallel统一到一个系统中。允许用户将数据当成一个图或一个集合RDD,而简化数据移动或复杂操作。

2. 属性图
属性图为有向多重图,带有链接到每个顶点和边的用户定义的对象。有向多重图多个并行的边共享相同源和目的地顶点。每个顶点由一个唯一的64位长的标识符(VertexId)作为key,顶点拥有相同的源和目的顶点标识符。
属性图通过vertex(VD)和edge(ED)类型参数化,分别与每个顶点和边相关联的对象的类型。某些情况下,相同图形中希望顶点拥有不同属性类型,可通过继承实现。
class VertexProperty()
case class UserProperty(val name: String) extends VertexProperty
case class ProductProperty(val name: String, val price: Double) extends VertexProperty var grapg: Graph[VertexProperty, String] = null
与RDD类似,属性图是不可变、分布式、容错的。图中的值或结构变化需要生成新的图实现。注意:原始图中的大部分可以在新图中重用,以减少固有功能数据结构成本。
逻辑上,属性图对应一对类型化的集合RDD,包含了每一个顶点和边属性。
class Graph[VD, ED]{
val vertices: VertexRDD[VD]
val edges: EdgeRDD[ED]
}
VertexRDD[VD]和EdgeRDD[ED]分别继承于RDD[(VertexID, VD)]和RDD[Edge[ED]]。
Graph也包含一个三元组视图,三元组视图逻辑上将顶点和边的属性保存为一个RDD[EdgeTriplet[VD, ED]],EdgeTriplet可通过下图理解。

EdgeTriplet继承于Edge类,并加入srcAttr和dstAttr成员,分别包含源和目标的属性。
例:
import org.apache.spark.graphx.{Edge, Graph, VertexId}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
class GraphTest1 {
def main(args: Array[String]): Unit = {
val sc = new SparkContext(new SparkConf().setAppName("GraphTest1"))
// 创建顶点信息
val users: RDD[(VertexId, (String, String))] = sc.parallelize(
Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")), (5L, ("franklin", "prof")), (2L, ("istoica", "prof")))
)
// 创建图的Edge类,Edge类具有srcId和dstId分别对应与源和目标点的标识符,次明早attr成员存储边属性
val relationships: RDD[Edge[String]] = sc.parallelize(
Array(Edge(3L, 7L, "collab"), Edge(5L, 3L, "advisor"), Edge(2L, 5L, "colleague"), Edge(5L, 7L, "pi"))
)
// 定义一个默认用户
val defaultUser = ("John Doe", "Missing")
// 基于Graph对象构造初始化图
val graph = Graph(users, relationships, defaultUser)
// 统计用户为postdoc的总数
// graph.vertices返回VertexRDD[(String, String)],继承于RDD[(VertexID, (String, String))]
graph.vertices.filter{case (id, (name, pos)) => pos == "postdoc"}.count
// 统计src > dst的边总数
// graph.edges返回Edge[String]对象的EdgeRDD
// graph.edges.filter(e => e.srcId > e.dstId).count
graph.edges.filter{case Edge(srcId, dstId, attr) => srcId > dstId}.count()
// graph.triplets包含的属性有Array(((3,(rxin,student)),(7,(jgonzal,postdoc)),collab))
val facts = graph.triplets.map(triplet => triplet.srcAttr._1 + " is the " + triplet.attr + triplet.dstAttr._1 )
facts.collect().foreach(println)
sc.stop()
}
}
3. 图操作符
(1) 属性操作
属性图包含操作如下,每个操作都产生一个新图,包含用户自定义map操作修改后的顶点或边的属性。
a. mapVertices[VD2: ClassTag](map: (VertexId, VD) => VD2): Graph[VD2, ED]
b. mapEdges[ED2: ClassTag](map: Edge[ED] => ED2): Graph[VD, ED2]
c. mapTriplets[ED2: ClassTag](map: EdgeTriplet[VD, ED] => ED2): Graph[VD, ED2]
注意:每种情况下图结构均不受影响,如上操作的一个重要特征是允许所得图形重用原有图形的结构索引ndices。
例:
import org.apache.spark.graphx.{Edge, Graph, VertexId, GraphOps}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
class GraphTest1 {
def main(args: Array[String]): Unit = {
val sc = new SparkContext(new SparkConf().setAppName("GraphTest1"))
// 创建顶点信息
val users: RDD[(VertexId, (String, String))] = sc.parallelize(
Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")), (5L, ("franklin", "prof")), (2L, ("istoica", "prof")))
)
// 创建图的Edge类,Edge类具有srcId和dstId分别对应与源和目标点的标识符,次明早attr成员存储边属性
val relationships: RDD[Edge[String]] = sc.parallelize(
Array(Edge(3L, 7L, "collab"), Edge(5L, 3L, "advisor"), Edge(2L, 5L, "colleague"), Edge(5L, 7L, "pi"))
)
// 定义一个默认用户
val defaultUser = ("John Doe", "Missing")
// 基于Graph对象构造初始化图
val graph = Graph(users, relationships, defaultUser)
// 统计用户为postdoc的总数
// graph.vertices返回VertexRDD[(String, String)],继承于RDD[(VertexID, (String, String))]
graph.vertices.filter{case (id, (name, pos)) => pos == "postdoc"}.count
// 统计src > dst的边总数
// graph.edges返回Edge[String]对象的EdgeRDD
// graph.edges.filter(e => e.srcId > e.dstId).count
graph.edges.filter{case Edge(srcId, dstId, attr) => srcId > dstId}.count()
// graph.triplets包含的属性有Array(((3,(rxin,student)),(7,(jgonzal,postdoc)),collab))
val facts = graph.triplets.map(triplet => triplet.srcAttr._1 + " is the " + triplet.attr + triplet.dstAttr._1 )
facts.collect().foreach(println)
// 指定新图,顶点属性为出度
val inputGraph: Graph[Int, String] = graph.outerJoinVertices(graph.outDegrees)((vid, _, degOpt) => degOpt.getOrElse(0))
// Construct a graph where each edge contains the weight and each vertex is the initial PageRank
val outputGraph:Graph[Double, Double] = inputGraph.mapTriplets(triplet => 1.0 / triplet.srcAttr).mapVertices((_id, _) => 1.0)
sc.stop()
}
}
(2) 结构性操作
图中基本的结构性操作包含:
a. reverse: Graph[VD, ED]:返回新图,图的边的方向都是反转,可用于计算反转的PageRank
b. subgraph(epred: EdgeTriplet[VD,ED] => Boolean, vpred: (VertexId, VD) => Boolean): Graph[VD, ED]:利用顶点和边的predicates,返回的图仅仅包含满足顶点predicates的顶点,满足边predicates的边以及满足顶点predicates的连接顶点(connect vertices)。应用场景:
获取感兴趣的 顶点和边组成的图或者清除断开链接后的图。
例:
val validGraph = graph.subgraph(vpred = (id, attr) => !attr._2.equals("Missing"))
validGraph.vertices.collect.foreach(println)
validGraph.triplets.map(triplet => triplet.srcAttr._1 + " is the " + triplet.attr + " of "+triplet.dstAttr._1).collect
c. mask[VD2, ED2](other: Graph[VD2, ED2]): Graph[VD, ED]:构建子图,包含输入图中的顶点和边。可与subgraph结合,基于另一个相关图的特征去约束一个图。
例:利用缺失顶点的图运行连通体,返回有效子图
val ccGraph = graph.connectedComponents() // No longer contains missing field
val validCCGraph = ccGraph.mask(validGraph) // Restrict the answer to the valid subgraph
d. groupEdges(merge: (ED, ED) => ED): Graph[VD,ED]:合并图中的并行边(如顶点对之间重复的边),降低图的大小
(3) 连接操作
用于将外部数据加入到图中。
a. joinVertices[U: ClassTag](table: RDD[(VertexId, U)])(mapFunc: (VertexId, VD, U) => VD): Graph[VD, ED]:将输入RDD和顶点相结合,返回一个新的带有顶点特征的图。
注意:对于给定顶点,RDD中有超过1个匹配值时,则仅使用其中一个。建议使用如下方法,保证RDD的唯一性。
val nonUniqueCosts: RDD[(VertexId, Double)]
val uniqueCosts: VertexRDD[Double] = graph.vertices.aggregateUsingIndex(nonUniqueCosts, (a, b) => a + b)
val joinedGraph = graph.joinVertices(uniqueCosts)((id, oldCost, extraCost) => oldCost + extraCost)
b. outerJoinVertices(mapFunc: (VertexId, VD, Option[U]) => VD2): Graph[VD2, ED]:与joinVertices类似,因为不是所有顶点在RDD中拥有匹配的值,map函数需要一个Option类型
Spark GraphX初探的更多相关文章
- Spark GraphX学习资料
<Spark GraphX 大规模图计算和图挖掘> http://book.51cto.com/art/201408/450049.htm http://www.csdn.net/arti ...
- 明风:分布式图计算的平台Spark GraphX 在淘宝的实践
快刀初试:Spark GraphX在淘宝的实践 作者:明风 (本文由团队中梧苇和我一起撰写,并由团队中的林岳,岩岫,世仪等多人Review,发表于程序员的8月刊,由于篇幅原因,略作删减,本文为完整版) ...
- Spark Graphx编程指南
问题导读1.GraphX提供了几种方式从RDD或者磁盘上的顶点和边集合构造图?2.PageRank算法在图中发挥什么作用?3.三角形计数算法的作用是什么?Spark中文手册-编程指南Spark之一个快 ...
- Spark Graphx
Graphx 概述 Spark GraphX是一个分布式图处理框架,它是基于Spark平台提供对图计算和图挖掘简洁易用的而丰富的接口,极大的方便了对分布式图处理的需求. ...
- Spark GraphX实例(1)
Spark GraphX是一个分布式的图处理框架.社交网络中,用户与用户之间会存在错综复杂的联系,如微信.QQ.微博的用户之间的好友.关注等关系,构成了一张巨大的图,单机无法处理,只能使用分布式图处理 ...
- Spark GraphX图处理编程实例
所构建的图如下: Scala程序代码如下: import org.apache.spark._ import org.apache.spark.graphx._ // To make some of ...
- Spark GraphX 的数据可视化
概述 Spark GraphX 本身并不提供可视化的支持, 我们通过第三方库 GraphStream 和 Breeze 来实现这一目标 详细 代码下载:http://www.demodashi.com ...
- 大数据技术之_19_Spark学习_05_Spark GraphX 应用解析 + Spark GraphX 概述、解析 + 计算模式 + Pregel API + 图算法参考代码 + PageRank 实例
第1章 Spark GraphX 概述1.1 什么是 Spark GraphX1.2 弹性分布式属性图1.3 运行图计算程序第2章 Spark GraphX 解析2.1 存储模式2.1.1 图存储模式 ...
- 十、spark graphx的scala示例
简介 spark graphx官网:http://spark.apache.org/docs/latest/graphx-programming-guide.html#overview spark g ...
随机推荐
- JavaScript中定义类的方式详解
本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...
- 为什么说Redis是单线程的以及Redis为什么这么块
一.前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”.什么是“热数据和冷数据”,复杂一点的会问到缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级等问题,这些看似 ...
- mongodb命令---花样查询语句
闲言少叙 查出价格低于200的商品信息----包含商品名称,货物编号,价格,添加信息等 db.goods.find( {}}, {,,,} ) 商品分类不为3的商品 db.goods.find( {} ...
- JavaScript变量、作用域和内存问题总结
㈠理解基本类型和引用类型的值 ⑴JavaScript变量可以用来保存两种类型的值:基本类型值和引用类型值. ⑵基本类型的值源自以下 5 种基本数据类型:Undefined.Null.Boolean. ...
- MySQL基础练习01--牛客网
目录 1 查找最晚入职员工的信息 2 查找入职第三晚的员工信息 3 查找当前薪水详情及部门编号 4 查找所有员工入职时的薪水情况 5 查找已分配员工姓名 6 查找员工姓名 7 查找涨薪找过15次的员工 ...
- 解决Spring AOP Controller 不生效
在spring-mvc.xml文件中,进行以下配置,就可以实现在Controller中, 方法一:最简单的,在spring-mvc.xml配置文件中,添加以下语句 spring-mvc.xml < ...
- HDU 5486 Difference of Clustering 暴力模拟
Difference of Clustering HDU - 5486 题意:有n个实体,新旧两种聚类算法,每种算法有很多聚类,在同一算法里,一个实体只属于一个聚类,然后有以下三种模式. 第一种分散, ...
- hive-server 启动失败问题小记
Unable to instantiate using constructor(MetricRegistry, HiveC onf) for reporter org.apache.hadoop.hi ...
- 五一培训 清北学堂 DAY5
今天是吴耀轩老师的讲解- 今天的主要内容:图论 如何学好图论? 学好图论的基础:必须意识到图论! 图 邻接矩阵存图: 其缺点是显而易见的:1. 空间复杂度O(n^2)不能接受:2.有重边的时候很麻烦: ...
- Java基础_死锁、线程组、定时器Timer
一.死锁问题: 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. 比如,线程一需要第一把所,此时锁处于空闲状态,给了 ...