LAB 0 实验准备¶
Rust基础入门¶
本系列实验使用Rust语言开发,建议具备基本的Rust编程能力。我们已经准备了相关的学习资源在Rust语言基础章节。在实验开始前,推荐从Rustlings项目练习。
本实验内容完成以下练习:
- 05_vecs
- 06_move_semantics
- 15_traits
- 16_lifetimes
- 19_smart_pointers
了解项目¶
请阅读以下文档,了解本实验项目的整体设计与架构:
实验项目的路径为 ${PROJECT_ROOT}/labs/miniGU/,请熟悉该目录结构。
编译与运行¶
请使用 cargo build命令编译项目,并确保能够成功运行。可以参考快速上手章节中的指导。
实验过程中,你需要做的是对指定接口进行实现,然后通过 cargo test运行单元测试,确保实现的正确性。
背景知识¶
在开始实验之前,我们需要了解一些数据库与图的基础概念,这将帮助你更好地理解 miniGU 存储系统的设计思路。
数据库系统的经典架构¶
一个完整的数据库系统通常分为两大核心组件:
- 查询引擎(Query Engine):负责解析用户查询、生成执行计划、优化查询路径。对于图数据库而言,查询引擎需要理解图查询语言(如 GQL、Cypher、Gremlin),将高层查询转换为底层的存储操作序列。
- 存储引擎(Storage Engine):负责数据的持久化存储、索引维护、事务管理、并发控制和崩溃恢复。它向查询引擎提供统一的数据访问接口(CRUD),屏蔽底层存储细节。
属性图(Label Property Graph)模型¶
图模型有多重种,包括RDF图、属性图等。其中,属性图是一种常用的图数据模型,主要由以下元素组成:
- 顶点(Vertex):图中的节点,表示实体(如用户、商品等)。每个顶点可以有多个标签(Label)和属性(Property)。
- 边(Edge):连接顶点的有向关系,表示实体之间的联系。每条边也可以有多个标签和属性。
图数据库的查询语言¶
由于历史发展的原因,图数据库的查询语言多种多样,主要包括:GQL、SQL/PGQ、Cypher、Gremlin等。GQL是图查询语言的国际标准,Cypher 是 Neo4j 图数据库的查询语言,Gremlin 则是 Apache TinkerPop 图计算框架的查询语言。GQL于2024年被ISO采纳为国际标准,未来是图数据库的统一查询语言标准。下面是一些GQL的示例:
查询操作(Read)¶
// 查询单个顶点:根据ID查询用户的姓名和年龄
MATCH (u:User WHERE u.id = 12345)
RETURN u.name, u.age
// 查询关系:查找某用户关注的所有人
MATCH (u:User WHERE u.name = 'Alice')-[:FOLLOWS]->(friend:User)
RETURN friend.name, friend.age
// 多跳查询:查找朋友的朋友(2度关系)
MATCH (u:User WHERE u.name = 'Alice')-[:FOLLOWS*2]->(fof:User)
RETURN DISTINCT fof.name
// 复杂模式匹配:查找相互关注的用户对
MATCH (u1:User)-[:FOLLOWS]->(u2:User)-[:FOLLOWS]->(u1)
RETURN u1.name, u2.name
// 聚合查询:统计每个用户的关注者数量
MATCH (u:User)<-[:FOLLOWS]-(follower:User)
RETURN u.name, COUNT(follower) AS follower_count
ORDER BY follower_count DESC
创建操作(Create)¶
// 创建单个顶点:创建一个新用户
CREATE (u:User {id: 67890, name: 'Bob', age: 28, city: 'Beijing'})
// 创建多个顶点:批量创建用户
CREATE (u1:User {id: 10001, name: 'Carol', age: 25}),
(u2:User {id: 10002, name: 'Dave', age: 30})
// 创建顶点和边:创建用户并建立关注关系
CREATE (u1:User {id: 20001, name: 'Eve', age: 26}),
(u2:User {id: 20002, name: 'Frank', age: 29}),
(u1)-[:FOLLOWS {since: '2024-01-15'}]->(u2)
// 在已有顶点间创建边:为现有用户建立好友关系
MATCH (u1:User WHERE u1.name = 'Alice'),
(u2:User WHERE u2.name = 'Bob')
CREATE (u1)-[:FRIENDS {since: '2024-03-20', strength: 'strong'}]->(u2)
更新操作(Update)¶
// 更新顶点属性:修改用户年龄
MATCH (u:User WHERE u.id = 12345)
SET u.age = 31
// 批量更新:为所有北京用户添加标签
MATCH (u:User WHERE u.city = 'Beijing')
SET u.region = 'North'
// 更新边属性:更新关注关系的时间戳
MATCH (u1:User)-[f:FOLLOWS]->(u2:User WHERE u2.name = 'Bob')
SET f.last_interaction = '2024-11-08'
// 条件更新:只更新符合条件的属性
MATCH (u:User WHERE u.age < 30)
SET u.category = 'young_user', u.updated_at = timestamp()
// 删除属性:移除用户的某个属性
MATCH (u:User WHERE u.id = 12345)
REMOVE u.city
删除操作(Delete)¶
// 删除单个顶点:删除用户(需先删除相关的边)
MATCH (u:User WHERE u.id = 67890)
DETACH DELETE u
// 删除边:删除特定的关注关系
MATCH (u1:User WHERE u1.name = 'Alice')-[f:FOLLOWS]->(u2:User WHERE u2.name = 'Bob')
DELETE f
// 批量删除:删除所有不活跃用户及其关系
MATCH (u:User WHERE u.last_login < '2023-01-01')
DETACH DELETE u
// 条件删除:删除年龄小于18的用户的敏感信息属性
MATCH (u:User WHERE u.age < 18)
REMOVE u.phone, u.email
复合操作示例¶
// MERGE操作:创建或更新(如果存在则更新,不存在则创建)
MERGE (u:User {id: 12345})
ON CREATE SET u.name = 'NewUser', u.created_at = timestamp()
ON MATCH SET u.last_seen = timestamp()
// 路径查询与过滤:查找最短路径
MATCH p = shortestPath((u1:User WHERE u1.name = 'Alice')
-[:FOLLOWS*]->
(u2:User WHERE u2.name = 'Bob'))
RETURN p, length(p) AS path_length