Giter Club home page Giter Club logo

rust-tugraph-plugin-tutorial's Introduction

TuGraph中使用Rust语言编写插件

TuGraph是一个高性能图数据库,它支持标准的Cypher查询语言,同时也支持插件机制,用户可以通过插件机制来扩展TuGraph的功能。TuGraph插件机制支持多种语言,包括C++, Python, Rust等。本文将介绍如何使用Rust语言编写TuGraph插件。

在这个教程中你会学习到:

  • 如何使用vscode Dev Containers插件快速搭建开发环境
  • 如何构建运行tugraph服务并通过web界面导入数据
  • 如何编写rust-tugraph插件
  • 如何在TuGraph中上传及使用rust插件

本教程所有代码都在这里

搭建开发环境

本文提供了vscode的开发环境,你可以通过vscode的Dev Containers插件来快速搭建开发环境。如果你不想使用vscode,你也可以通过使用.devcontainer/Dockerfile基于容器来构建开发环境。为了更好的Rust开发体验,我们推荐使用vscode。

安装vscode及其Dev Containers插件

vscode安装:请参考vscode官网安装vscode。

Dev Containers插件:请参考Dev Containers插件安装Dev Containers插件。

安装完毕后,在vscode插件栏中可以看到Dev Containers插件已经安装成功。

插件显示Dev Containers安装成功

使用Dev Containers插件搭建开发环境

新建一个项目目录,取名为rust-tugraph-plugin-tutorial,然后在项目目录下新建一个.devcontainer目录,将.devcontainer 下的内容全部拷贝到.devcontainer目录下。然后在vscode中打开项目目录,vscode会自动检测到.devcontainer目录下的配置文件,提示你是否打开一个新的容器化的开发环境,点击Reopen in Container按钮,vscode会自动构建一个容器化的开发环境。如果没有提示,你也可以通过vscode的命令面板(Ctrl+Shift+P或者Cmd+P)输入Dev Containers: Reopen in Container来打开容器化的开发环境。

在第一次打开容器化的开发环境时,vscode会自动下载容器镜像,这个过程可能会比较慢,请耐心等待⌛️。构建完毕时,使用 cargo version 来检测你是否拥有rust开发环境,如果你看到如下输出,那么恭喜你,你已经拥有了rust开发环境。

$ cargo version
cargo 1.68.0 (115f34552 2023-02-26)

构建运行tugraph服务准备数据

在使用Rust开发插件之前,我们需要先构建运行tugraph服务并登录web界面,这样我们才能在web界面中上传和使用我们的插件。接下来的步骤将介绍如何构建运行tugraph服务并登录web界面。

下载tugraph-db源码

$ git clone --recurse-submodules https://github.com/TuGraph-family/tugraph-db.git

构建tugraph-db依赖

$ bash tugraph-db/deps/build_deps.sh -j8

注意 如果这个步骤在前端构建过程中跑挂了,重跑一次就好

构建lgraph_server

$ cmake -S tugraph-db -B build && cmake --build build --target lgraph_server -j 8

启动lgraph_server

bash -c "cd build/output && sudo ./lgraph_server -c ./lgraph_daemon.json -d start"

登录web界面并准备数据

访问http://localhost:7070, 在登录界面输入admin/73@TuGraph登录,登录成功后,在左侧导航栏选择建模,添加两类顶点Person, Movie, 一类边Watch.

  • Person顶点包含属性name,并为唯一索引。
  • Movie顶点包含属性title,并为唯一索引。
  • Watch边,无属性。

Person Schema Movie Schema Watch Schema

建模完成后,我们往数据库中添加一些数据,这里我们使用Cypher查询语言添加了三个人,两部电影,以及他们之间的观看关系。

CREATE
    (p1:Person {name: 'Alice'}),
    (p2:Person {name: 'Bob'}),
    (p3:Person {name: 'Charlie'}),
    (m1:Movie {title: 'The Matrix'}),
    (m2:Movie {title: 'The Matrix Reloaded'}),
    (p1)-[:Watch]->(m1),
    (p2)-[:Watch]->(m1),
    (p2)-[:Watch]->(m2)

Create Data using Cypher 通过 MATCH (n) RETURN n 可以查看所有点边可视化数据。 查看数据

使用Rust语言编写插件

恭喜你到了最后一步,在这一步中我们将使用Rust语言编写插件。这个插件功能是给定一个人名,电影名,寻找看过这部电影的其他人的名字。

创建rust library项目

cargo new movie-friend --lib

修改Cargo.toml配置清单

tugraph支持的插件类型包括:C++源代码,动态库so,以及Python源代码。这里,我们选择动态库so方式加载。 rust crate的默认编译结果是rust rlib文件类型,通过lib.crate-type字段,我们可以将它设置为动态库类型。 往movie-friend/Cargo.toml中添加如下配置:

[lib]
crate-type = ["cdylib"]

我们要使用rust-tugraph这个rust binding库来调用tugraph的api,以及使用tugraph-plugin-util这个工具库来简化 编写插件的流程。往movie-friend/Cargo.toml中添加如下依赖:

[dependencies]
tugraph = "0.1.4"
tugraph-plugin-util = "0.1.2"

rust-tugraph这个binding依赖tugraph-db的liblgraph.so, 会使用LGRAPH_CXX_COMPILER, LGRAPH_C_COMPILER 来构建它。如果没有设置,那么他会寻找系统默认的g++和gcc编译器来构建,通常情况下版本应该大于8.2。这里我们通过以上两个 环境变量来确保我们接下来的构建中都适用合适版本的编译器。

mkdir .cargo
cat <<EOF | tee .cargo/config
[env]
LGRAPH_C_COMPILER="/usr/local/bin/gcc"
LGRAPH_CXX_COMPILER="/usr/local/bin/g++"
EOF

运行cargo check来检查并下载依赖,并且构建liblgraph.so动态库,这个过程时间可能会有点长,请耐心等待⌛️。

cd movie-friend && cargo check --release -j 8

⚠️: 如果你不关心插件的运行性能,你可以使用默认的debug模式构建,此时你只需要通过cargo check -j 8进行检查即可。

编写插件核心代码

在movie-friend/src/lib.rs中将其替换成如下代码:

use std::error::Error;

use tugraph::{
    cursor::EdgeCursor, cursor::VertexCursor, db::Graph, field::FieldData, txn::TxnRead,
};

#[tugraph_plugin_util::tugraph_plugin]
fn movie_friend(graph: &mut Graph, req: &str) -> Result<String, Box<dyn Error>> {
    // req stores the request string from the web
    // its format is "person_name,movie_title"
    // parse from req to get person_name and movie_title
    let (person_name, movie_title) = parse_req(req)?;

    // create read only transaction
    let ro_txn = graph.create_ro_txn()?;
    let mut movie_index_iter = ro_txn.vertex_index_iter_ids_from(
        "Movie",
        "title",
        &FieldData::String(movie_title.clone()),
        &FieldData::String(movie_title),
    )?;

    let movie_id = movie_index_iter.next().ok_or("movie not found")?;

    // find the movie vertex with vid = movie_id
    let mut vertex_cur = ro_txn.vertex_cur()?;
    vertex_cur.seek(movie_id, false)?;
    // get all the watcher ids of the movie
    let watcher_ids: Vec<_> = vertex_cur.in_edge_cursor()?.into_edge_srcs().collect();

    // collect all user names through watcher ids
    let user_names = watcher_ids
        .iter()
        .map(|user_id| {
            let mut user_cur = ro_txn.vertex_cur()?;
            user_cur.seek(*user_id, false)?;
            user_cur.field("name").map(|name| match name {
                FieldData::String(name) => name,
                _ => panic!("name should be string"),
            })
        })
        .collect::<Result<Vec<_>, _>>()?;

    // return all user names except the person_name
    Ok(user_names
        .into_iter()
        .filter(|name| name != &person_name)
        .collect::<Vec<_>>()
        .join(","))
}

fn parse_req(req: &str) -> Result<(String, String), String> {
    let v: Vec<_> = req.split(',').collect();
    if v.len() != 2 {
        return Err("parse request error, format should be `Person.name,Movie.title`".to_string());
    }
    Ok((v[0].to_string(), v[1].to_string()))
}

这段代码使用了 tugraph 这个crate,它是tugraph的rust binding库,提供了tugraph的api接口。movie_friend函数是 插件的核心函数,它的输入是一个字符串,格式为Person.name,Movie.title,它的输出是一个字符串,格式为Person.name,Person.name,...。 所有的插件函数都需要使用tugraph_plugin_util::tugraph_plugin这个宏来修饰,并且函数签名必须为fn(&mut Graph, &str) -> Result<String, E>

函数开始部分,我们首先解析请求字符串,获取到person_name和movie_title。然后创建一个只读事务,通过vertex_index_iter_ids_from函数 获取到movie_title对应的movie_id。

接下来我们需要获取这个movie的所有观看者。我们首先可以构建出vertex_cur并通过seek函数定位到movie_id所在顶点。接下来使用in_edge_cursor方法获取到 能够遍历所有入边的cursor,并调用它into_edge_srcs适配器方法将其转化为遍历所有入边起始点的迭代器。由schema所知,这些入边起始点就是指向这个movie的所有观看者顶点id。 最后通过collect方法将这些观看者顶点id收集起来。

离最终目标只差一步了。有了这些观看者顶点id,我们可以通过针对每个id,构建出相应的vertex_cur,并通过field方法获取到观看者的名字。最后通过join方法将所有观看者的名字。 返回给调用者之前,别忘记过滤掉person_name哦。

tugraph_plugin_util::tugraph_plugin是一个由tugraph-plugin-util工具包提供的一个属性宏,它会将修饰的函数将被展开为能够被tugraph插件 系统调用的函数。关于属性宏的更多信息,可以参考attribute macro。关于tugraph-plugin-util工具包的更多信息,可以参考tugraph-plugin-util

构建plugin

构建plugin,在movie-friend/target/release/下会生成libmovie_friend.so

cargo build --release -j 8

TuGraph中使用rust plugin

上传插件

将上面步骤生成的libmovie_friend.so上传到tugraph插件页面。

上传插件

使用插件

使用插件

rust-tugraph-plugin-tutorial's People

Contributors

antkiller996 avatar wangtao9 avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

kellerli

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.