moduforge-search

Crates.iomoduforge-search
lib.rsmoduforge-search
version0.7.0
created_at2025-08-19 09:38:53.689987+00
updated_at2025-11-14 06:23:28.062254+00
descriptionmoduforge 搜索服务 - SQLite 后端
homepagehttps://github.com/Cassielxd/moduforge-rs
repositoryhttps://github.com/Cassielxd/moduforge-rs
max_upload_size
id1801644
size145,679
Cassie (Cassielxd)

documentation

https://github.com/Cassielxd/moduforge-rs

README

ModuForge Search - SQLite 搜索引擎

基于 SQLite + FTS5 的高性能树形文档搜索引擎。

✨ 特性

  • 全文搜索 - SQLite FTS5 虚拟表,支持中文分词
  • 树形查询 - 原生 WITH RECURSIVE 递归查询
  • 结构化查询 - 完整 SQL 支持,灵活组合条件
  • 增量更新 - 事务级增量索引更新
  • 高并发 - WAL 模式,读写分离
  • 零配置 - 内嵌 SQLite,无需额外依赖

🚀 快速开始

基本使用

use mf_search::{SqliteBackend, SearchService, SearchQuery};
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1. 创建后端
    let backend = Arc::new(SqliteBackend::new_in_dir("./data/index")?);
    let service = SearchService::new(backend);

    // 2. 全文搜索
    let results = service.search_text("富文本编辑器", 10).await?;
    println!("找到 {} 条结果", results.len());

    // 3. 树形查询(递归)
    let results = service.query_descendants("root", 100).await?;
    println!("子树节点数: {}", results.len());

    // 4. 按类型查询
    let results = service.query_by_type("paragraph", 20).await?;
    println!("段落数: {}", results.len());

    Ok(())
}

复杂查询

let results = service.search(SearchQuery {
    text: Some("搜索关键词".to_string()),
    node_type: Some("section".to_string()),
    parent_id: Some("parent_id".to_string()),
    marks: vec!["bold".to_string(), "important".to_string()],
    attrs: vec![("status".to_string(), "published".to_string())],
    sort_by: Some("created_at_i64".to_string()),
    sort_asc: false,
    limit: 20,
    ..Default::default()
}).await?;

与 State 集成

use mf_search::create_search_index_plugin;
use mf_state::{State, StateConfig};

let search_plugin = create_search_index_plugin("./data/index")?;

let state = State::create(StateConfig {
    schema: Some(schema),
    plugins: Some(vec![search_plugin]),
    ..Default::default()
}).await?;

// 自动索引更新
let mut tr = state.tr();
tr.add_node("root".into(), vec![node])?;
let result = state.apply(tr).await?; // 索引自动同步

📊 查询类型

1. 全文搜索

// FTS5 全文索引
SearchQuery {
    text: Some("富文本编辑器".to_string()),
    limit: 50,
    ..Default::default()
}

2. 树形递归

// 获取节点及所有子孙节点
SearchQuery {
    parent_id: Some("root".to_string()),
    include_descendants: true,
    limit: 1000,
    ..Default::default()
}

3. 精确过滤

SearchQuery {
    node_type: Some("paragraph".to_string()),
    parent_id: Some("section_1".to_string()),
    marks: vec!["bold".to_string()],
    ..Default::default()
}

4. 属性查询

// JSON 属性查询
SearchQuery {
    attrs: vec![
        ("status".to_string(), "published".to_string()),
        ("priority".to_string(), "high".to_string()),
    ],
    ..Default::default()
}

5. 范围查询

SearchQuery {
    range_field: Some("created_at_i64".to_string()),
    range_min: Some(1000000),
    range_max: Some(2000000),
    ..Default::default()
}

6. 路径前缀

// 查询路径以 "/root/section" 开头的所有节点
SearchQuery {
    path_prefix: Some("/root/section".to_string()),
    ..Default::default()
}

🏗️ 架构

┌─────────────────────────────────────────┐
│          SearchService                  │  ← 高层查询接口
│  (search_text, query_descendants, ...)  │
└──────────────────┬──────────────────────┘
                   │
┌──────────────────▼──────────────────────┐
│         SqliteBackend                   │  ← SQLite 后端
│  ┌─────────────────────────────────┐   │
│  │  nodes (主表)                    │   │
│  │  - 结构化数据                     │   │
│  │  - B-tree 索引                    │   │
│  └─────────────────────────────────┘   │
│  ┌─────────────────────────────────┐   │
│  │  nodes_fts (FTS5)                │   │
│  │  - 全文索引                       │   │
│  │  - 触发器自动同步                 │   │
│  └─────────────────────────────────┘   │
└─────────────────────────────────────────┘

🎯 性能特点

操作 性能 说明
全文搜索 ~5-10ms FTS5 倒排索引
树形递归 ~3ms WITH RECURSIVE
精确过滤 ~2ms B-tree 索引
批量插入 ~50K/s WAL 模式
索引大小 1.2x 原始数据的 1.2 倍

🔧 配置选项

创建选项

// 1. 指定目录
SqliteBackend::new_in_dir("./data/index")?

// 2. 系统临时目录
SqliteBackend::new_in_system_temp()?

// 3. 自定义临时根目录
SqliteBackend::new_in_temp_root("/tmp/myapp")?

查询选项

pub struct SearchQuery {
    pub text: Option<String>,           // 全文搜索
    pub node_type: Option<String>,      // 节点类型
    pub parent_id: Option<String>,      // 父节点
    pub path_prefix: Option<String>,    // 路径前缀
    pub marks: Vec<String>,             // 标记列表
    pub attrs: Vec<(String, String)>,   // 属性键值对
    pub limit: usize,                   // 返回数量(默认 50)
    pub offset: usize,                  // 偏移量
    pub sort_by: Option<String>,        // 排序字段
    pub sort_asc: bool,                 // 排序方向
    pub include_descendants: bool,      // 包含子树
    pub range_field: Option<String>,    // 范围查询字段
    pub range_min: Option<i64>,         // 最小值
    pub range_max: Option<i64>,         // 最大值
}

🧪 测试

# 运行测试
cargo test -p moduforge-search

# 运行示例
cargo run --example basic -p moduforge-search

# 基准测试
cargo bench -p moduforge-search

📝 迁移指南

从 Tantivy 迁移到 SQLite:

  1. 更新依赖 - 已自动完成
  2. 更新代码 - TantivyBackendSqliteBackend
  3. 更新插件 - create_tantivy_index_plugincreate_search_index_plugin
  4. 查询 API 兼容 - SearchQuery 保持不变

🎁 优势对比

特性 Tantivy SQLite 说明
全文搜索 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ SQLite FTS5 足够强大
树形查询 ⭐⭐⭐ ⭐⭐⭐⭐⭐ 原生 WITH RECURSIVE
SQL 查询 ⭐⭐⭐⭐⭐ 完整 SQL 支持
事务 ⭐⭐ ⭐⭐⭐⭐⭐ ACID 保证
维护成本 ⭐⭐⭐ ⭐⭐⭐⭐⭐ 熟悉的 SQL
写入性能 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ WAL 高并发

📚 参考

Commit count: 493

cargo fmt