学习

如何使用 Rust 查询 Redis 中的图数据

Ajeet Raina
作者
Ajeet Raina, Redis 前开发者增长经理
终止生命周期通知

Redis 正在逐步淘汰 RedisGraph。 这篇博客文章 解释了此决定的动机以及对现有 Redis 客户和社区成员的影响。

支持将于 2025 年 1 月 31 日结束。

RedisGraph 是首个可查询的属性图数据库,它使用稀疏矩阵表示图中的邻接矩阵,并使用线性代数查询图。RedisGraph 基于一种独特的方法和架构,该方法和架构将 Cypher 查询转换为在 GraphBLAS 引擎上执行的矩阵操作。这种新设计使社交图操作、欺诈检测和实时推荐等用例的执行速度比任何其他图数据库快 10 倍至 600 倍。毫无疑问,它是最快的图数据库,能够实时处理复杂的图操作,比任何其他图数据库快 10 倍至 600 倍。它主要通过多种可视化集成(包括 RedisInsight、Linkurious 和 Graphileon)展示了数据是如何连接的。

RedisGraph 是一个从头开始构建在 Redis 之上的图数据库,它使用新的 Redis Modules API 扩展了 Redis 的新命令和功能。其主要特性包括:使用内存高效的自定义数据结构,对存储在 RAM 中的数据进行简单、快速的索引和查询。Redis Graph 是一个有向图,其中的节点和关系都具有类型——节点带有标签,边缘带有类型。节点和边缘可以(并且通常会)包含属性,就像 SQL 数据库中的列或文档存储中的键一样。更新的 RedisGraph 2.0 基准测试显示,在并行工作负载(多个客户端)下,进行图遍历时,延迟改进高达 6 倍,吞吐量改进高达 5 倍。

以下是 RedisGraph 的主要用例

  • 推荐:通过检查客户与他们所需体验之间的关系,您可以快速找到它们之间的连接。
  • 图辅助搜索:它允许您搜索单个或多个单词或短语,并在图结构上实时执行全文和语言查询及实现。
  • 身份和访问管理:它允许您将复杂的资源访问权限定义为图,并通过单个查询实现这些权限的快速实时验证。

RedisGraph Rust 客户端#

Rust 编程语言速度极快且内存效率高:没有运行时或垃圾回收器,它可以为性能关键型服务提供动力,运行在嵌入式设备上,并轻松与其他语言集成。它是一个最初由 Mozilla Research 开发的开源项目。Rust 标准库是可移植 Rust 软件的基础,是为更广泛的 Rust 生态系统提供的一套最小且经过实战检验的共享抽象。

redisgraph-rs 是 Redis 的图数据库 RedisGraph 的一个惯用 Rust 客户端。此 crate 解析来自 RedisGraph 的响应,并将其转换为普通的 Rust 值。它提供了一个非常灵活的 API,允许您仅使用一个函数 Graph::query 来检索单个值、单个记录或多个记录。

按照以下步骤开始使用 Rust 的 RedisGraph

步骤 1. 运行 Redis Stack Docker 容器#

 docker run -p 6379:6379 --name redis/redis-stack

步骤 2. 验证 RedisGraph 模块是否已加载#

 info modules
 # Modules
 module:name=graph,ver=20405,api=1,filters=0,usedby=[],using=[],options=[]

步骤 3. 安装 Rust#

 brew install rust

步骤 4. 克隆仓库#

  git clone https://github.com/malte-v/redisgraph-rs

步骤 5. 编写 Rust 程序#

复制以下内容并将其保存为 src 目录下的 "main.rs" 文件。

 use redis::Client;
 use redisgraph::{Graph, RedisGraphResult};

 fn main() -> RedisGraphResult<()> {
   let client = Client::open("redis://127.0.0.1:6379")?;
   let mut connection = client.get_connection()?;

   let mut graph = Graph::open(connection, "MotoGP".to_string())?;

   // Create six nodes (three riders, three teams) and three relationships between them.
   graph.mutate("CREATE (:Rider {name: 'Valentino Rossi', birth_year: 1979})-[:rides]->(:Team {name: 'Yamaha'}), \
       (:Rider {name:'Dani Pedrosa', birth_year: 1985, height: 1.58})-[:rides]->(:Team {name: 'Honda'}), \
       (:Rider {name:'Andrea Dovizioso', birth_year: 1986, height: 1.67})-[:rides]->(:Team {name: 'Ducati'})")?;

   // Get the names and birth years of all riders in team Yamaha.
   let results: Vec<(String, u32)> = graph.query("MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, r.birth_year")?;
   // Since we know just one rider in our graph rides for team Yamaha,
   // we can also write this and only get the first record:
   let (name, birth_year): (String, u32) = graph.query("MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, r.birth_year")?;
   // Let's now get all the data about the riders we have.
   // Be aware of that we only know the height of some riders, and therefore we use an `Option`:
   let results: Vec<(String, u32, Option<f32>)> = graph.query("MATCH (r:Rider) RETURN r.name, r.birth_year, r.height")?;

   // That was just a demo; we don't need this graph anymore. Let's delete it from the database:
   //graph.delete()?;

   Ok(())

步骤 6. 运行当前本地包#

 cargo run

步骤 7. 监控图查询#

 1633515550.109594 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "CREATE (dummy:__DUMMY_LABEL__)" "--compact"
 1633515550.111727 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "MATCH (dummy:__DUMMY_LABEL__) DELETE dummy" "--compact"
 1633515550.114948 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "CREATE (:Rider {name: 'Valentino Rossi', birth_year: 1979})-[:rides]->(:Team {name: 'Yamaha'}), (:Rider {name:'Dani Pedrosa', birth_year: 1985, height: 1.58})-[:rides]->(:Team {name: 'Honda'}), (:Rider {name:'Andrea Dovizioso', birth_year: 1986, height: 1.67})-[:rides]->(:Team {name: 'Ducati'})" "--compact"
 1633515550.118380 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, r.birth_year" "--compact"
 1633515550.120766 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, r.birth_year" "--compact"
 1633515550.122505 [0 172.17.0.1:55114] "GRAPH.QUERY" "MotoGP" "MATCH (r:Rider) RETURN r.name, r.birth_year, r.height" "--compact"
 1633515550.124045 [0 172.17.0.1:55114] "GRAPH.DELETE" "MotoGP"

步骤 8. 安装 RedisInsight#

对于此演示,我们将使用 RedisInsight Docker 容器,如下所示

 docker run -d -v redisinsight:/db -p 8001:8001 redislabs/redisinsight:latest

步骤 9. 访问 RedisInsight#

接下来,将浏览器指向 http://localhost:8001。

步骤 10. 运行图查询#

您可以使用 limit 子句限制查询返回的记录数

 GRAPH.QUERY "MotoGP" "MATCH (r:Rider) RETURN r.name, r.birth_year, r.height"

参考资料#

  • 在 快速入门 教程中了解有关 RedisGraph 的更多信息。

请点击您的文本内容,然后按回车键。