diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9657a9a38..fa56ab52b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,22 +76,46 @@ jobs: - uses: actions/checkout@v4 - uses: EmbarkStudios/cargo-deny-action@v2 - build: + # Quick smoke test to catch obvious issues early + smoke: needs: [ typos, toml, fmt, clippy, machete, deny ] + name: Smoke Test + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: Swatinem/rust-cache@v2 + - name: Quick build check + run: cargo build --features ${{ env.DEFAULT_FEATURES }} -p minigu-cli + - name: Quick unit tests + run: cargo test --lib --features ${{ env.DEFAULT_FEATURES }} -- --test-threads=4 + + # Combined build and test job to avoid duplicate compilation + build_and_test: + needs: [ smoke ] strategy: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - name: Build on ${{ matrix.os }} + name: Build & Test on ${{ matrix.os }} runs-on: ${{ matrix.os }} - timeout-minutes: 30 + timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest@0.9.88 - uses: Swatinem/rust-cache@v2 - - run: cargo build --features ${{ env.DEFAULT_FEATURES }} + - name: Build + run: cargo build --features ${{ env.DEFAULT_FEATURES }} + - name: Run tests with nextest + run: cargo nextest run --features ${{ env.DEFAULT_FEATURES }} + - name: Run doc tests + run: cargo test --features ${{ env.DEFAULT_FEATURES }} --doc build_no_std: - needs: [ typos, toml, fmt, clippy, machete, deny ] + needs: [ smoke ] name: Build gql-parser in no_std mode runs-on: ubuntu-latest timeout-minutes: 30 @@ -104,21 +128,10 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo build -p gql-parser --target aarch64-unknown-none --no-default-features -Zbuild-std=core,alloc + # Combined WASM check and test wasm: - needs: [ typos, toml, fmt, clippy, machete, deny ] - name: WASM Check (minigu-wasm) - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - run: rustup target add wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 - - run: cargo check -p minigu-wasm --target wasm32-unknown-unknown - - wasm_test: - needs: [ typos, toml, fmt, clippy, machete, deny ] - name: WASM Tests (minigu-wasm) + needs: [ smoke ] + name: WASM Build & Test (minigu-wasm) runs-on: ubuntu-latest timeout-minutes: 30 steps: @@ -132,30 +145,16 @@ jobs: with: tool: wasm-pack@0.13.1 - uses: Swatinem/rust-cache@v2 - - run: wasm-pack test --node minigu-wasm - - run: wasm-pack test --headless --chrome minigu-wasm - - test: - needs: [ typos, toml, fmt, clippy, machete, deny ] - strategy: - matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - uses: taiki-e/install-action@v2 - with: - tool: cargo-nextest@0.9.88 - - uses: Swatinem/rust-cache@v2 - - run: cargo nextest run --features ${{ env.DEFAULT_FEATURES }} - - run: cargo test --features ${{ env.DEFAULT_FEATURES }} --doc + - name: WASM build check + run: cargo check -p minigu-wasm --target wasm32-unknown-unknown + - name: WASM tests (Node) + run: wasm-pack test --node minigu-wasm + - name: WASM tests (Chrome) + run: wasm-pack test --headless --chrome minigu-wasm docs: name: Build Docs - needs: [ typos, toml, fmt, clippy, machete, deny ] + needs: [ smoke ] runs-on: ubuntu-latest timeout-minutes: 30 steps: diff --git a/README.md b/README.md index 637a4e546..42347fc33 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,82 @@ MiniGU 是一个基于 Rust 语言实现的图数据库,旨在帮助学习者 # 文档 -详细文档TBA +- [用户指南](docs/user-guide.md) - 安装、快速开始、GQL 语法参考 +- [架构设计](docs/architecture.md) - 系统架构、核心模块、扩展指南 +- [解析器开发指南](docs/parser/development.md) - GQL 解析器开发文档 ## 快速上手 -Start the interactive shell: +启动交互式 Shell: ```bash -cargo run -- shell # start in debug mode -cargo run -r -- shell # start in release mode +cargo run -- shell # 调试模式启动 +cargo run -r -- shell # 发布模式启动(推荐) +``` + +执行脚本文件: +```bash +cargo run -- execute path/to/script.gql +``` + +### 基本示例 + +```sql +-- 创建图 +CREATE GRAPH my_graph; +SET GRAPH my_graph; + +-- 插入数据 +INSERT (a:Person {name: 'Alice', age: 30}), + (b:Person {name: 'Bob', age: 25}); + +-- 查询数据 +MATCH (p:Person) +WHERE p.age > 25 +RETURN p.name, p.age +ORDER BY p.age DESC; ``` ## 系统架构 -TBA +miniGU 采用分层架构设计: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ CLI Layer (minigu-cli) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Core API Layer (minigu/core) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────────┐ ┌─────────────────┐ +│ Catalog │ │ Context │ │ Transaction │ +└───────────────┘ └───────────────────┘ └─────────────────┘ + │ │ │ + └───────────────────────┼───────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────────┐ ┌─────────────────┐ +│ Common │ │ Storage │ │ GQL │ +│ (公共类型) │ │ (存储引擎) │ │ (查询引擎) │ +└───────────────┘ └───────────────────┘ └─────────────────┘ +``` + +### 核心特性 + +- **GQL 查询语言**: 支持图模式匹配、过滤、聚合、排序等操作 +- **事务支持**: 基于 MVCC 的事务管理,支持快照隔离和可串行化隔离级别 +- **向量搜索**: 内置 DiskANN 向量索引,支持近似最近邻搜索 +- **嵌入式设计**: 单文件存储格式,无需独立服务器进程 +- **持久化存储**: 支持 WAL 和检查点机制 + +详细架构说明请参阅 [架构设计文档](docs/architecture.md) # Contributing diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 000000000..3c8c314a3 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,1253 @@ +# miniGU 架构设计文档 + +## 目录 + +- [概述](#概述) +- [系统架构](#系统架构) +- [核心模块](#核心模块) +- [存储引擎](#存储引擎) +- [查询引擎](#查询引擎) +- [事务管理](#事务管理) +- [向量索引](#向量索引) +- [数据流与执行流程](#数据流与执行流程) +- [扩展指南](#扩展指南) + +--- + +## 概述 + +miniGU 是一个嵌入式图数据库,采用 Rust 语言实现,支持 GQL (Graph Query Language) 查询语言。系统设计遵循分层架构原则,各模块职责清晰,便于学习和扩展。 + +### 设计目标 + +1. **教育性**: 代码结构清晰,适合学习图数据库核心概念 +2. **模块化**: 各组件独立,可单独理解和测试 +3. **现代性**: 采用 Rust 2024 Edition,利用现代语言特性保证安全性和性能 +4. **标准兼容**: 实现 GQL 标准语法 + +### 技术栈 + +| 组件 | 技术选型 | +|------|----------| +| 语言 | Rust 2024 Edition | +| 词法分析 | Logos | +| 语法分析 | Winnow (Parser Combinator) | +| 并发数据结构 | DashMap, SkipSet | +| 列式内存 | Arrow | +| 并行计算 | Rayon | +| 向量索引 | DiskANN | +| 测试框架 | SQLLogicTest, Insta | + +--- + +## 系统架构 + +### 分层架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ CLI Layer (minigu-cli) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Shell │ │ Executor │ │ Output Formatter │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Core API Layer (minigu/core) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Database │ │ Session │ │ Procedures │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────────┐ ┌─────────────────┐ +│ Catalog │ │ Context │ │ Transaction │ +│ (元数据) │ │ (上下文) │ │ (事务) │ +└───────────────┘ └───────────────────┘ └─────────────────┘ + │ │ │ + └───────────────────────┼───────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────────┐ ┌─────────────────┐ +│ Common │ │ Storage │ │ GQL │ +│ (公共类型) │ │ (存储引擎) │ │ (查询引擎) │ +└───────────────┘ └───────────────────┘ └─────────────────┘ +``` + +### 模块依赖关系 + +``` +minigu-cli + │ + └──► minigu (core) + │ + ├──► catalog + ├──► context + ├──► transaction + │ + ├──► common + ├──► storage + │ │ + │ ├──► tp (OLTP) + │ ├──► ap (OLAP) + │ └──► diskann-rs (向量索引) + │ + └──► gql + │ + ├──► parser + ├──► planner + └──► execution +``` + +--- + +## 核心模块 + +### 项目结构 + +``` +miniGU/ +├── minigu/ # 核心库 +│ ├── core/ # 核心 API +│ ├── common/ # 公共数据类型 +│ ├── catalog/ # 元数据管理 +│ ├── context/ # 上下文管理 +│ ├── transaction/ # 事务管理 +│ ├── storage/ # 存储引擎 +│ │ ├── src/ +│ │ │ ├── tp/ # OLTP 存储 +│ │ │ ├── ap/ # OLAP 存储 +│ │ │ ├── common/ # 公共组件 +│ │ │ └── db_file/ # 数据库文件 +│ │ └── diskann-rs/ # 向量索引 +│ └── gql/ # 查询语言 +│ ├── parser/ # 解析器 +│ ├── planner/ # 规划器 +│ └── execution/ # 执行器 +│ +├── minigu-cli/ # 命令行工具 +├── minigu-test/ # 测试框架 +└── docs/ # 文档 +``` + +### 核心模块职责 + +| 模块 | 职责 | +|------|------| +| `core` | 数据库和会话管理,内置存储过程 | +| `common` | 值类型、数据块、结果集等基础数据结构 | +| `catalog` | Schema、图、标签等元数据管理 | +| `context` | 会话上下文、数据库上下文、图上下文 | +| `transaction` | 事务定义、时间戳管理、隔离级别 | +| `storage` | 数据持久化、内存图、向量索引 | +| `gql/parser` | GQL 词法和语法分析 | +| `gql/planner` | 查询绑定、逻辑计划、物理计划 | +| `gql/execution` | 执行器构建、表达式求值 | + +--- + +## 存储引擎 + +存储引擎位于 `minigu/storage/`,采用 TP/AP 分离架构。 + +### 存储架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Storage Layer │ +├─────────────────────────┬───────────────────────────────────────┤ +│ TP Storage │ AP Storage │ +│ (Transaction Proc.) │ (Analytical Proc.) │ +├─────────────────────────┼───────────────────────────────────────┤ +│ ┌───────────────────┐ │ ┌─────────────────────────────────┐ │ +│ │ MemoryGraph │ │ │ OlapStorage │ │ +│ │ ┌─────────────┐ │ │ │ ┌───────────────────────────┐ │ │ +│ │ │ Vertices │ │ │ │ │ Dense Vertex Array │ │ │ +│ │ │ (DashMap) │ │ │ │ └───────────────────────────┘ │ │ +│ │ ├─────────────┤ │ │ │ ┌───────────────────────────┐ │ │ +│ │ │ Edges │ │ │ │ │ Edge Blocks (CSR) │ │ │ +│ │ │ (DashMap) │ │ │ │ └───────────────────────────┘ │ │ +│ │ ├─────────────┤ │ │ │ ┌───────────────────────────┐ │ │ +│ │ │ Adjacency │ │ │ │ │ Property Columns (Arrow) │ │ │ +│ │ │ (SkipSet) │ │ │ │ └───────────────────────────┘ │ │ +│ │ └─────────────┘ │ │ └─────────────────────────────────┘ │ +│ └───────────────────┘ │ │ +├─────────────────────────┴───────────────────────────────────────┤ +│ Persistence Layer │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ DbFileManager ││ +│ │ ┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐ ││ +│ │ │ Header │ │ Checkpoint │ │ WAL │ ││ +│ │ │ (256B) │ │ (Region) │ │ (Region) │ ││ +│ │ └─────────────┘ └─────────────────┘ └─────────────────┘ ││ +│ └─────────────────────────────────────────────────────────────┘│ +└─────────────────────────────────────────────────────────────────┘ +``` + +### TP 存储 (OLTP) + +TP 存储面向事务处理,位于 `storage/src/tp/`。 + +#### 核心数据结构 + +```rust +// 内存图结构 +pub struct MemoryGraph { + // 顶点存储:ID -> 版本化顶点 + pub(super) vertices: DashMap, + + // 边存储:ID -> 版本化边 + pub(super) edges: DashMap, + + // 邻接表:顶点ID -> 邻接容器 + pub(super) adjacency_list: DashMap, + + // 向量索引 + pub(super) vector_indices: DashMap>>>, +} + +// 邻接表容器 +pub(super) struct AdjacencyContainer { + pub(super) incoming: Arc>, // 入边 + pub(super) outgoing: Arc>, // 出边 +} + +// 版本化数据结构 (MVCC) +pub(super) struct VersionChain { + pub(super) current: RwLock>, + pub(super) undo_ptr: RwLock, // 撤销链指针 +} +``` + +#### 关键设计 + +1. **并发控制**: 使用 `DashMap` 实现高效的并发 HashMap,减少锁竞争 +2. **邻接表**: 使用无锁跳表 `SkipSet` 存储邻接关系,支持高效遍历 +3. **版本链**: MVCC 版本链支持快照读取 + +### AP 存储 (OLAP) + +AP 存储面向分析查询,位于 `storage/src/ap/`。 + +#### 核心数据结构 + +```rust +pub struct OlapStorage { + // ID 映射 + pub logic_id_counter: AtomicU64, + pub dense_id_map: DashMap, // 稀疏ID -> 密集ID + + // 列式存储 + pub vertices: RwLock>, + pub edges: RwLock>, + pub property_columns: RwLock>, + + // 压缩存储 + pub is_edge_compressed: AtomicBool, + pub compressed_edges: RwLock>, + pub is_property_compressed: AtomicBool, + pub compressed_properties: RwLock>, +} + +// 边块 (CSR 格式) +pub const BLOCK_CAPACITY: usize = 256; +pub struct EdgeBlock { + pub src_id: VertexId, + pub edges: Vec, +} +``` + +#### 压缩策略 + +```rust +// Delta 编码压缩 +pub struct CompressedEdgeBlock { + pub delta_bit_width: u8, // 增量位宽 + pub first_dst_id: VertexId, // 起始目标ID + pub compressed_dst_ids: BitVec, // 压缩的目标ID + pub label_ids: [Option; BLOCK_CAPACITY], +} +``` + +### 持久化层 + +#### 数据库文件格式 + +``` ++------------------+--------------------------+-----------------------+ +| Header (256B) | Checkpoint Region (Var) | WAL Region (Var) | ++------------------+--------------------------+-----------------------+ +0 256 header.wal_offset EOF +``` + +#### 文件头结构 + +```rust +pub struct DbFileHeader { + pub magic: [u8; 8], // "MINIGU\0\0" + pub version: u32, // 文件格式版本 + pub header_size: u32, // 头大小 (256字节) + pub flags: DbFileFlags, // 特性标志位 + pub checkpoint_offset: u64, // 检查点区域偏移 + pub checkpoint_length: u64, // 检查点区域长度 + pub wal_offset: u64, // WAL区域偏移 + pub wal_length: u64, // WAL区域长度 + pub last_lsn: u64, // 最后的日志序列号 + pub last_commit_ts: u64, // 最后提交时间戳 + pub header_crc: u32, // CRC32校验和 +} +``` + +#### WAL (Write-Ahead Log) + +```rust +pub struct RedoEntry { + pub lsn: u64, // 日志序列号 + pub txn_id: Timestamp, // 事务ID + pub iso_level: IsolationLevel, // 隔离级别 + pub op: Operation, // 操作类型 +} + +pub enum Operation { + BeginTransaction(Timestamp), + CommitTransaction(Timestamp), + AbortTransaction, + Delta(DeltaOp), // 数据变更 +} + +pub enum DeltaOp { + DelVertex(VertexId), + DelEdge(EdgeId), + CreateVertex(Vertex), + CreateEdge(Edge), + SetVertexProps(VertexId, SetPropsOp), + SetEdgeProps(EdgeId, SetPropsOp), + AddLabel(LabelId), + RemoveLabel(LabelId), +} +``` + +#### 检查点机制 + +```rust +pub struct GraphCheckpoint { + pub meta: CheckpointMetadata, + pub vertices: HashMap, + pub edges: HashMap, + pub adjacency_list: HashMap, +} + +// 自动检查点触发 +pub struct CheckpointConfig { + pub wal_threshold: usize, // WAL条目阈值,默认1000 +} +``` + +--- + +## 查询引擎 + +查询引擎位于 `minigu/gql/`,采用经典的 Parser → Planner → Executor 架构。 + +### 查询处理流程 + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ GQL Text │───►│ Lexer │───►│ Parser │───►│ AST │ +└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ + ▼ +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Result │◄───│ Executor │◄───│ Optimizer │◄───│ Binder │ +└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ │ + ▼ ▼ + ┌─────────────┐ ┌─────────────┐ + │ Physical │ │ Logical │ + │ Plan │ │ Plan │ + └─────────────┘ └─────────────┘ +``` + +### 解析器 (Parser) + +位于 `gql/parser/`,使用 Logos + Winnow 实现。 + +#### 词法分析 (Lexer) + +```rust +// 使用 Logos 定义 Token +#[derive(Logos, Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[logos(skip r"[ \t\r\n\f]+")] +#[logos(skip r"--[^\n]*")] +#[logos(skip r"//[^\n]*")] +pub enum TokenKind { + // 关键字 + #[token("MATCH", ignore_case)] + Match, + #[token("RETURN", ignore_case)] + Return, + #[token("WHERE", ignore_case)] + Where, + // ... + + // 标识符和字面量 + #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*", ignore_case)] + RegularIdentifier, + #[regex(r"'[^']*'")] + CharacterStringLiteral, + #[regex(r"[0-9]+")] + UnsignedInteger, + // ... +} +``` + +#### 语法分析 (Parser) + +```rust +// 使用 Winnow 解析器组合子 +pub fn parse_gql(gql: &str) -> Result, Error> { + let tokens = Lexer::new(gql).collect::, _>>()?; + let input = LocatedSlice::new(&tokens); + program.parse(input).map_err(Into::into) +} + +// 解析 MATCH 语句示例 +fn match_statement(input: &mut Input) -> PResult> { + let start = input.start(); + let _ = TokenKind::Match.parse_next(input)?; + let pattern = graph_pattern.parse_next(input)?; + let where_clause = opt(where_clause).parse_next(input)?; + let end = input.end(); + Ok(Spanned::new( + MatchStatement { pattern, where_clause }, + start..end, + )) +} +``` + +#### AST 结构 + +```rust +// 程序入口 +pub struct Program { + pub activity: OptSpanned, + pub session_close: Option>, +} + +// 图模式 +pub struct GraphPattern { + pub match_mode: Option>, + pub element_bindings: Spanned, + pub where_clause: Option>, +} + +// 节点模式 +pub struct NodePattern { + pub variable: Option>, + pub label_expression: Option>, + pub predicate: Option>, +} + +// 边模式 +pub struct EdgePattern { + pub direction: EdgeDirection, + pub variable: Option>, + pub label_expression: Option>, + pub predicate: Option>, + pub quantifier: Option>, +} +``` + +### 查询规划器 (Planner) + +位于 `gql/planner/`,负责将 AST 转换为执行计划。 + +#### 绑定器 (Binder) + +```rust +pub struct Binder<'a> { + catalog: &'a dyn CatalogProvider, + current_schema: Option, + home_schema: Option, + current_graph: Option, + home_graph: Option, + active_data_schema: Option, +} + +impl Binder<'_> { + pub fn bind(&self, procedure: &Procedure) -> PlanResult { + // 1. 名称解析 + // 2. 类型检查 + // 3. Schema 推导 + // 4. 标签 ID 解析 + } +} +``` + +#### 逻辑计划节点 + +```rust +pub enum PlanNode { + // 扫描 + LogicalMatch(LogicalMatch), + LogicalVertexPropertyFetch(LogicalVertexPropertyFetch), + LogicalEdgePropertyFetch(LogicalEdgePropertyFetch), + + // 变换 + LogicalFilter(LogicalFilter), + LogicalProject(LogicalProject), + LogicalSort(LogicalSort), + LogicalLimit(LogicalLimit), + LogicalOffset(LogicalOffset), + + // 连接 + LogicalHashJoin(LogicalHashJoin), + + // 向量搜索 + LogicalVectorIndexScan(LogicalVectorIndexScan), + + // DDL + LogicalCreateVectorIndex(LogicalCreateVectorIndex), + LogicalDropVectorIndex(LogicalDropVectorIndex), + + // 其他 + LogicalOneRow(LogicalOneRow), + LogicalExplain(LogicalExplain), + LogicalCall(LogicalCall), +} +``` + +#### 物理计划节点 + +```rust +pub enum PhysicalNode { + // 扫描 + PhysicalNodeScan(PhysicalNodeScan), + PhysicalExpand(PhysicalExpand), + PhysicalVertexPropertyFetch(PhysicalVertexPropertyFetch), + + // 变换 + PhysicalFilter(PhysicalFilter), + PhysicalProject(PhysicalProject), + PhysicalSort(PhysicalSort), + PhysicalLimit(PhysicalLimit), + PhysicalOffset(PhysicalOffset), + + // 连接 + PhysicalHashJoin(PhysicalHashJoin), + + // 向量搜索 + PhysicalVectorIndexScan(PhysicalVectorIndexScan), + + // 聚合 + PhysicalAggregate(PhysicalAggregate), +} +``` + +#### 优化规则 + +```rust +// 向量索引重写规则 +pub struct VectorIndexScanRewrite; + +impl OptimizerRule for VectorIndexScanRewrite { + fn apply(&self, plan: &PlanNode) -> PlanResult> { + // 检测模式: Sort(VECTOR_DISTANCE) + LIMIT APPROXIMATE + // 重写为: HashJoin(VectorIndexScan, PropertyFetch) + if let PlanNode::LogicalSort(sort) = plan { + if let PlanNode::LogicalLimit(limit) = sort.child.as_ref() { + if limit.is_approximate { + // 执行重写 + return self.rewrite_to_vector_index_scan(plan); + } + } + } + Ok(None) + } +} +``` + +### 查询执行器 (Executor) + +位于 `gql/execution/`,采用 Volcano 模型实现。 + +#### 执行器接口 + +```rust +pub trait Executor: Debug + Send { + fn next_chunk(&mut self) -> Option>; +} + +// 类型别名 +pub type BoxedExecutor = Box; +``` + +#### 执行器构建 + +```rust +pub struct ExecutorBuilder { + session: SessionContext, +} + +impl ExecutorBuilder { + pub fn build(self, plan: &PlanNode) -> BoxedExecutor { + match plan { + PlanNode::PhysicalNodeScan(scan) => self.build_node_scan(scan), + PlanNode::PhysicalExpand(expand) => self.build_expand(expand), + PlanNode::PhysicalFilter(filter) => self.build_filter(filter), + PlanNode::PhysicalProject(project) => self.build_project(project), + PlanNode::PhysicalSort(sort) => self.build_sort(sort), + PlanNode::PhysicalLimit(limit) => self.build_limit(limit), + PlanNode::PhysicalHashJoin(join) => self.build_hash_join(join), + PlanNode::PhysicalVectorIndexScan(scan) => self.build_vector_scan(scan), + PlanNode::PhysicalAggregate(agg) => self.build_aggregate(agg), + // ... + } + } +} +``` + +#### 核心执行器 + +```rust +// 过滤执行器 +pub struct FilterExecutor { + child: BoxedExecutor, + predicate: Box, +} + +impl Executor for FilterExecutor { + fn next_chunk(&mut self) -> Option> { + while let Some(result) = self.child.next_chunk() { + let chunk = result?; + let mask = self.predicate.evaluate(&chunk)?.as_bool_mask(); + if mask.any() { + return Some(Ok(chunk.filter(&mask))); + } + } + None + } +} + +// 投影执行器 +pub struct ProjectExecutor { + child: BoxedExecutor, + expressions: Vec>, +} + +impl Executor for ProjectExecutor { + fn next_chunk(&mut self) -> Option> { + self.child.next_chunk().map(|result| { + let chunk = result?; + let columns: Vec = self.expressions + .iter() + .map(|expr| expr.evaluate(&chunk)?.into_array()) + .collect(); + Ok(DataChunk::new(columns)) + }) + } +} + +// 扩展执行器 (图遍历) +pub struct ExpandExecutor { + child: BoxedExecutor, + input_column_index: usize, + edge_labels: Option>>, + target_vertex_labels: Option>>, + source: Arc, +} + +impl Executor for ExpandExecutor { + fn next_chunk(&mut self) -> Option> { + // 从子执行器获取顶点ID + // 通过邻接表扩展边 + // 返回扩展结果 + } +} +``` + +#### 表达式求值 + +```rust +pub trait Evaluator: Debug + Send + Sync { + fn evaluate(&self, chunk: &DataChunk) -> ExecutionResult; +} + +// 常量求值器 +pub struct Constant { + value: Datum, +} + +// 列引用求值器 +pub struct ColumnRef { + index: usize, +} + +// 二元运算求值器 +pub struct Binary { + left: Box, + op: BinaryOp, + right: Box, +} + +// 向量距离求值器 +pub struct VectorDistanceEvaluator { + left: Box, + right: Box, + metric: VectorMetric, +} +``` + +--- + +## 事务管理 + +事务管理位于 `minigu/transaction/` 和 `storage/src/tp/`。 + +### MVCC 架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Transaction Manager │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ active_txns: SkipMap> │ │ +│ │ committed_txns: SkipMap> │ │ +│ │ commit_lock: Mutex<()> │ │ +│ │ latest_commit_ts: AtomicU64 │ │ +│ │ watermark: AtomicU64 │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Transaction │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ start_ts: Timestamp // 开始时间戳 │ │ +│ │ commit_ts: OnceLock // 提交时间戳 │ │ +│ │ isolation_level: IsolationLevel │ │ +│ │ vertex_reads: DashSet // 读集合 │ │ +│ │ edge_reads: DashSet // 边读集合 │ │ +│ │ undo_buffer: Vec // 撤销日志 │ │ +│ │ redo_buffer: Vec // 重做日志 │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 事务结构 + +```rust +pub struct MemTransaction { + graph: Arc, + isolation_level: IsolationLevel, + start_ts: Timestamp, + commit_ts: OnceLock, + txn_id: Timestamp, + + // 读集合 (用于可串行化验证) + vertex_reads: DashSet, + edge_reads: DashSet, + + // 日志缓冲 + undo_buffer: RwLock>>, + redo_buffer: RwLock>, + + is_handled: Arc, +} +``` + +### 隔离级别 + +```rust +pub enum IsolationLevel { + Snapshot, // 快照隔离 + Serializable, // 可串行化 +} +``` + +### 提交协议 + +```rust +pub fn commit_at(&self, commit_ts: Option, skip_wal: bool) -> StorageResult { + // 1. 获取提交时间戳 + let commit_ts = global_timestamp_generator().next()?; + + // 2. 获取全局提交锁 + let _guard = self.graph.txn_manager.commit_lock.lock().unwrap(); + + // 3. 可串行化验证 + if let IsolationLevel::Serializable = self.isolation_level { + self.validate_read_sets()?; + } + + // 4. 设置提交时间戳 + self.commit_ts.set(commit_ts)?; + + // 5. 处理撤销缓冲区 + for undo_entry in undo_entries.iter() { + // 更新版本链 + } + + // 6. 写入 WAL 并刷盘 + for entry in redo_entries { + self.graph.persistence.append_wal(&entry)?; + } + self.graph.persistence.flush_wal()?; + + // 7. 更新最新提交时间戳 + self.graph.txn_manager.finish_transaction(self)?; + + // 8. 检查自动检查点 + self.graph.check_auto_checkpoint()?; + + Ok(commit_ts) +} +``` + +### 垃圾回收 + +```rust +fn garbage_collect(&self, graph: &MemoryGraph) -> Result<(), StorageError> { + let min_read_ts = self.low_watermark().raw(); + + // 1. 收集过期事务 + for entry in self.committed_txns.iter() { + if entry.key().raw() > min_read_ts { break; } + expired_txns.push(entry.value().clone()); + } + + // 2. 清理版本链中的过期版本 + self.cleanup_version_chains(graph, &expired_undo_entries)?; + + // 3. 移除过期事务记录 + for txn in expired_txns { + self.committed_txns.remove(&txn.commit_ts()?); + } +} +``` + +--- + +## 向量索引 + +向量索引基于 DiskANN 算法实现,位于 `storage/diskann-rs/`。 + +### 架构设计 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Vector Index Interface │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ build(vectors) -> () │ │ +│ │ ann_search(query, k, l, filter) -> Vec<(id, distance)> │ │ +│ │ insert(vectors) -> () │ │ +│ │ soft_delete(ids) -> () │ │ +│ │ save(path) / load(path) │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ InMemANNAdapter │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ inner: Box> // DiskANN 核心 │ │ +│ │ dimension: usize │ │ +│ │ node_to_vector: DashMap // 节点->向量映射 │ │ +│ │ vector_to_node: ShardedVectorMap // 向量->节点映射 │ │ +│ │ next_vector_id: AtomicU32 │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 核心接口 + +```rust +pub trait VectorIndex: Send + Sync { + /// 构建索引 + fn build(&mut self, vectors: &[(u64, &[f32])]) -> StorageResult<()>; + + /// 近似最近邻搜索 + fn ann_search( + &self, + query: &[f32], + k: usize, + l_value: u32, + filter_mask: Option<&dyn DiskANNFilterMask>, + should_pre: bool, + ) -> StorageResult>; + + /// 带过滤的搜索 + fn search( + &self, + query: &[f32], + k: usize, + l_value: u32, + filter_mask: Option<&FilterMask>, + should_pre: bool, + ) -> StorageResult>; + + /// 插入向量 + fn insert(&mut self, vectors: &[(u64, &[f32])]) -> StorageResult<()>; + + /// 软删除 + fn soft_delete(&mut self, node_ids: &[u64]) -> StorageResult<()>; + + /// 持久化 + fn save(&mut self, path: &str) -> StorageResult<()>; + fn load(&mut self, path: &str) -> StorageResult<()>; +} +``` + +### 分片映射优化 + +```rust +// 分片向量映射,减少锁竞争 +pub struct ShardedVectorMap { + shards: Vec>>>, // 16个分片 + shard_bits: u32, +} + +impl ShardedVectorMap { + fn get_shard_and_index(&self, vector_id: u32) -> (usize, usize) { + let shard_mask = (1u32 << self.shard_bits) - 1; + let shard_idx = (vector_id & shard_mask) as usize; + let local_idx = (vector_id >> self.shard_bits) as usize; + (shard_idx, local_idx) + } +} +``` + +### 智能搜索策略 + +```rust +pub const SELECTIVITY_THRESHOLD: f32 = 0.1; // 10% 选择率阈值 + +fn search(&self, query: &[f32], k: usize, l_value: u32, + filter_mask: Option<&FilterMask>, should_pre: bool) -> StorageResult> { + let selectivity = mask.selectivity(); + + if selectivity < SELECTIVITY_THRESHOLD { + // 低选择率:暴力搜索更高效 + self.brute_force_search(query, k, mask) + } else { + // 高选择率:使用索引搜索 + self.filter_search(query, k, l_value, mask, should_pre) + } +} +``` + +### SIMD 优化 + +```rust +// 64字节对齐的向量数据访问 +fn ensure_query_aligned(query: &[f32]) -> StorageResult> { + if query.as_ptr().align_offset(64) == 0 { + Ok(AlignedQueryBuffer::Borrowed(query)) + } else { + let mut aligned = AlignedBoxWithSlice::::new(query.len(), 64)?; + aligned.as_mut_slice().copy_from_slice(query); + Ok(AlignedQueryBuffer::Owned(aligned)) + } +} +``` + +--- + +## 数据流与执行流程 + +### 查询执行流程 + +以一个典型的图查询为例: + +```sql +MATCH (a:Person)-[e:KNOWS]->(b:Person) +WHERE a.age > 25 +RETURN a.name, b.name +ORDER BY a.name +LIMIT 10 +``` + +#### 1. 解析阶段 + +``` +GQL Text + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Lexer (Logos) │ +│ "MATCH" → Token::Match │ +│ "(a:Person)" → Token::LParen, Token::Ident, Token::Colon, ... │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Parser (Winnow) │ +│ Tokens → AST │ +│ MatchStatement { │ +│ pattern: GraphPattern { │ +│ element_bindings: [(a:Person)-[e:KNOWS]->(b:Person)], │ +│ }, │ +│ where_clause: Some(WhereClause { predicate: a.age > 25 }), │ +│ } │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### 2. 规划阶段 + +``` +AST + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Binder │ +│ - 解析标签 Person → LabelId(1) │ +│ - 解析标签 KNOWS → LabelId(2) │ +│ - 类型检查 a.age > 25 (INT > INT → BOOL) │ +│ - 生成 BoundStatement │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ LogicalPlanner │ +│ LogicalMatch │ +│ └── LogicalFilter (a.age > 25) │ +│ └── LogicalProject (a.name, b.name) │ +│ └── LogicalSort (a.name ASC) │ +│ └── LogicalLimit (10) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Optimizer │ +│ PhysicalNodeScan (Person) │ +│ └── PhysicalExpand (KNOWS, outgoing) │ +│ └── PhysicalFilter (a.age > 25) │ +│ └── PhysicalVertexPropertyFetch (a.name, b.name) │ +│ └── PhysicalProject │ +│ └── PhysicalSort │ +│ └── PhysicalLimit │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### 3. 执行阶段 + +``` +PhysicalPlan + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ ExecutorBuilder │ +│ 构建 Executor 树 │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Execution (Volcano Model) │ +│ │ +│ LimitExecutor.next_chunk() │ +│ └── SortExecutor.next_chunk() │ +│ └── ProjectExecutor.next_chunk() │ +│ └── PropertyFetchExecutor.next_chunk() │ +│ └── FilterExecutor.next_chunk() │ +│ └── ExpandExecutor.next_chunk() │ +│ └── NodeScanExecutor.next_chunk()│ +│ │ │ +│ ▼ │ +│ MemoryGraph │ +│ (读取顶点和边) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +DataChunk (结果) +``` + +### 事务执行流程 + +``` +START TRANSACTION + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 生成开始时间戳 start_ts │ +│ 创建 Transaction 对象 │ +│ 注册到 active_txns │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +执行 SQL 语句 + │ + ├── 读操作: 记录到 vertex_reads/edge_reads + │ 读取 start_ts 时可见的版本 + │ + └── 写操作: 创建新版本 + 记录到 undo_buffer + 记录到 redo_buffer + │ + ▼ +COMMIT / ROLLBACK + │ + ├── COMMIT: + │ ├── 获取 commit_ts + │ ├── 获取 commit_lock + │ ├── 可串行化验证 (如需要) + │ ├── 设置版本链 commit_ts + │ ├── 写入 WAL + │ ├── 刷盘 WAL + │ ├── 更新 latest_commit_ts + │ ├── 移动到 committed_txns + │ └── 检查自动检查点 + │ + └── ROLLBACK: + ├── 遍历 undo_buffer + ├── 撤销所有修改 + └── 从 active_txns 移除 +``` + +--- + +## 扩展指南 + +### 添加新的查询语法 + +1. **定义 AST 节点** (`gql/parser/src/ast/`) + ```rust + // 在适当的文件中添加新的 AST 结构 + pub struct NewStatement { + pub fields: Vec>, + } + ``` + +2. **扩展 Lexer** (`gql/parser/src/lexer.rs`) + ```rust + #[derive(Logos)] + pub enum TokenKind { + // 添加新的关键字 + #[token("NEW_KEYWORD", ignore_case)] + NewKeyword, + } + ``` + +3. **实现 Parser** (`gql/parser/src/parser/impls/`) + ```rust + fn new_statement(input: &mut Input) -> PResult> { + // 解析逻辑 + } + ``` + +4. **添加 Binder** (`gql/planner/src/binder/`) + ```rust + impl Binder<'_> { + pub fn bind_new_statement(&self, stmt: &NewStatement) -> PlanResult { + // 绑定逻辑 + } + } + ``` + +5. **创建计划节点** (`gql/planner/src/plan/`) + ```rust + pub struct LogicalNewStatement { + pub bound: BoundNewStatement, + } + ``` + +6. **实现执行器** (`gql/execution/src/executor/`) + ```rust + pub struct NewStatementExecutor { + // 执行器字段 + } + + impl Executor for NewStatementExecutor { + fn next_chunk(&mut self) -> Option> { + // 执行逻辑 + } + } + ``` + +### 添加新的存储后端 + +1. **实现 Trait** (`storage/src/`) + ```rust + pub trait GraphStorage: Send + Sync { + fn create_vertex(&self, txn: &Transaction, vertex: &Vertex) -> StorageResult; + fn get_vertex(&self, txn: &Transaction, id: VertexId) -> StorageResult>; + // ... 其他方法 + } + ``` + +2. **实现事务支持** + ```rust + pub trait TransactionManager: Send + Sync { + fn begin_transaction(&self, isolation_level: IsolationLevel) -> StorageResult; + fn commit(&self, txn: Transaction) -> StorageResult; + fn rollback(&self, txn: Transaction) -> StorageResult<()>; + } + ``` + +### 添加新的内置函数 + +1. **定义函数** (`gql/execution/src/evaluator/`) + ```rust + pub struct NewFunctionEvaluator { + args: Vec>, + } + + impl Evaluator for NewFunctionEvaluator { + fn evaluate(&self, chunk: &DataChunk) -> ExecutionResult { + // 计算逻辑 + } + } + ``` + +2. **注册函数** (`gql/planner/src/binder/`) + ```rust + impl Binder<'_> { + pub fn bind_function_call(&self, name: &str, args: &[Expr]) -> PlanResult> { + match name.to_lowercase().as_str() { + "new_function" => Ok(Box::new(NewFunctionEvaluator::new(bound_args))), + // ... 其他函数 + } + } + } + ``` + +### 添加新的优化规则 + +1. **定义规则** (`gql/planner/src/optimizer/`) + ```rust + pub struct NewOptimizationRule; + + impl OptimizerRule for NewOptimizationRule { + fn apply(&self, plan: &PlanNode) -> PlanResult> { + // 检测可优化的模式 + // 返回优化后的计划 + } + } + ``` + +2. **注册规则** + ```rust + impl Optimizer { + pub fn new() -> Self { + Self { + rules: vec![ + Box::new(VectorIndexScanRewrite), + Box::new(NewOptimizationRule), // 添加新规则 + ], + } + } + } + ``` + +--- + +## 参考资料 + +- [GQL 标准](https://www.iso.org/standard/76120.html) - ISO/IEC 39075 +- [Logos](https://github.com/maciejhirsz/logos) - 词法分析器生成器 +- [Winnow](https://github.com/winnow-rs/winnow) - 解析器组合子库 +- [Arrow](https://arrow.apache.org/) - 列式内存格式 +- [DiskANN](https://github.com/microsoft/DiskANN) - 向量索引算法 \ No newline at end of file diff --git a/docs/user-guide.md b/docs/user-guide.md new file mode 100644 index 000000000..ae569967b --- /dev/null +++ b/docs/user-guide.md @@ -0,0 +1,660 @@ +# miniGU 用户指南 + +## 目录 + +- [简介](#简介) +- [安装与构建](#安装与构建) +- [快速开始](#快速开始) +- [GQL 查询语言](#gql-查询语言) +- [数据类型](#数据类型) +- [内置函数](#内置函数) +- [向量搜索](#向量搜索) +- [存储过程](#存储过程) +- [配置与调优](#配置与调优) + +--- + +## 简介 + +miniGU 是一个由 TuGraph 团队联合多所高校共建的嵌入式图数据库学习项目。它使用 Rust 语言实现,支持 GQL (Graph Query Language) 查询语言,提供交互式 Shell 环境。 + +### 主要特性 + +- **GQL 查询语言**: 支持图模式匹配、过滤、聚合、排序等操作 +- **事务支持**: 基于 MVCC 的事务管理,支持快照隔离和可串行化隔离级别 +- **向量搜索**: 内置 DiskANN 向量索引,支持近似最近邻搜索 +- **嵌入式设计**: 单文件存储格式,无需独立服务器进程 +- **持久化存储**: 支持 WAL (Write-Ahead Log) 和检查点机制 + +--- + +## 安装与构建 + +### 系统要求 + +- Rust 1.75+ (推荐使用最新稳定版) +- Cargo 包管理器 + +### 构建项目 + +```bash +# 克隆仓库 +git clone https://github.com/TuGraph-family/miniGU.git +cd miniGU + +# 调试模式构建 +cargo build + +# 发布模式构建 (推荐用于生产环境) +cargo build --release +``` + +### 运行测试 + +```bash +# 运行所有测试 +cargo test + +# 运行特定模块测试 +cargo test -p minigu-storage + +# 运行 GQL 测试 +cargo test -p minigu-test +``` + +--- + +## 快速开始 + +### 启动交互式 Shell + +```bash +# 调试模式启动 +cargo run -- shell + +# 发布模式启动 (性能更好) +cargo run -r -- shell +``` + +### Shell 命令 + +miniGU Shell 支持以下内置命令: + +| 命令 | 说明 | +|------|------| +| `:help` | 显示帮助信息 | +| `:quit` / `:exit` | 退出 Shell | +| `:cd ` | 切换工作目录 | +| `:clear` | 清屏 | +| `:reset` | 重置会话 | +| `:set ` | 设置会话参数 | + +### 执行脚本文件 + +```bash +# 执行 GQL 脚本文件 +cargo run -- execute path/to/script.gql +``` + +### 基本操作示例 + +```sql +-- 创建 Schema +CREATE SCHEMA my_schema; + +-- 创建图 +CREATE GRAPH my_graph; + +-- 设置当前图 +SET GRAPH my_graph; + +-- 创建顶点标签 +CREATE NODE TYPE Person { + name STRING, + age INT, + email STRING +}; + +-- 创建边标签 +CREATE EDGE TYPE KNOWS { + since INT +}; + +-- 插入顶点 +INSERT (a:Person {name: 'Alice', age: 30}), + (b:Person {name: 'Bob', age: 25}), + (c:Person {name: 'Charlie', age: 35}); + +-- 插入边 +INSERT (a:Person {name: 'Alice'})-[e:KNOWS {since: 2020}]->(b:Person {name: 'Bob'}); + +-- 查询顶点 +MATCH (p:Person) +RETURN p.name, p.age +ORDER BY p.age DESC +LIMIT 10; + +-- 模式匹配查询 +MATCH (a:Person)-[e:KNOWS]->(b:Person) +RETURN a.name, b.name, e.since; + +-- 过滤查询 +MATCH (p:Person) +WHERE p.age > 25 +RETURN p.name, p.age; +``` + +--- + +## GQL 查询语言 + +### 数据定义语言 (DDL) + +#### 创建 Schema + +```sql +CREATE SCHEMA schema_name; +``` + +#### 删除 Schema + +```sql +DROP SCHEMA schema_name; +``` + +#### 创建图 + +```sql +-- 创建空图 +CREATE GRAPH graph_name; + +-- 创建指定类型的图 +CREATE GRAPH graph_name OF TYPE graph_type_name; +``` + +#### 删除图 + +```sql +DROP GRAPH graph_name; +``` + +#### ���建顶点类型 + +```sql +CREATE NODE TYPE LabelName { + property1 Type1, + property2 Type2, + ... +}; +``` + +#### 创建边类型 + +```sql +CREATE EDGE TYPE EdgeLabel { + property1 Type1, + property2 Type2, + ... +} FROM SourceLabel TO TargetLabel; +``` + +#### 创建向量索引 + +```sql +CREATE VECTOR INDEX index_name +FOR (n:Label) +ON n.property_name +DIMENSION 128 +METRIC L2; +``` + +#### 删除向量索引 + +```sql +DROP VECTOR INDEX index_name; +``` + +### 数据操作语言 (DML) + +#### 插入顶点 + +```sql +-- 插入单个顶点 +INSERT (a:Person {name: 'Alice', age: 30}); + +-- 插入多个顶点 +INSERT (a:Person {name: 'Alice'}), + (b:Person {name: 'Bob'}), + (c:Person {name: 'Charlie'}); +``` + +#### 插入边 + +```sql +-- 插入有向边 +INSERT (a:Person {name: 'Alice'})-[e:KNOWS {since: 2020}]->(b:Person {name: 'Bob'}); + +-- 插入无向边 +INSERT (a:Person)-[e:FRIEND {since: 2021}]-(b:Person); +``` + +#### 更新属性 + +```sql +MATCH (p:Person {name: 'Alice'}) +SET p.age = 31; +``` + +#### 删除元素 + +```sql +-- 删除顶点 +MATCH (p:Person {name: 'Alice'}) +DELETE p; + +-- 删除边 +MATCH (a:Person)-[e:KNOWS]->(b:Person) +WHERE a.name = 'Alice' AND b.name = 'Bob' +DELETE e; +``` + +### 数据查询语言 (DQL) + +#### MATCH 语句 + +MATCH 是图模式匹配的核心语句: + +```sql +-- 简单顶点匹配 +MATCH (p:Person) +RETURN p; + +-- 边模式匹配 +MATCH (a:Person)-[e:KNOWS]->(b:Person) +RETURN a, e, b; + +-- 多跳路径匹配 +MATCH (a:Person)-[e1:KNOWS]->(b:Person)-[e2:KNOWS]->(c:Person) +RETURN a.name, c.name; + +-- 可变长度路径 +MATCH (a:Person)-[e:KNOWS*1..3]->(b:Person) +RETURN a.name, b.name; +``` + +#### 边方向 + +```sql +-- 出边 (指向右侧) +MATCH (a)-[e]->(b) + +-- 入边 (指向左侧) +MATCH (a)<-[e]-(b) + +-- 无向边 (任意方向) +MATCH (a)-[e]-(b) + +-- 双向边 +MATCH (a)<-[e]->(b) +``` + +#### 标签表达式 + +```sql +-- 单标签 +MATCH (p:Person) + +-- 多标签 (或) +MATCH (p:Person|Animal) + +-- 标签交集 (与) +MATCH (p:Person&Employee) + +-- 标签取反 +MATCH (p:!Bot) +``` + +#### WHERE 过滤 + +```sql +-- 比较过滤 +MATCH (p:Person) +WHERE p.age > 25 +RETURN p; + +-- 逻辑组合 +MATCH (p:Person) +WHERE p.age > 25 AND p.name STARTS WITH 'A' +RETURN p; + +-- 存在性检查 +MATCH (p:Person) +WHERE p.email IS NOT NULL +RETURN p; + +-- 标签检查 +MATCH (p) +WHERE p IS LABELED Person +RETURN p; +``` + +#### RETURN 投影 + +```sql +-- 返回属性 +MATCH (p:Person) +RETURN p.name, p.age; + +-- 使用别名 +MATCH (p:Person) +RETURN p.name AS name, p.age AS age; + +-- 表达式计算 +MATCH (p:Person) +RETURN p.name, p.age * 2 AS double_age; + +-- 聚合函数 +MATCH (p:Person) +RETURN COUNT(p) AS person_count; + +-- 去重 +MATCH (p:Person) +RETURN DISTINCT p.age; +``` + +#### ORDER BY 排序 + +```sql +-- 升序排序 +MATCH (p:Person) +RETURN p.name, p.age +ORDER BY p.age ASC; + +-- 降序排序 +MATCH (p:Person) +RETURN p.name, p.age +ORDER BY p.age DESC; + +-- 多字段排序 +MATCH (p:Person) +RETURN p.name, p.age +ORDER BY p.age DESC, p.name ASC; +``` + +#### LIMIT 和 OFFSET 分页 + +```sql +-- 限制结果数量 +MATCH (p:Person) +RETURN p +LIMIT 10; + +-- 分页查询 +MATCH (p:Person) +RETURN p +ORDER BY p.name +LIMIT 10 OFFSET 20; +``` + +#### GROUP BY 分组 + +```sql +MATCH (p:Person) +RETURN p.age, COUNT(p) AS count +GROUP BY p.age; +``` + +--- + +## 数据类型 + +### 基本类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| `BOOL` | 布尔值 | `true`, `false` | +| `INT` | 64位整数 | `42`, `-100` | +| `FLOAT` | 64位浮点数 | `3.14`, `-0.5` | +| `STRING` | 字符串 | `'hello'`, `"world"` | +| `BYTES` | 字节串 | `x'48656c6c6f'` | + +### 时间类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| `DATE` | 日期 | `DATE '2024-01-15'` | +| `TIME` | 时间 | `TIME '14:30:00'` | +| `DATETIME` | 日期时间 | `DATETIME '2024-01-15T14:30:00'` | +| `DURATION` | 时间间隔 | `DURATION 'P1Y2M3D'` | + +### 复合类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| `LIST` | 列表 | `[1, 2, 3]` | +| `RECORD` | 记录 | `{name: 'Alice', age: 30}` | +| `VECTOR` | 向量 | `VECTOR [1.0, 2.0, 3.0]` | + +### 图元素类型 + +| 类型 | 说明 | +|------|------| +| `NODE` | 顶点引用 | +| `EDGE` | 边引用 | +| `PATH` | 路径 | + +--- + +## 内置函数 + +### 聚合函数 + +| 函数 | 说明 | +|------|------| +| `COUNT(x)` | 计数 | +| `SUM(x)` | 求和 | +| `AVG(x)` | 平均值 | +| `MIN(x)` | 最小值 | +| `MAX(x)` | 最大值 | +| `COLLECT(x)` | 收集为列表 | + +### 字符串函数 + +| 函数 | 说明 | +|------|------| +| `UPPER(s)` | 转大写 | +| `LOWER(s)` | 转小写 | +| `TRIM(s)` | 去除首尾空白 | +| `SUBSTRING(s, start, len)` | 子字符串 | +| `CONCAT(s1, s2, ...)` | 字符串连接 | +| `LENGTH(s)` | 字符串长度 | + +### 数值函数 + +| 函数 | 说明 | +|------|------| +| `ABS(x)` | 绝对值 | +| `FLOOR(x)` | 向下取整 | +| `CEIL(x)` | 向上取整 | +| `ROUND(x)` | 四舍五入 | +| `SQRT(x)` | 平方根 | +| `POWER(x, y)` | 幂运算 | + +### 图函数 + +| 函数 | 说明 | +|------|------| +| `ELEMENT_ID(e)` | 获取元素 ID | +| `LABELS(n)` | 获取顶点标签列表 | +| `PROPERTIES(e)` | 获取元素属性 | +| `START_NODE(e)` | 获取边的起始顶点 | +| `END_NODE(e)` | 获取边的目标顶点 | + +--- + +## 向量搜索 + +miniGU 内置向量索引支持,可以进行高效的向量相似性搜索。 + +### 创建向量属性 + +```sql +-- 创建带向量属性的顶点类型 +CREATE NODE TYPE Article { + title STRING, + content STRING, + embedding VECTOR(128) +}; + +-- 插入带向量的顶点 +INSERT (a:Article { + title: 'Introduction to Graphs', + content: '...', + embedding: VECTOR [0.1, 0.2, 0.3, ...] +}); +``` + +### 创建向量索引 + +```sql +CREATE VECTOR INDEX article_embedding_idx +FOR (a:Article) +ON a.embedding +DIMENSION 128 +METRIC L2; +``` + +支持的距离度量: +- `L2`: 欧几里得距离 +- `COSINE`: 余弦相似度 +- `INNER_PRODUCT`: 内积 + +### 向量相似性搜索 + +```sql +-- 计算向量距离 +MATCH (a:Article) +RETURN a.title, VECTOR_DISTANCE([0.1, 0.2, ...], a.embedding, L2) AS distance +ORDER BY distance +LIMIT 10; + +-- 使用索引进行近似搜索 +MATCH (a:Article) +RETURN a.title, VECTOR_DISTANCE([0.1, 0.2, ...], a.embedding, L2) AS distance +ORDER BY distance +LIMIT APPROXIMATE 10; +``` + +`LIMIT APPROXIMATE` 提示查询优化器使用向量索引进行近似最近邻搜索,可以显著提升查询性能。 + +--- + +## 存储过程 + +miniGU 提供内置存储过程用于数据库管理。 + +### 查看图信息 + +```sql +CALL show_graph() +YIELD name, vertex_count, edge_count +RETURN name, vertex_count, edge_count; +``` + +### 导入图数据 + +```sql +CALL import_graph('/path/to/data.json') +YIELD status +RETURN status; +``` + +### 导出图数据 + +```sql +CALL export_graph('/path/to/output.json') +YIELD status +RETURN status; +``` + +### 创建测试图 + +```sql +CALL create_test_graph() +YIELD status +RETURN status; +``` + +--- + +## 配置与调优 + +### 数据库文件 + +miniGU 使用单文件存储格式,默认数据文件为 `.minigu` 扩展名。 + +文件结构: +``` ++----------------+--------------------------+-----------------------+ +| Header (256B) | Checkpoint Region (Var) | WAL Region (Var) | ++----------------+--------------------------+-----------------------+ +``` + +### 事务隔离级别 + +```sql +-- 设置隔离级别 +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; + +-- 开始事务 +START TRANSACTION; + +-- 提交事务 +COMMIT; + +-- 回滚事务 +ROLLBACK; +``` + +### 性能建议 + +1. **批量插入**: 使用批量 INSERT 语句减少事务开销 +2. **向量索引**: 对于向量搜索场景,创建适当的向量索引 +3. **查询优化**: 使用 EXPLAIN 查看查询计划 + +```sql +EXPLAIN MATCH (p:Person)-[e:KNOWS]->(f:Person) +RETURN p.name, f.name; +``` + +--- + +## 常见问题 + +### Q: 如何重置数据库? + +```sql +-- 删除并重建图 +DROP GRAPH my_graph; +CREATE GRAPH my_graph; +``` + +### Q: 如何查看当前会话状态? + +```sql +-- 显示当前图 +CALL show_graph() RETURN *; +``` + +### Q: 支持哪些图算法? + +当前版本专注于基础图查询功能,图算法支持正在开发中。 + +--- + +## 更多资源 + +- [架构设计文档](architecture.md) - 了解 miniGU 内部实现 +- [贡献指南](../CONTRIBUTING.md) - 参与项目开发 +- [问题反馈](https://github.com/TuGraph-family/miniGU/issues) - 报告问题或提出建议 \ No newline at end of file