背景
当前 codeweb 的 GraphStore 使用 bincode 作为唯一二进制存储格式(store.rs version=6)。这带来两个问题:
问题 1: 版本兼容性脆弱
历史上每次 GraphStore schema 变更都触发了 version bump,用户必须重新 analyze:
| 版本 |
变更内容 |
| 1→2 |
ReferencesTable → TableAccess 重构 |
| 2→3 |
新增 Table/View/Package/Trigger 等 8+ Node 变体 |
| 3→4 |
Edge 类型丰富(CallScope/DataFlowKind) |
| 4→5 |
MappedStatement/JavaSql 新增 sql 字段 |
| 5→6 |
新增 JspPage/JspSql Node 变体 |
bincode 采用位置编码,新增枚举变体或字段会破坏旧文件的解析 → 每次 schema 演进都强制全量重分析。
问题 2: 缺少通用数据分析接口
用户希望用 Python/pandas、DuckDB 等外部工具分析调用图数据(统计、聚合、关联查询),当前只能通过 CLI 或 JSON 导出间接获取。
方案
Phase 1: Parquet 导出格式(推荐优先实施)
新增 codeweb export --format parquet,将图谱导出为列式 Parquet 文件,供外部工具消费。
Schema 设计(宽表 + nullable 列,天然支持 schema 演进):
nodes.parquet — 核心标识列 + 各变体特有字段均为 nullable:
node_id: Int64 (NOT NULL)
node_type: Utf8 (NOT NULL) — "Procedure"/"Function"/"Table"/...
schema_name: Utf8
package_name: Utf8
object_name: Utf8
file_path: Utf8
line: Int64
is_partial: Boolean
is_explicit: Boolean
is_system: Boolean
sql_text: Utf8 — MappedStatement.sql / Procedure.body_sql
namespace: Utf8 — MappedStatement
statement_id: Utf8 — MappedStatement
class_fqn: Utf8 — JavaMethod/JavaClass
method_signature: Utf8 — JavaMethod
columns_json: Utf8 — Table (JSON)
partition_json: Utf8 — Table (JSON)
distribute_json: Utf8 — Table (JSON)
ddl_source: Utf8 — Table
type_kind: Utf8 — Type
properties_json: Utf8 — Custom (JSON string via JsonMap)
...
edges.parquet:
edge_id: Int64
source_node_id: Int64
target_node_id: Int64
edge_type: Utf8 — "DirectCall"/"TableAccess"/...
scope: Utf8 — DirectCall
flow_kind: Utf8 — TableAccess
access_modes: Int32 — TableAccess (bitflags)
write_kinds_json: Utf8 — TableAccess (JSON array)
column_analysis_json: Utf8 — TableAccess (JSON)
file_path: Utf8
line: Int64
为什么这样设计:
- 新增 Node/Edge 变体 = 新增 nullable 列 → 旧文件自动兼容(列不存在时 reader 返回 NULL)
node_type / edge_type 是 string 列而非 enum → 新增变体不改变已有数据的编码
- 嵌套结构(
PartitionInfo, DistributeInfo, ColumnAnalysis)用 JSON string 列 → 灵活但不可列内查询(折中方案)
依赖:
parquet = { version = "54", features = ["arrow", "zstd"] }
CLI 接口:
codeweb export --format parquet --output graph.parquet
# 生成 nodes.parquet + edges.parquet(两个文件)
codeweb export --format parquet --output ./export/
Phase 2: bincode + zstd 压缩(低风险优化)
在不改变存储格式的前提下,对 bincode 输出做 zstd 压缩包装:
// store.rs
pub fn save_bincode(&self, path: &Path) -> Result<()> {
let bytes = bincode::serialize(self)?;
let compressed = zstd::encode_all(&bytes[..], 3)?; // level 3, 平衡速度与压缩率
std::fs::write(path, compressed)?;
Ok(())
}
收益: 文件大小减小 30-50%,代码改动 < 10 行,零兼容性风险。
Phase 3(远期): Parquet 作为 store 的可选格式
在 codeweb.toml 中支持 format = "parquet",GraphStore 直接读写 Parquet。此阶段需要:
- 完整的 Parquet → GraphStore 反序列化(重建 petgraph + 全部索引)
- 增量更新的 row group 追加策略
- Benchmark 对比 bincode+zstd
仅在经过 Phase 1 验证 Parquet 读写性能和 schema 兼容性后再考虑。
验证标准
Phase 1
Phase 2
Phase 3
参考资料
- 当前
GraphStore 结构: src/graph/store.rs L24-58
- bincode 版本管理:
store.rs L920-928
- 历史 version bump 清单:
git log --oneline -S "version:" -- src/graph/store.rs
parquet crate: https://crates.io/crates/parquet (需 features=["arrow", "zstd"])
背景
当前 codeweb 的
GraphStore使用 bincode 作为唯一二进制存储格式(store.rsversion=6)。这带来两个问题:问题 1: 版本兼容性脆弱
历史上每次 GraphStore schema 变更都触发了 version bump,用户必须重新
analyze:ReferencesTable→TableAccess重构sql字段bincode 采用位置编码,新增枚举变体或字段会破坏旧文件的解析 → 每次 schema 演进都强制全量重分析。
问题 2: 缺少通用数据分析接口
用户希望用 Python/pandas、DuckDB 等外部工具分析调用图数据(统计、聚合、关联查询),当前只能通过 CLI 或 JSON 导出间接获取。
方案
Phase 1: Parquet 导出格式(推荐优先实施)
新增
codeweb export --format parquet,将图谱导出为列式 Parquet 文件,供外部工具消费。Schema 设计(宽表 + nullable 列,天然支持 schema 演进):
nodes.parquet — 核心标识列 + 各变体特有字段均为 nullable:
edges.parquet:
为什么这样设计:
node_type/edge_type是 string 列而非 enum → 新增变体不改变已有数据的编码PartitionInfo,DistributeInfo,ColumnAnalysis)用 JSON string 列 → 灵活但不可列内查询(折中方案)依赖:
CLI 接口:
Phase 2: bincode + zstd 压缩(低风险优化)
在不改变存储格式的前提下,对 bincode 输出做 zstd 压缩包装:
收益: 文件大小减小 30-50%,代码改动 < 10 行,零兼容性风险。
Phase 3(远期): Parquet 作为 store 的可选格式
在
codeweb.toml中支持format = "parquet",GraphStore 直接读写 Parquet。此阶段需要:仅在经过 Phase 1 验证 Parquet 读写性能和 schema 兼容性后再考虑。
验证标准
Phase 1
codeweb export --format parquet生成可通过 DuckDB 查询的 Parquet 文件duckdb -c "SELECT node_type, count(*) FROM nodes.parquet GROUP BY 1"结果与codeweb stats一致pd.read_parquet("nodes.parquet")可正常读取Phase 2
save → load → stats一致)load_bincode延迟对比(hyperfine)Phase 3
参考资料
GraphStore结构:src/graph/store.rsL24-58store.rsL920-928git log --oneline -S "version:" -- src/graph/store.rsparquetcrate: https://crates.io/crates/parquet (需 features=["arrow", "zstd"])