Procedure API
此文档主要讲解 TuGraph 的存储过程使用说明
1.简介
当用户需要表达的查询/更新逻辑较为复杂(例如 Cypher 无法描述,或是对性能要求较高)时,相比调用多个请求并在客户端完成整个处理流程的方式,TuGraph 提供的存储过程是更简洁和高效的选择。
与传统数据库类似,TuGraph 的存储过程运行在服务器端,用户通过将处理逻辑(即多个操作)封装到一个过程单次调用,并且可以在实现时通过并行处理的方式(例如使用相关的 C++ OLAP 接口以及基于其实现的内置算法)进一步提升性能。
存储过程中有一类特殊的API来进行数据的并行操作,我们叫 Traversal API,见文档。
2.存储过程的版本支持
目 前TuGraph支持两个版本的存储过程,适用于不同的场景,v3.5版本只支持v1,可通过REST或RPC接口直接调用;从v3.5版本开始支持v2,能够在图查询语言(比如Cypher)中嵌入调用,我们称之为POG(Procedure On Graph query language,APOC)。
Procedure v1 | Procedure v2 | |
---|---|---|
适用场景 | 极致性能,或者复杂的多事务管理情形 | 一般情况,与Cypher高度联动 |
事务 | 函数内部创建,可自由控制多事务 | 外部传入函数,单一事务 |
签名(参数定义) | 无 | 有 |
输入输出参数类型 | 不需要指定 | 需要指定参数类型 |
Cypher Standalone Call | 支持 | 支持 |
Cypher Embeded Call | 不支持 | 支持 |
语言 | C++/Python/Rust | C++ |
调用模式 | 直接传字符串,一般为JSON | 通过Cypher语句中的变量 |
在TuGraph中,存储过程v1和v2单独管理,支持增删查,但仍不建议重名。
3.存储过程语言支持
在 TuGraph 中,用户可以动态的加载,更新和删除存储过程。TuGraph 支持 C++ 语言、 Python 语言和 Rust 语言编写存储过程。在性能上 C++ 语言支持的最完整,性能最优。
注意存储过程是在服务端编译执行的逻辑,和客户端的语言支持无关。
4.Procedure v1接口
4.1.编写存储过程
4.1.1.编写C++存储过程
用户可以通过使用 Procedure API 或者 Traversal API 来编写 C 存储过程。一个简单的 C 存储过程举例如下:
#include <iostream>
#include "lgraph.h"
using namespace lgraph_api;
extern "C" LGAPI bool Process(GraphDB& db, const std::string& request, std::string& response) {
auto txn = db.CreateReadTxn();
size_t n = 0;
for (auto vit = txn.GetVertexIterator(); vit.IsValid(); vit.Next()) {
if (vit.GetLabel() == "student") {
auto age = vit.GetField("age");
if (!age.is_null() && age.integer() == 10) n++; ## 统计所有年龄为10的学生数量
}
}
output = std::to_string(n);
return true;
}
从代码中我们可以看到,存储过程的入口函数是Process
函数,它的参数有三个,分别为:
db
: 数据库实例request
: 输入请求数据,可以是二进制字节数组,或者 JSON 串等其它任意格式。response
: 输出数据,可以是字符串,也可以直接返回二进制数据。
Process
函数的返回值是一个布尔值。当它返回true
的时候,表示该请求顺利完成,反之表示这个存储过程在执行过程中发现了错误,此时用户可以通过response
来返回错误信息以方便调试。
C++存储过程编写完毕后需要编译成动态链接库。TuGraph 提供了compile.sh
脚本来帮助用户自动编译存储过程。compile.sh
脚本只有一个参数,是该存储过程的名称,在上面的例子中就是age_10
。编译调用命令行如下:
g++ -fno-gnu-unique -fPIC -g --std=c++14 -I/usr/local/include/lgraph -rdynamic -O3 -fopenmp -o age_10.so age_10.cpp /usr/local/lib64/liblgraph.so -shared
如果编译顺利,会生成 age_10.so,然后用户就可以将它加载到服务器中了。