版本: v0.7.1
语言: Rust 核心 + Python 绑定 (PyO3) + Node.js 绑定 (napi-rs)
许可: Apache-2.0
- 数据库生命周期
- 节点 CRUD
- 图谱操作
- 向量检索
- Hook 扩展系统
- 元数据过滤
- TQL 统一查询
- 属性二级索引
- 持久化与压缩
- 内存管理
- 工具方法
- 维度迁移
- 事务支持
- Pythonic 魔术方法
- 数据类型说明
import triviumdb
# 基础打开方式(默认 f32 向量、1536 维、normal 同步模式)
db = triviumdb.TriviumDB("my_data.tdb", dim=1536)
# 完整参数
db = triviumdb.TriviumDB(
path="my_data.tdb", # 文件路径(不存在则新建)
dim=1536, # 向量维度(一旦创建不可更改)
dtype="f32", # 向量类型:"f32" | "f16" | "u64"
sync_mode="normal" # WAL 同步模式:"full" | "normal" | "off"
)
# 推荐:使用上下文管理器(退出时自动 flush 落盘)
with triviumdb.TriviumDB("my_data.tdb", dim=1536) as db:
# ... 所有操作 ...
pass # 退出时自动调用 db.flush()参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
必填 | .tdb 文件路径,不存在时自动创建 |
dim |
int |
1536 |
向量维度,必须与后续插入的向量长度一致 |
dtype |
str |
"f32" |
向量存储精度:f32(标准)、f16(省内存)、u64(SimHash) |
sync_mode |
str |
"normal" |
WAL 写入安全级别,详见持久化与压缩 |
use triviumdb::Database;
use triviumdb::database::{Config, StorageMode};
use triviumdb::storage::wal::SyncMode;
// 基础打开(默认 Mmap 模式 + Normal 同步)
let mut db = Database::<f32>::open("my_data.tdb", 1536)?;
// 指定同步模式(向后兼容)
let mut db = Database::<f32>::open_with_sync("my_data.tdb", 1536, SyncMode::Full)?;
// 高级配置(v0.4+)——同时指定存储模式和同步模式
let mut db = Database::<f32>::open_with_config("my_data.tdb", Config {
dim: 1536,
storage_mode: StorageMode::Rom, // Rom:单文件便携 | Mmap:分离零拷贝(默认)
sync_mode: SyncMode::Normal,
})?;
// 运行时切换同步模式
db.set_sync_mode(SyncMode::Off);泛型类型参数 T:
| 类型 | 说明 | 适用场景 |
|---|---|---|
f32 |
32 位浮点 | 标准 embedding(OpenAI、BGE 等) |
half::f16 |
16 位半精度浮点 | 大规模数据集省内存 |
u64 |
64 位无符号整数 | SimHash / 二值化向量 |
向数据库写入一个新节点,同时携带向量和 JSON 元数据。返回自动分配的 u64 节点 ID。
Python:
node_id = db.insert(
vector=[0.12, -0.45, 0.78, ...], # 向量(长度必须等于 dim)
payload={"text": "小明喜欢吃苹果", "ts": 1711440000} # 任意 JSON
)Rust:
let id = db.insert(&[0.12, -0.45, 0.78], json!({"text": "Hello"}))?;适用于从外部系统导入数据时,保持原始 ID 不变。如果 ID 已存在会返回错误。
Python:
db.insert_with_id(id=42, vector=[0.1, 0.2, 0.3, ...], payload={"source": "external"})Rust:
db.insert_with_id(42, &[0.1, 0.2, 0.3], json!({"source": "external"}))?;一次性插入多个节点,返回所有新 ID 的列表。
Python:
ids = db.batch_insert(
vectors=[[0.1, 0.2, ...], [0.3, 0.4, ...]],
payloads=[{"name": "A"}, {"name": "B"}]
)Python:
db.batch_insert_with_ids(
ids=[100, 101],
vectors=[[0.1, 0.2, ...], [0.3, 0.4, ...]],
payloads=[{"name": "A"}, {"name": "B"}]
)按 ID 获取节点的完整视图,包含向量、元数据和边的数量。不存在时返回 None。
Python:
node = db.get(42)
if node:
print(node.id) # 42
print(node.vector) # [0.1, 0.2, ...]
print(node.payload) # {"name": "Alice", ...}
print(node.num_edges) # 3Rust:
if let Some(view) = db.get(42) {
println!("ID={}, edges={}", view.id, view.edges.len());
println!("payload={:?}", view.payload);
}整体替换节点的 JSON 元数据(向量和图谱关系不受影响)。
Python:
db.update_payload(id=42, payload={"text": "更新后的文本", "version": 2})就地替换节点的向量(维度必须一致,元数据和图谱关系不受影响)。
Python:
db.update_vector(vector=[0.5, 0.6, 0.7, ...], id=42)三层原子联删:同时清除该节点的向量、元数据以及所有关联的图谱边(包括其他节点指向它的入边)。
Python:
db.delete(42)Rust:
db.delete(42)?;
⚠️ 删除操作不可逆。删除后,该节点的向量区间被逻辑置零,待 Compaction 时物理回收。
只获取节点的 JSON Payload,不含向量,比 get() 更轻量。
Python:
payload = db.get_payload(42)
if payload:
print(payload["name"]) # "Alice"Node.js:
const payload = db.getPayload(42)
if (payload) console.log(payload.name)获取节点的所有出向边(不含向量和 Payload)。
Python:
edges = db.get_edges(42)
for e in edges:
print(f"{e.target_id} ({e.label}, w={e.weight})")Node.js:
const edges = db.getEdges(42)
edges.forEach(e => console.log(`${e.targetId} (${e.label})`))Python:
if db.contains(42): # 或用 42 in db
print("节点存在")Node.js:
if (db.contains(42)) console.log('节点存在')在两个节点之间建立一条有向带权边。两个端点必须已存在,否则返回错误。
Python:
db.link(src=1, dst=2, label="knows", weight=0.95)Rust:
db.link(1, 2, "knows", 0.95)?;参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
src |
u64 |
必填 | 源节点 ID |
dst |
u64 |
必填 | 目标节点 ID |
label |
str |
"related" |
边的类型标签(自定义字符串) |
weight |
f32 |
1.0 |
边的权重(支持负值,可用于表达抑制关系) |
💡 边是有向的。如需双向关系,需调用两次
link():link(A, B)+link(B, A)。
移除从 src 到 dst 的所有边(无论 label 是什么)。
Python:
db.unlink(src=1, dst=2)Rust:
db.unlink(1, 2)?;从指定节点出发,沿有向边进行广度优先遍历(BFS),返回 N 跳以内所有可达节点的 ID。
Python:
neighbor_ids = db.neighbors(id=1, depth=2) # 2 跳以内的所有邻居Rust:
let ids = db.neighbors(1, 2);TriviumDB 核心杀手锏:引入稀疏文本表示(BM25/AC自动机)与稠密向量(Dense Vector)构成双路融合召回锚定,再在第二阶段进行图谱激活扩散。这极大弥补了纯向量检索容易导致的专有名词幻觉(Hallucination)。
Python:
results = db.search_hybrid(
query_vector=[0.10, -0.48, 0.80, ...],
query_text="Rust 内存安全",
top_k=5,
expand_depth=2,
min_score=0.1,
hybrid_alpha=0.7 # 0.7 偏向量,0.3 偏精确文本
)
for hit in results:
print(f"[{hit.id}] score={hit.score:.3f} | {hit.payload}")TriviumDB 的基础检索能力(退化态):先用核心稠密向量相似度找到锚点,再沿图谱关系向外扩散。
Python:
results = db.search(
query_vector=[0.10, -0.48, 0.80, ...], # 查询向量
top_k=5, # 向量阶段返回的锚点数量
expand_depth=2, # 图谱扩散跳数(0 = 纯向量检索)
min_score=0.5 # 最低相似度阈值
)
for hit in results:
print(f"[{hit.id}] score={hit.score:.3f} | {hit.payload}")Rust:
let results = db.search(&[0.10, -0.48, 0.80], 5, 2, 0.5)?;
for hit in &results {
println!("[{}] score={:.3} {:?}", hit.id, hit.score, hit.payload);
}参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
query_vector |
list[float] |
必填 | 查询向量 |
top_k |
int |
5 |
向量阶段返回的最相似节点数 |
expand_depth |
int |
0 |
图谱扩散深度。设为 0 则退化为纯向量检索 |
min_score |
float |
0.5 |
余弦相似度下限,低于此值的结果被过滤 |
返回值 SearchHit:
| 属性 | 类型 | 说明 |
|---|---|---|
id |
u64 |
命中节点的 ID |
score |
f32 |
相似度得分(余弦相似度或扩散热度) |
payload |
dict |
节点的 JSON 元数据 |
检索流程:
查询向量 ──→ [向量索引层] ──→ Top-K 锚点
│
▼
[图谱扩散层] ──→ N 跳邻居(Spreading Activation)
│
▼
最终排序结果
内置九层认知管线的全功能入口。通过 SearchConfig 参数化控制 FISTA 残差寻隐、PPR 图扩散、DPP 多样性采样等高级特性。
Python:
results = db.search_advanced(
query_vector=[0.10, -0.48, 0.80, ...],
top_k=10,
expand_depth=2,
min_score=0.1,
teleport_alpha=0.15, # PPR 回跳概率
enable_advanced_pipeline=True, # 总开关
enable_sparse_residual=True, # FISTA 影子查询
fista_lambda=0.1,
fista_threshold=0.3,
enable_dpp=True, # DPP 多样性采样
dpp_quality_weight=1.0,
)
for hit in results:
print(f"[{hit.id}] score={hit.score:.3f} | {hit.payload}")Node.js:
const results = db.searchAdvanced(queryVector, {
topK: 10,
expandDepth: 2,
teleportAlpha: 0.15,
enableAdvancedPipeline: true,
enableSparseResidual: true,
enableDpp: true,
});Rust:
use triviumdb::database::SearchConfig;
let config = SearchConfig {
top_k: 10,
expand_depth: 2,
min_score: 0.1,
teleport_alpha: 0.15,
enable_advanced_pipeline: true,
enable_sparse_residual: true,
fista_lambda: 0.1,
fista_threshold: 0.3,
enable_dpp: true,
dpp_quality_weight: 1.0,
};
let results = db.search_advanced(&query_vec, &config)?;SearchConfig 参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
top_k |
usize |
5 |
最终返回的结果数量 |
expand_depth |
usize |
2 |
图谱扩散跳数 |
min_score |
f32 |
0.1 |
余弦相似度下限 |
teleport_alpha |
f32 |
0.0 |
PPR 回跳概率 (0.0~1.0),越高越抑制深层扩散 |
enable_advanced_pipeline |
bool |
false |
认知管线总开关,关闭时退化为普通检索 |
enable_sparse_residual |
bool |
false |
启用 FISTA 残差寻隐 + 影子查询 |
fista_lambda |
f32 |
0.1 |
FISTA L1 正则化系数 |
fista_threshold |
f32 |
0.3 |
残差范数超过此值时触发影子查询 |
enable_dpp |
bool |
false |
启用 DPP 多样性采样 |
dpp_quality_weight |
f32 |
1.0 |
DPP 质量权重幂次 |
enable_text_hybrid_search |
bool |
false |
是否开启 BM25/AC 双路混合搜索 |
text_boost |
f32 |
1.5 |
文本混合查询分数提权倍率 |
hybrid_alpha |
f32 |
0.7 |
混合检索中向量权重 (0~1),(1-alpha) 为稀疏文本权重 |
custom_query_text |
str |
None |
(可选) 手动传入用于文本匹配的原始文本 |
force_brute_force |
bool |
false |
强制使用暴力搜索,禁用 QuIVer 图索引(用于基准测试和需要精确结果的场景) |
💡 所有参数均内置安全钳位:
teleport_alpha被约束在 [0, 1],fista_lambda在 [1e-5, 100],dpp_quality_weight在 [0, 10]。传入越界值不会崩溃,而是被静默钳平。
💡 当
enable_advanced_pipeline = false时,search_advanced的行为与search完全一致。
TriviumDB v0.6.0 新增的检索管线 Hook 系统,允许开发者在 6 个关键阶段注入自定义逻辑,高度自定义检索管线。
查询输入
│
🔌 #1 on_pre_search — 查询预处理(改写向量 / 修改配置 / 提前终止)
│
🔌 #2 on_custom_recall — 自定义召回(可替代内置召回)
│
┌── 内置召回管线 ──┐
│ L1 文本稀疏召回 │
│ L2 向量稠密召回 │
│ L3 布隆预过滤 │
└──────────────────┘
│
🔌 #3 on_post_recall — 召回后处理(业务过滤 / 分数调权)
│
🔌 #4 on_pre_graph_expand — 图扩散前拦截
│
┌── 图谱扩散 ──────┐
│ L6 PPR 扩散 │
│ L7 不应期/抑制 │
└──────────────────┘
│
🔌 #5 on_rerank — 自定义重排序
│
🔌 #6 on_post_search — 最终后处理
│
返回结果
加载一个导出了 C ABI 符号的动态库(.so / .dll / .dylib)作为检索管线 Hook。动态库中的所有符号均为可选,未找到的符号将自动被无操作替代。
Python:
db.load_ffi_hook("./libmy_plugin.so")
results = db.search(query_vec) # 自动经过 C++ HookNode.js:
db.loadFfiHook('./libmy_plugin.so')
const results = db.search(queryVec) // 自动经过 C++ HookRust:
use triviumdb::hook::FfiHook;
let ffi_hook = FfiHook::load("./libmy_plugin.so")?;
db.set_hook(ffi_hook);清除当前的 Hook,恢复为默认的零开销 NoopHook。
Python:
db.clear_hook()Node.js:
db.clearHook()Rust:
db.clear_hook();与 search 相同的检索能力,但额外返回 HookContext 对象,包含管线各阶段的计时统计和 Hook 注入的自定义数据。
Python:
hits, ctx = db.search_with_context(
query_vector=[0.10, -0.48, 0.80, ...],
top_k=10,
expand_depth=2,
min_score=0.1,
)
print(ctx.timings)
# {'hook_pre_search': 0.012, 'hook_custom_recall': 0.001, 'graph_expand': 2.34, ...}
print(ctx.custom_data) # Hook 注入的自定义数据
print(ctx.aborted) # 管线是否被 Hook 提前终止Node.js:
const { hits, context } = db.searchWithContext(queryVec, {
topK: 10,
expandDepth: 2,
minScore: 0.1,
})
console.log(context.timings) // { hook_pre_search: 0.012, graph_expand: 2.34, ... }
console.log(context.customData) // Hook 注入的自定义数据
console.log(context.aborted) // 管线是否被提前终止Rust:
use triviumdb::database::SearchConfig;
let config = SearchConfig {
top_k: 10,
expand_depth: 2,
..Default::default()
};
let (results, ctx) = db.search_hybrid_with_context(None, Some(&query_vec), &config)?;
for (stage, dur) in &ctx.stage_timings {
println!("{}: {:.2}ms", stage, dur.as_secs_f64() * 1000.0);
}在 Rust 中,开发者可以直接实现 SearchHook trait 来创建自定义 Hook:
use triviumdb::hook::{SearchHook, HookContext};
use triviumdb::database::SearchConfig;
use triviumdb::node::SearchHit;
struct MyHook;
impl SearchHook for MyHook {
fn on_pre_search(
&self,
query_vector: &mut Vec<f32>,
config: &mut SearchConfig,
ctx: &mut HookContext,
) {
// 修改查询向量、调整配置等
ctx.custom_data = serde_json::json!({"user_id": "u_12345"});
}
fn on_rerank(
&self,
results: &mut Vec<SearchHit>,
_ctx: &mut HookContext,
) -> Option<Vec<SearchHit>> {
// 自定义重排序逻辑
results.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap());
None // 返回 None 表示使用原地修改,返回 Some 替换结果
}
}
// 注册 Hook
db.set_hook(MyHook);💡 零开销设计:未注册 Hook 时,默认的
NoopHook的所有方法均为空实现,编译器会将它们完全内联消除,对无 Hook 的普通检索完全零开销。
⚠️ FFI 插件安全提示:FfiHook加载的动态库将在进程内执行任意代码,请确保动态库来源可信。
使用类 MongoDB 语法对所有节点的 Payload 进行条件过滤。返回匹配的 NodeView 列表。
Python:
# 单条件
adults = db.filter_where({"age": {"$gt": 18}})
# 多条件组合
results = db.filter_where({
"$and": [
{"age": {"$lt": 30}},
{"role": {"$in": ["admin", "mod"]}}
]
})
# OR 组合
results = db.filter_where({
"$or": [
{"age": {"$lt": 18}},
{"role": "admin"}
]
})支持的操作符:
| 操作符 | 含义 | 值类型 | 示例 |
|---|---|---|---|
$eq |
等于 | 任意 | {"name": {"$eq": "Alice"}} 或直接 {"name": "Alice"} |
$ne |
不等于 | 任意 | {"status": {"$ne": "deleted"}} |
$gt |
大于 | 数字 | {"age": {"$gt": 18}} |
$gte |
大于等于 | 数字 | {"score": {"$gte": 0.8}} |
$lt |
小于 | 数字 | {"age": {"$lt": 30}} |
$lte |
小于等于 | 数字 | {"price": {"$lte": 99.9}} |
$in |
包含于列表 | 数组 | {"role": {"$in": ["admin", "mod"]}} |
$nin |
不在列表中 | 数组 | {"status": {"$nin": ["banned", "deleted"]}} |
$startsWith |
前缀匹配 | 字符串 | {"folder": {"$startsWith": "/地理"}} |
$contains |
包含子串 | 字符串 | {"tag": {"$contains": "重要"}} |
$exists |
字段是否存在 | 布尔 | {"email": {"$exists": true}} |
$size |
数组长度 | 正整数 | {"tags": {"$size": 3}} |
$all |
数组包含所有 | 数组 | {"tags": {"$all": ["A", "B"]}} |
$type |
字段类型 | 字符串 | {"age": {"$type": "number"}} |
$and |
逻辑与 | 条件数组 | {"$and": [{...}, {...}]} |
$or |
逻辑或 | 条件数组 | {"$or": [{...}, {...}]} |
字符串匹配示例(v0.7.1 新增):
# 前缀匹配:匹配 /地理 及其所有子路径
results = db.filter_where({"folder": {"$startsWith": "/地理"}})
# 多前缀 OR 组合:匹配多个路径前缀
results = db.filter_where({
"$or": [
{"folder": {"$startsWith": "/地理"}},
{"folder": {"$startsWith": "/天文"}}
]
})
# 子串包含
results = db.filter_where({"description": {"$contains": "关键词"}})
# search() 中使用 payload_filter 前缀过滤
results = db.search(
query_vector=[0.1, ...],
payload_filter={"folder": {"$startsWith": "/地理"}}
)Rust:
use triviumdb::filter::Filter;
let filter = Filter::And(vec![
Filter::Gt("age".into(), 18.0),
Filter::In("role".into(), vec![json!("admin"), json!("mod")]),
]);
let results = db.filter_where(&filter);支持三种入口:MATCH(图遍历)/ FIND(文档过滤)/ SEARCH(向量检索)。
Python:
# 图遍历
rows = db.tql('MATCH (a)-[:knows]->(b) WHERE b.age > 18 RETURN b')
for row in rows:
node = row.row["b"] # {"id": ..., "payload": {...}, "num_edges": ...}
print(node["payload"])
# 文档过滤
rows = db.tql('FIND {type: "event", heat: {$gte: 0.7}} RETURN *')
# 带内联属性 + WHERE
rows = db.tql('MATCH (a {id: 1})-[]->(b) WHERE b.score >= 0.8 RETURN a, b')Node.js:
const rows = db.tql('MATCH (a)-[:knows]->(b) WHERE b.age > 18 RETURN b')
rows.forEach(row => console.log(row.b.payload))Rust:
let rows = db.tql("MATCH (a)-[:knows]->(b) WHERE b.age > 20 RETURN b")?;
for row in &rows {
if let Some(node) = row.get("b") {
println!("{}: {:?}", node.id, node.payload);
}
}支持 CREATE / SET / DELETE / DETACH DELETE 语法,返回受影响行数和新创建的节点 ID。
Python:
# 创建节点
result = db.tql_mut('CREATE (a {name: "Alice", age: 30})')
print(result["affected"]) # 1
print(result["created_ids"]) # [1]
# 更新属性
db.tql_mut('MATCH (a {name: "Alice"}) SET a.age == 31')
# 删除节点
db.tql_mut('MATCH (a {name: "Alice"}) DELETE a')
# 删除节点及其所有关联边
db.tql_mut('MATCH (a {type: "temp"}) DETACH DELETE a')Node.js:
const result = db.tqlMut('CREATE (a {name: "Alice", age: 30})')
console.log(result.affected) // 1
console.log(result.createdIds) // [1]返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
affected |
int |
受影响的节点数 |
created_ids / createdIds |
list[int] / number[] |
CREATE 新建的节点 ID 列表 |
语法规范:
Query := MATCH Pattern (WHERE Condition)? RETURN ReturnList
| MATCH Pattern (WHERE Condition)? (SET SetExpr | DELETE Ident | DETACH DELETE Ident)
| CREATE NodePat
| FIND JsonFilter RETURN ReturnList
Pattern := NodePat (EdgePat NodePat)*
NodePat := '(' Ident? ('{' PropList '}')? ')'
EdgePat := '-[' (':' Ident)? ']->'
Condition := CompareExpr ((AND | OR) CompareExpr)*
ReturnList := Ident (',' Ident)* | '*'
💡 当起始节点已知 ID 时,强烈建议将
id写入节点属性过滤器。主键id走 O(1) 哈希短路扫描,而type等非主键字段会触发 O(N) 全表扫描(除非已建立属性索引)。
💡 当前仅支持有向边模式
-[]->,不支持无向匹配或反向匹配。
对指定的 JSON Payload 字段建立 O(1) 倒排索引。创建时自动回填全表现有数据,后续 insert / update_payload / delete 自动维护索引一致性。
Python:
db.create_index("name") # 之后 tql('FIND {name: "Alice"} RETURN *') 使用 O(1) 索引
db.create_index("type")Node.js:
db.createIndex('name')
db.createIndex('type')Rust:
db.create_index("name");删除指定字段的索引。查询仍然可用,只是退化为 O(N) 全表扫描。
Python:
db.drop_index("name")Node.js:
db.dropIndex('name')将当前内存中的全部数据写入 .tdb 文件。安全写入流程:先写临时文件 → fsync → 原子 rename → 清除 WAL。
Python:
db.flush()通过构造函数参数或运行时方法切换 WAL(Write-Ahead Log)的同步策略:
| 模式 | 安全性 | 性能 | 说明 |
|---|---|---|---|
"full" |
★★★ | 最慢 | 每条写入后 fsync,断电零丢失 |
"normal" |
★★☆ | 均衡 | flush 到 OS 缓冲区,操作系统崩溃可能丢少量数据(默认) |
"off" |
★☆☆ | 最快 | 不主动 flush,仅适合测试/批量导入 |
运行时切换:
db.set_sync_mode("full") # 切到最安全模式
db.set_sync_mode("off") # 批量导入时临时提速启动后台守护线程,定时在后台串行化执行数据压缩与全量落盘(包含 flush + WAL 截断清理)。
Python:
db.enable_auto_compaction(interval_secs=30) # 每 30 秒后台自动落盘
db.disable_auto_compaction() # 停止后台压缩线程Rust:
db.enable_auto_compaction(Duration::from_secs(30));
db.disable_auto_compaction();主动触发一次全量数据重写与压实。此调用会阻塞当前线程,直到所有的内存数据被安全落盘,并彻底截断清理旧的 WAL 文件。 为了极致的崩溃安全性,执行压实时会短暂阻塞前台读写。强烈建议在关闭了自动压缩后,于业务低峰期(如凌晨调度)执行此方法。
Python:
db.compact()Rust:
db.compact()?;设置 MemTable 内存使用上限。当估算内存超过限额时,写操作完成后自动触发 flush。
Python:
db.set_memory_limit(mb=256) # 限制为 256 MB
db.set_memory_limit(mb=0) # 取消限制(默认)Python:
usage_bytes = db.estimated_memory()
print(f"当前内存占用: {usage_bytes / 1024 / 1024:.1f} MB")对指定节点的长文本内容提取 BM25 特征,用于后续的混合检索召回。需在节点 insert 后调用。
Python:
db.index_text(id=42, text="Rust 在嵌入式领域取得突破")建立基于 AC 自动机 (Aho-Corasick) 的精确词汇匹配索引,极速锁定特征锚点。
Python:
db.index_keyword(id=42, keyword="Rust")在数据初始化批量调用完毕后,必须调用此方法完成底层 AC 自动机的编译与全局文本 IDF 频率汇算。之后方可进行 search_hybrid 混合检索。
Python:
db.build_text_index()返回当前数据库中所有活跃节点的 ID 列表(顺序不定)。可用于遍历全库或批量操作。
Python:
ids = db.all_node_ids() # 返回 list[int]
print(f"共 {len(ids)} 个节点")Rust:
let ids = db.all_node_ids(); // Vec<NodeId>TriviumDB v0.7.0 起采用自研的 QuIVer SOTA 级 ANN 图索引,全自动双引擎向量索引路由,无需手动 rebuild_index() 接口:
| 条件 | 检索引擎 | 召回行为 |
|---|---|---|
| < 1 万节点 或 QuIVer 未就绪 | BruteForce | 100% 精确召回,零误差 |
| ≥ 1 万节点 + 索引就绪 | QuIVer (BQ + Vamana) | BQ 签名 + 图导航 + f32 精排,Recall@10 > 97% |
QuIVer 索引支持增量 Insert/Delete/Update,无需全量重建。索引以独立的 .tdb.quiver 文件持久化,重启后零延迟恢复。
💡 如果你的业务对 100% 召回率有强需求(如金融/医疗),可以通过
force_brute_force: true强制使用 BruteForce。
当需要更换 Embedding 模型(维度发生变化)时,使用 migrate 将旧库的结构迁移到新维度。
将当前数据库的所有节点 Payload、图谱边复制到一个全新的数据库文件中,向量以零向量占位(因为维度变了,旧向量无法直接复用)。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
new_path |
str |
新数据库文件路径 |
new_dim |
int |
新的向量维度 |
返回值: 所有已迁移节点的 ID 列表(list[int])
Python:
# 第一步:迁移结构(保留 payload + 边,向量置零)
with triviumdb.TriviumDB("old.tdb", dim=768) as old_db:
node_ids = old_db.migrate("new.tdb", new_dim=1536)
# 第二步:打开新库,用新模型逐节点更新向量
with triviumdb.TriviumDB("new.tdb", dim=1536) as new_db:
for nid in node_ids:
payload = new_db.get(nid).payload
new_vec = new_model.encode(payload["text"]).tolist()
new_db.update_vector(new_vec, nid)Rust:
// 迁移结构
let (mut new_db, node_ids) = old_db.migrate_to("new.tdb", 1536)?;
// 更新向量
for &nid in &node_ids {
let new_vec = new_model.encode(&payload_map[&nid]);
new_db.update_vector(nid, &new_vec)?;
}
new_db.flush()?;
⚠️ 迁移不修改原数据库,原库仍可正常使用。新库创建完毕后,需要手动更新所有向量后才能进行有效的向量检索。
💡 如果希望同时切换 dtype(例如从 f32 换 f16),需在创建新库时指定
dtype参数:TriviumDB("new.tdb", dim=1536, dtype="f16")。
TriviumDB 提供轻量级事务,采用验证前置(Dry-Run)架构:所有操作先缓冲在内存中,commit() 分两阶段执行——首先在纯内存验证全部约束(维度、节点存在性、ID 冲突),全部通过后才一次性写入。
特性:
commit()返回Err时,底层数据没有被修改一个字节,可加入日志后安全重试- 在同一事务内,
insert_with_id(999)后立即link(..., 999)是完全合法的(虚拟状态叠加给 999 号打过标记) rollback()(或直接drop事务对象)将丢弃所有缓冲操作
let mut tx = db.begin_tx();
tx.insert(&vec1, json!({"type": "event"}));
tx.insert_with_id(9999, &vec2, json!({"type": "person"}));
tx.link(1, 9999, "attended", 1.0);
// 原子提交 → 两阶段: 干跑验证 → 物理写入
let ids = tx.commit()?;
// 或显式回滚(丢弃所有操作)
// tx.rollback();
⚠️ 事务目前仅在 Rust API 中可用,Python 侧暂未暴露。
| 语法 | 等价调用 | 说明 |
|---|---|---|
len(db) |
db.node_count() |
当前活跃节点数 |
42 in db |
db.contains(42) |
节点是否存在 |
print(db) |
db.__repr__() |
输出如 TriviumDB(dtype=f32, nodes=100, dim=1536) |
with db: |
__enter__ / __exit__ |
退出时自动 flush() |
节点的完整视图,通过 get() 或 filter_where() 返回。
| 属性 (Python) | 属性 (Rust) | 类型 | 说明 |
|---|---|---|---|
id |
id |
u64 |
全局唯一节点 ID |
vector |
vector |
list[float] / Vec<T> |
节点的特征向量 |
payload |
payload |
dict / serde_json::Value |
JSON 元数据 |
edges |
edges |
list[Edge] / Vec<Edge> |
详细出边列表(包含 target_id, label, weight) |
num_edges |
edges.len() |
int / usize |
快速获取出边数量 |
向量检索命中结果,通过 search() 返回。
| 属性 | 类型 | 说明 |
|---|---|---|
id |
u64 |
命中节点 ID |
score |
f32 |
相似度得分 |
payload |
dict |
节点元数据 |
Cypher 查询结果行,通过 query() 返回。
| 属性 | 类型 | 说明 |
|---|---|---|
row |
dict[str, dict] |
变量名 → 节点摘要字典 |
图谱边的内部结构。
| 字段 | 类型 | 说明 |
|---|---|---|
target_id |
NodeId (u64) |
目标节点 ID |
label |
String |
关系类型标签 |
weight |
f32 |
权重(支持负值) |
Hook 管线执行上下文,通过 search_with_context() 返回。
| 属性 (Python) | 属性 (Node.js) | 属性 (Rust) | 类型 | 说明 |
|---|---|---|---|---|
timings |
timings |
stage_timings |
dict / Object / Vec<(String, Duration)> |
各管线阶段的耗时(Python/JS 单位毫秒) |
custom_data |
customData |
custom_data |
dict / Object / serde_json::Value |
Hook 注入的自定义数据 |
aborted |
aborted |
abort |
bool |
管线是否被 Hook 提前终止 |