GraphScope项目教程:如何编写自定义图算法
前言
GraphScope是阿里巴巴开源的一款分布式图计算系统,其分析引擎基于GRAPE(一种在SIGMOD-2017上提出的图处理系统)。GRAPE的独特之处在于能够将顺序图算法作为一个整体进行并行化处理。本教程将详细介绍如何在GraphScope中使用PIE和Pregel两种编程模型来编写自定义图算法。
环境准备
首先需要安装GraphScope包:
!pip3 install graphscope
PIE模型算法开发
基本概念
PIE(Parallel Incremental Evaluator)模型是GRAPE的核心编程模型,它允许开发者通过实现三个关键方法将顺序算法轻松并行化:
Init
:初始化顶点数据和消息传递策略PEval
:初始计算(Partial Evaluation)IncEval
:增量计算(Incremental Evaluation)
算法框架
我们以单源最短路径(SSSP)算法为例:
from graphscope.framework.app import AppAssets
from graphscope.analytical.udf.decorators import pie
@pie(vd_type="double", md_type="double")
class SSSP_PIE(AppAssets):
@staticmethod
def Init(frag, context):
pass
@staticmethod
def PEval(frag, context):
pass
@staticmethod
def IncEval(frag, context):
pass
@pie
装饰器中的vd_type
和md_type
分别指定顶点数据类型和消息类型,支持int
、double
和string
三种类型。
实现Init方法
Init
方法负责三件事:
- 设置顶点初始值
- 定义消息传递策略
- 指定消息聚合器
@staticmethod
def Init(frag, context):
v_label_num = frag.vertex_label_num()
for v_label_id in range(v_label_num):
nodes = frag.nodes(v_label_id)
context.init_value(
nodes, v_label_id, 1000000000.0, PIEAggregateType.kMinAggregate
)
context.register_sync_buffer(v_label_id, MessageStrategy.kSyncOnOuterVertex)
对于SSSP算法,我们使用kMinAggregate
作为聚合器,因为需要找出最短路径。其他可用的聚合器包括kMaxAggregate
、kSumAggregate
等。
实现PEval方法
PEval
方法处理包含源节点的分片:
@staticmethod
def PEval(frag, context):
src = int(context.get_config(b"src"))
graphscope.declare(graphscope.Vertex, source)
native_source = False
v_label_num = frag.vertex_label_num()
for v_label_id in range(v_label_num):
if frag.get_inner_node(v_label_id, src, source):
native_source = True
break
if native_source:
context.set_node_value(source, 0)
else:
return
e_label_num = frag.edge_label_num()
for e_label_id in range(e_label_num):
edges = frag.get_outgoing_edges(source, e_label_id)
for e in edges:
dst = e.neighbor()
distv = e.get_int(2)
if context.get_node_value(dst) > distv:
context.set_node_value(dst, distv)
实现IncEval方法
IncEval
方法在所有分片上执行:
@staticmethod
def IncEval(frag, context):
v_label_num = frag.vertex_label_num()
e_label_num = frag.edge_label_num()
for v_label_id in range(v_label_num):
iv = frag.inner_nodes(v_label_id)
for v in iv:
v_dist = context.get_node_value(v)
for e_label_id in range(e_label_num):
es = frag.get_outgoing_edges(v, e_label_id)
for e in es:
u = e.neighbor()
u_dist = v_dist + e.get_int(2)
if context.get_node_value(u) > u_dist:
context.set_node_value(u, u_dist)
运行算法
加载P2P网络数据集并执行算法:
from graphscope.dataset import load_p2p_network
graph = load_p2p_network(directed=False, generate_eid=False)
sssp = SSSP_PIE()
ctx = sssp(graph, src=6)
查看结果:
r1 = (
ctx.to_dataframe({"node": "v:host.id", "r": "r:host"})
.sort_values(by=["node"])
.to_numpy(dtype=float)
)
算法持久化
可以将算法保存为GAR文件供以后使用:
import os
dump_path = os.path.expanduser("~/sssp_pie.gar")
SSSP_PIE.to_gar(dump_path)
加载保存的算法:
from graphscope.framework.app import load_app
sssp2 = load_app(os.path.expanduser("~/sssp_pie.gar"))
Pregel模型算法开发
基本概念
Pregel是Google提出的顶点中心计算模型,GraphScope也提供了对Pregel模型的支持。
算法框架
from graphscope.analytical.udf.decorators import pregel
@pregel(vd_type="double", md_type="double")
class SSSP_Pregel(AppAssets):
@staticmethod
def Init(v, context):
pass
@staticmethod
def Compute(messages, v, context):
pass
实现Init方法
@staticmethod
def Init(v, context):
v.set_value(1000000000.0)
实现Compute方法
@staticmethod
def Compute(messages, v, context):
src_id = context.get_config(b"src")
cur_dist = v.value()
new_dist = 1000000000.0
if v.id() == src_id:
new_dist = 0
for message in messages:
new_dist = min(message, new_dist)
if new_dist < cur_dist:
v.set_value(new_dist)
for e_label_id in range(context.edge_label_num()):
edges = v.outgoing_edges(e_label_id)
for e in edges:
v.send(e.vertex(), new_dist + e.get_int(2))
v.vote_to_halt()
总结
本教程详细介绍了在GraphScope中开发自定义图算法的两种方式:
- PIE模型:基于分片的编程模型,适合复杂图算法
- Pregel模型:顶点中心计算模型,实现简单直观
开发者可以根据算法特性和个人偏好选择合适的编程模型。GraphScope的强大之处在于能够将顺序算法轻松并行化,同时保持代码的简洁性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考