3. GraphFrames 入门:安装配置与图属性查询

GraphFrames 是构建在 Spark DataFrame 之上的图处理库,将图顶点和边统一为 DataFrame 进行管理,天然支持 DataFrame 的 Catalyst 优化、Tungsten 内存管理与 DataFrame 算子。本章从安装配置开始,逐步建立顶点 DataFrame 与边 DataFrame,并完成图的基本属性查询。

3.1 GraphFrames 安装与配置

GraphFrames 目前由 Databricks 维护,支持 Spark 2.4+ 及 Spark 3.x 系列。安装方式分为 Spark Shell / Jupyter 动态加载 与 Maven / SBT 项目依赖 两种。

环境 安装方式 示例命令 / 配置
Spark Shell / PySpark --packages 参数 --packages graphframes:graphframes:0.8.2-spark3.2-s_2.12
Jupyter Notebook spark.jars.packages spark = SparkSession.builder.config("spark.jars.packages", "graphframes:graphframes:0.8.2-spark3.2-s_2.12").getOrCreate()
Maven 项目 pom.xml 依赖 <groupId>graphframes</groupId><artifactId>graphframes</artifactId><version>0.8.2-spark3.2-s_2.12</version>
SBT 项目 build.sbt libraryDependencies += "graphframes" % "graphframes" % "0.8.2-spark3.2-s_2.12"
版本匹配提示:GraphFrames 的 artifact 名称中包含了 Spark 主版本号(如 spark3.2)和 Scala 版本(s_2.12)。请根据集群实际 Spark 版本选择对应包,否则运行时会出现 NoSuchMethodError 或 ClassNotFoundException。

配置完成后,在代码中通过 from graphframes import GraphFrame(Python)或 import org.graphframes.GraphFrame(Scala)导入即可使用。

3.2 创建顶点 DataFrame 与边 DataFrame

GraphFrame 的核心输入是两个 DataFrame:顶点 DataFrame 必须包含名为 id 的列;边 DataFrame 必须包含 src 和 dst 两列,分别表示边的起点和终点 ID。其他列作为顶点或边的属性自动保留。

3.2.1 顶点 DataFrame 示例

from pyspark.sql import SparkSession
from graphframes import GraphFrame

spark = SparkSession.builder.appName("GraphFramesDemo").getOrCreate()

# 顶点 DataFrame:必须包含 "id" 列
vertices = spark.createDataFrame([
    ("1", "Alice", 34),
    ("2", "Bob", 36),
    ("3", "Charlie", 30),
    ("4", "David", 29),
    ("5", "Eve", 32)
], ["id", "name", "age"])

vertices.show()
+---+-------+---+
| id|   name|age|
+---+-------+---+
|  1|  Alice| 34|
|  2|    Bob| 36|
|  3|Charlie| 30|
|  4|  David| 29|
|  5|    Eve| 32|
+---+-------+---+

3.2.2 边 DataFrame 示例

# 边 DataFrame:必须包含 "src" 和 "dst" 列
edges = spark.createDataFrame([
    ("1", "2", "friend"),
    ("1", "3", "friend"),
    ("2", "3", "friend"),
    ("3", "4", "follow"),
    ("4", "5", "follow"),
    ("5", "1", "follow")
], ["src", "dst", "relationship"])

edges.show()
+---+---+------------+
|src|dst|relationship|
+---+---+------------+
|  1|  2|      friend|
|  1|  3|      friend|
|  2|  3|      friend|
|  3|  4|      follow|
|  4|  5|      follow|
|  5|  1|      follow|
+---+---+------------+

3.2.3 构建 GraphFrame 对象

g = GraphFrame(vertices, edges)
print(f"GraphFrame 构建完成:顶点数 = {g.vertices.count()}, 边数 = {g.edges.count()}")
关键约束:顶点 ID 必须全局唯一,且边中的 src 和 dst 必须在顶点 ID 集合中存在。GraphFrame 在构建时不会自动校验,但后续图算法(如 PageRank、连通分量)会因悬挂边而报错或产生错误结果。

3.3 图的基本属性查询

GraphFrame 提供了丰富的属性查询接口,无需编写复杂 SQL 即可获取图的宏观统计信息。

3.3.1 顶点数与边数

num_vertices = g.vertices.count()
num_edges = g.edges.count()
print(f"顶点数: {num_vertices}")
print(f"边数: {num_edges}")
顶点数: 5
边数: 6

3.3.2 度数分布(入度、出度、总度数)

GraphFrame 的 degrees、inDegrees、outDegrees 属性直接返回 DataFrame,包含每个顶点的度数统计。

# 总度数
g.degrees.show()

# 入度
g.inDegrees.show()

# 出度
g.outDegrees.show()
+---+------+
| id|degree|
+---+------+
|  1|     3|
|  2|     2|
|  3|     3|
|  4|     2|
|  5|     2|
+---+------+

+---+--------+
| id|inDegree|
+---+--------+
|  1|       1|
|  2|       1|
|  3|       2|
|  4|       1|
|  5|       1|
+---+--------+

+---+---------+
| id| outDegree|
+---+---------+
|  1|        2|
|  2|        1|
|  3|        1|
|  4|        1|
|  5|        1|
+---+---------+

3.3.3 度数分布统计(聚合分析)

from pyspark.sql.functions import desc

# 按度数分组统计顶点数量
degree_distribution = g.degrees.groupBy("degree").count().orderBy(desc("degree"))
degree_distribution.show()
+------+-----+
|degree|count|
+------+-----+
|     3|    2|
|     2|    3|
+------+-----+

该结果表示:度数为 3 的顶点有 2 个(Alice 和 Charlie),度数为 2 的顶点有 3 个(Bob、David、Eve)。

3.4 图结构可视化:顶点与边关系

下图展示了当前示例图的拓扑结构,包含 5 个顶点和 6 条有向边,边标签表示关系类型。

GraphFrames 示例图结构 GraphFrames 示例图:5 顶点 6 边 Alice (1) age:34 Bob (2) age:36 Charlie (3) age:30 David (4) age:29 Eve (5) age:32 friend friend friend follow follow follow 顶点 有向边

3.5 属性查询进阶:过滤与投影

由于顶点和边本身就是 DataFrame,可以直接使用 DataFrame 的 filter、select、groupBy 等算子进行灵活查询。

# 查询年龄大于 30 的顶点
g.vertices.filter("age > 30").show()

# 查询所有 "friend" 关系的边
g.edges.filter("relationship = 'friend'").show()

# 统计每种关系类型的边数
g.edges.groupBy("relationship").count().show()
+---+-----+---+
| id| name|age|
+---+-----+---+
|  1|Alice| 34|
|  2|  Bob| 36|
|  5|  Eve| 32|
+---+-----+---+

+---+---+------------+
|src|dst|relationship|
+---+---+------------+
|  1|  2|      friend|
|  1|  3|      friend|
|  2|  3|      friend|
+---+---+------------+

+------------+-----+
|relationship|count|
+------------+-----+
|      follow|    3|
|      friend|    3|
+------------+-----+
性能注意:GraphFrame 的 degrees、inDegrees、outDegrees 属性在调用时会触发一次 Spark 作业(Action)。如果图规模极大(亿级边),频繁调用度数属性会导致多次 Shuffle。建议在需要度数统计时一次性计算并缓存结果 DataFrame。

3.6 本章小结

通过本章学习,你已掌握:

  • GraphFrames 的 Maven / SBT / Spark Shell 安装配置方法
  • 顶点 DataFrame 与边 DataFrame 的创建规范(id / src / dst 列约束)
  • GraphFrame 对象的构建与基本属性查询(顶点数、边数、度数分布)
  • 利用 DataFrame 算子对图属性进行过滤、分组与统计