前段时间 NebulaGraph 3.5.0 公布,@whitewum 吴老师倡议我把前段时间 NebulaGraph 社区里开启的新我的项目 ng_ai 公开给大家。
所以,就有了这个系列文章,本文是该系列的开篇之作。
ng_ai 是什么
ng_ai 的全名是:Nebulagraph AI Suite,顾名思义,它是在 NebulaGraph 之上跑算法的 Python 套件,心愿能给 NebulaGraph 的用户一个天然、简洁的高级 API。简略来说,用很少的代码量就能够执行图上的算法相干的工作。
ng_ai 这个开源我的项目的指标是,疾速迭代、公开探讨、继续演进,一句话概述便是:
Simplifying things in surprising ways.
这个 ng_ai 的专属 url:https://github.com/wey-gu/nebulagraph-ai 能够帮你理解更全面的它。
ng_ai 的特点
为了让 NebulaGraph 社区的小伙伴领有顺滑的算法体验,ng_ai 有以下特点:
- 与 NebulaGraph 紧密结合,不便从其中读、写图数据
- 反对多引擎、后端,目前反对 Spark(NebulaGraph Algorithm)、NetworkX,之后会反对 DGL、PyG
- 敌对、合乎直觉的 API 设计
- 与 NebulaGraph 的 UDF 无缝联合,反对从 Query 中调用 ng_ai 工作
- 敌对的自定义算法接口,不便用户本人实现算法(尚未实现)
- 一键试玩环境(基于 Docker Extensions)
你能够这么用 ng_ai
跑分布式 PageRank 算法
能够在一个大图上,基于 nebula-algorithm 分布式地跑 PageRank 算法,像是这样:
from ng_ai import NebulaReader# scan 模式,通过 Spark 引擎读取数据reader = NebulaReader(engine="spark")reader.scan(edge="follow", props="degree")df = reader.read()# 运行 PageRank 算法pr_result = df.algo.pagerank(reset_prob=0.15, max_iter=10)
写回算法后果到 NebulaGraph
假如咱们要跑一个 Label Propagation 算法,而后把后果写回 NebulaGraph,咱们能够这么做:
先确保后果中要写回图数据库的数据 Schema 曾经创立好了,像是上面的示例,便是写到 label_propagation.cluster_id 字段里:
CREATE TAG IF NOT EXISTS label_propagation ( cluster_id string NOT NULL);
上面,咱们来看下具体流程。执行算法:
df_result = df.algo.label_propagation()
再看一下后果的 Schema:
df_result.printSchema()root |-- _id: string (nullable = false) |-- lpa: string (nullable = false)
参考上面的代码,把 lpa 的后果写回 NebulaGraph 中的 cluster_id 字段里({"lpa": "cluster_id"}
):
from ng_ai import NebulaWriterfrom ng_ai.config import NebulaGraphConfigconfig = NebulaGraphConfig()writer = NebulaWriter( data=df_result, sink="nebulagraph_vertex", config=config, engine="spark")# 将 lpa 同 cluster_id 进行映射properties = {"lpa": "cluster_id"}writer.set_options( tag="label_propagation", vid_field="_id", properties=properties, batch_size=256, write_mode="insert",)# 将数据写回到 NebulaGraphwriter.write()
最初,验证一下:
USE basketballplayer;MATCH (v:label_propagation)RETURN id(v), v.label_propagation.cluster_id LIMIT 3;
后果:
+-------------+--------------------------------+| id(v) | v.label_propagation.cluster_id |+-------------+--------------------------------+| "player103" | "player101" || "player113" | "player129" || "player121" | "player129" |+-------------+--------------------------------+
更具体的例子参考:ng_ai/examples
通过 nGQL 调用算法
自 NebulaGraph v3.5.0 开始,用户可从 nGQL 中调用本人实现的函数。而 ng_ai 也用这个能力来实现了一个本人的 ng_ai 函数,让它从 nGQL 中调用 ng_ai 的算法,例如:
-- 筹备将要写入数据的 SchemaUSE basketballplayer;CREATE TAG IF NOT EXISTS pagerank(pagerank string);:sleep 20;-- 回调 ng_ai()RETURN ng_ai("pagerank", ["follow"], ["degree"], "spark", {space: "basketballplayer", max_iter: 10}, {write_mode: "insert"})
更具体的例子参考:ng_ai/examples
单机运行算法
在单机、本地的环境,ng_ai 反对基于 NetworkX 运行算法。
举个例子,读取图为 ng_ai graph 对象:
from ng_ai import NebulaReaderfrom ng_ai.config import NebulaGraphConfig# query 模式,通过 NebulaGraph 或是 NetworkX 引擎读取数据config_dict = { "graphd_hosts": "graphd:9669", "user": "root", "password": "nebula", "space": "basketballplayer",}config = NebulaGraphConfig(**config_dict)reader = NebulaReader(engine="nebula", config=config)reader.query(edges=["follow", "serve"], props=[["degree"], []])g = reader.read()
查看、画图:
g.show(10)g.draw()
运行算法:
pr_result = g.algo.pagerank(reset_prob=0.15, max_iter=10)
写回 NebulaGraph:
from ng_ai import NebulaWriterwriter = NebulaWriter( data=pr_result, sink="nebulagraph_vertex", config=config, engine="nebula",)# 待写入的属性properties = ["pagerank"]writer.set_options( tag="pagerank", properties=properties, batch_size=256, write_mode="insert",)# 将数据写回到 NebulaGraphwriter.write()
其余算法:
# 获取所有算法g.algo.get_all_algo()# 获取相干算法的帮忙信息help(g.algo.node2vec)# 调用算法g.algo.node2vec()
更具体的例子参考:ng_ai/examples
可视化图算法后果
这里演示一个 NetworkX 引擎状况下,计算 Louvain、PageRank 并可视化的例子:
先执行两个图算法:
pr_result = g.algo.pagerank(reset_prob=0.15, max_iter=10)louvain_result = g.algo.louvain()
再手写一个画图难看的函数:
from matplotlib.colors import ListedColormapdef draw_graph_louvain_pr(G, pr_result, louvain_result, colors=["#1984c5", "#22a7f0", "#63bff0", "#a7d5ed", "#e2e2e2", "#e1a692", "#de6e56", "#e14b31", "#c23728"]): # 设定节点的地位 pos = nx.spring_layout(G) # 新建一个图形并设置坐标轴 fig, ax = plt.subplots(figsize=(35, 15)) ax.set_xlim(-1, 1) ax.set_ylim(-1, 1) # 从色彩列表中创立一个 colormap cmap = ListedColormap(colors) # 将图中的节点和边进行绘图 node_colors = [louvain_result[node] for node in G.nodes()] node_sizes = [70000 * pr_result[node] for node in G.nodes()] nx.draw_networkx_nodes(G, pos=pos, ax=ax, node_color=node_colors, node_size=node_sizes, cmap=cmap, vmin=0, vmax=max(louvain_result.values())) nx.draw_networkx_edges(G, pos=pos, ax=ax, edge_color='gray', width=1, connectionstyle='arc3, rad=0.2', arrowstyle='-|>', arrows=True) # 提取边数据中的 label 数据作为字典 edge_labels = nx.get_edge_attributes(G, 'label') # 在图中退出边的 label 数据 for edge, label in edge_labels.items(): ax.text((pos[edge[0]][0] + pos[edge[1]][0])/2, (pos[edge[0]][1] + pos[edge[1]][1])/2, label, fontsize=12, color='black', ha='center', va='center') # 在图中退出点的 label 数据 node_labels = {n: G.nodes[n]['label'] if 'label' in G.nodes[n] else n for n in G.nodes()} nx.draw_networkx_labels(G, pos=pos, ax=ax, labels=node_labels, font_size=12, font_color='black') # 为同社区数据增加雷同色彩 sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=0, vmax=max(louvain_result.values()))) sm.set_array([]) cbar = plt.colorbar(sm, ax=ax, ticks=range(max(louvain_result.values()) + 1), shrink=0.5) cbar.ax.set_yticklabels([f'Community {i}' for i in range(max(louvain_result.values()) + 1)]) # 数据展现 plt.show()draw_graph_louvain_pr(G, pr_result=pr_result, louvain_result=louvain_result)
成果如下所示:
更具体的例子参考:ng_ai/examples
更不便的 Notebook 操作 NebulaGraph
联合 NebulaGraph 的 Jupyter Notebook 插件: https://github.com/wey-gu/ipython-ngql,咱们还能够更便捷地操作 NebulaGraph:
可通过 ng_ai 的 extras 在 Jupyter Notbook 中装置插件:
%pip install ng_ai[jupyter]%load_ext ngql
当然,也能够独自装置插件:
%pip install ipython-ngql%load_ext ngql
装置实现后,就能够在 Notebook 里间接应用 %ngql
命令来执行 nGQL 语句:
%ngql --address 127.0.0.1 --port 9669 --user root --password nebula%ngql USE basketballplayer;%ngql MATCH (v:player{name:"Tim Duncan"})-->(v2:player) RETURN v2.player.name AS Name;
注,多行的 Query 用两个百分号就好了 %%ngql
最初,咱们还能在 Jupyter Notebook 里间接可视化渲染后果!只须要 %ng_draw
就能够啦!
%ngql match p=(:player)-[]->() return p LIMIT 5%ng_draw
成果如下:
将来工作
当初 ng_ai 还在开发中,咱们还有很多工作要做:
- [ ] 欠缺 Reader 模式,当初 NebulaGraph / NetworkX 的读取数据只反对 Query-Mode,还须要反对 Scan-Mode
- [ ] 实现基于 dgl(GNN)的链路预测、节点分类等算法,例如:
model = g.algo.gnn_link_prediction()result = model.train()# query src, dst to be predictedmodel.predict(src_vertex, dst_vertices)
- [ ] UDA,自定义算法
- [ ] 疾速部署工具
ng_ai 齐全 build in public,欢送社区的大家们来参加,一起来欠缺 ng_ai,让 NebulaGraph 上的 AI 算法更加简略、易用!
试玩 ng_ai
咱们曾经筹备好了一键部署的 NebulaGraph + NebulaGraph Studio + ng_ai in Jupyter 的环境,只须要大家从 Docker Desktop 的 Extension(扩大)中搜寻 NebulaGraph,就能够试玩了。
- 装置 NebulaGraph Docker 插件
在 Docker Desktop 的插件市场搜寻 NebulaGraph,点击装置:
- 装置 ng_ai Playground
进入 NebulaGraph 插件,点击 Install NX Mode,装置 ng_ai 的 NetworkX Playground,通常要等几分钟期待装置实现。
- 进入 NetworkX Playground
点击 Jupyter NB NetworkX,进入 NetworkX Playground。
ng_ai 的架构
ng_ai 的架构如下,它的外围模块有:
- Reader:负责从 NebulaGraph 读取数据
- Writer:负责将数据写入 NebulaGraph
- Engine:负责适配不同运行时,例如 Spark、DGL、NetowrkX 等
- Algo:算法模块,例如 PageRank、Louvain、GNN_Link_Predict 等
此外,为了反对 nGQL 中的调用,还有两个模块:
- ng_ai-udf:负责将 UDF 注册到 NebulaGraph,承受 ng_ai 的 Query 调用,拜访 ng_ai API
- ng_ai-api:ng_ai 的 API 服务,承受 UDF 的调用,拜访 ng_ai 外围模块
┌───────────────────────────────────────────────────┐ │ Spark Cluster │ │ .─────. .─────. .─────. .─────. │ │ ; : ; : ; : ; : │ ┌─▶│ : ; : ; : ; : ; │ │ │ ╲ ╱ ╲ ╱ ╲ ╱ ╲ ╱ │ │ │ `───' `───' `───' `───' │ Algo Spark │ Engine└───────────────────────────────────────────────────┘ │ ┌────────────────────────────────────────────────────┬──────────┐ └──┤ │ │ │ NebulaGraph AI Suite(ngai) │ ngai-api │◀─┐ │ │ │ │ │ └──────────┤ │ │ ┌────────┐ ┌──────┐ ┌────────┐ ┌─────┐ │ │ │ │ Reader │ │ Algo │ │ Writer │ │ GNN │ │ │ ┌───────▶│ └────────┘ └──────┘ └────────┘ └─────┘ │ │ │ │ │ │ │ │ │ │ │ │ ├────────────┴───┬────────┴─────┐ └──────┐ │ │ │ │ ▼ ▼ ▼ ▼ │ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐ │ │ │ ┌──┤ │ SparkEngine │ │ NebulaEngine │ │ NetworkX │ │ DGLEngine│ │ │ │ │ │ └─────────────┘ └──────────────┘ └──────────┘ └──────────┘ │ │ │ │ └──────────┬────────────────────────────────────────────────────┘ │ │ │ │ Spark │ │ │ └────────Reader ────────────┐ │ │ Spark Query Mode │ │ │ Reader │ │ │Scan Mode ▼ ┌─────────┐ │ │ ┌───────────────────────────────────────────────────┬─────────┤ ngai-udf│◀─────────────┐ │ │ │ │ └─────────┤ │ │ │ │ NebulaGraph Graph Engine Nebula-GraphD │ ngai-GraphD │ │ │ │ ├──────────────────────────────┬────────────────────┼───────────────────┘ │ │ │ │ │ │ │ │ │ │ NebulaGraph Storage Engine │ │ │ │ │ │ │ │ │ │ └─▶│ Nebula-StorageD │ Nebula-Metad │ │ │ │ │ │ │ │ └──────────────────────────────┴────────────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ RETURN ng_ai("pagerank", ["follow"], ["degree"], "spark", {space:"basketballplayer"}) │──┘ │ └───────────────────────────────────────────────────────────────────────────────────────┘ │ ┌─────────────────────────────────────────────────────────────┐ │ │ from ng_ai import NebulaReader │ │ │ │ │ │ # read data with spark engine, scan mode │ │ │ reader = NebulaReader(engine="spark") │ │ │ reader.scan(edge="follow", props="degree") │ └──│ df = reader.read() │ │ │ │ # run pagerank algorithm │ │ pr_result = df.algo.pagerank(reset_prob=0.15, max_iter=10) │ │ │ └─────────────────────────────────────────────────────────────┘
谢谢你读完本文 (///▽///)
欢送返回 GitHub 来浏览 NebulaGraph 源码,或是尝试用它解决你的业务问题 yo~ GitHub 地址:https://github.com/vesoft-inc/nebula