triviumdb 0.5.0

A high-performance memory-mmap hybrid search engine built for AI, combining dense vector, sparse text, graph relations, and JSON metadata.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# TriviumDB API 完整参考


> **版本**: v0.5.0  
> **语言**: Rust 核心 + Python 绑定 (PyO3) + Node.js 绑定 (napi-rs)  
> **许可**: Apache-2.0

---

## 目录


- [数据库生命周期]#数据库生命周期
- [节点 CRUD]#节点-crud
- [图谱操作]#图谱操作
- [向量检索]#向量检索
- [元数据过滤]#元数据过滤
- [Cypher 图谱查询]#cypher-图谱查询
- [持久化与压缩]#持久化与压缩
- [内存管理]#内存管理
- [工具方法]#工具方法
- [维度迁移]#维度迁移
- [事务支持]#事务支持-rust-only
- [Pythonic 魔术方法]#pythonic-魔术方法
- [数据类型说明]#数据类型说明

---

## 数据库生命周期


### Python


```python
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 写入安全级别,详见[持久化与压缩]#持久化与压缩 |

### Rust


```rust
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 / 二值化向量 |

---

## 节点 CRUD


### insert — 插入节点


向数据库写入一个新节点,同时携带向量和 JSON 元数据。返回自动分配的 `u64` 节点 ID。

**Python:**
```python
node_id = db.insert(
    vector=[0.12, -0.45, 0.78, ...],       # 向量(长度必须等于 dim)
    payload={"text": "小明喜欢吃苹果", "ts": 1711440000}  # 任意 JSON
)
```

**Rust:**
```rust
let id = db.insert(&[0.12, -0.45, 0.78], json!({"text": "Hello"}))?;
```

### insert_with_id — 带自定义 ID 插入


适用于从外部系统导入数据时,保持原始 ID 不变。如果 ID 已存在会返回错误。

**Python:**
```python
db.insert_with_id(id=42, vector=[0.1, 0.2, 0.3, ...], payload={"source": "external"})
```

**Rust:**
```rust
db.insert_with_id(42, &[0.1, 0.2, 0.3], json!({"source": "external"}))?;
```

### batch_insert — 批量插入


一次性插入多个节点,返回所有新 ID 的列表。

**Python:**
```python
ids = db.batch_insert(
    vectors=[[0.1, 0.2, ...], [0.3, 0.4, ...]],
    payloads=[{"name": "A"}, {"name": "B"}]
)
```

### batch_insert_with_ids — 带自定义 ID 批量插入


**Python:**
```python
db.batch_insert_with_ids(
    ids=[100, 101],
    vectors=[[0.1, 0.2, ...], [0.3, 0.4, ...]],
    payloads=[{"name": "A"}, {"name": "B"}]
)
```

### get — 获取单个节点


按 ID 获取节点的完整视图,包含向量、元数据和边的数量。不存在时返回 `None`。

**Python:**
```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)  # 3
```

**Rust:**
```rust
if let Some(view) = db.get(42) {
    println!("ID={}, edges={}", view.id, view.edges.len());
    println!("payload={:?}", view.payload);
}
```

### update_payload — 更新元数据


整体替换节点的 JSON 元数据(向量和图谱关系不受影响)。

**Python:**
```python
db.update_payload(id=42, payload={"text": "更新后的文本", "version": 2})
```

### update_vector — 更新向量


就地替换节点的向量(维度必须一致,元数据和图谱关系不受影响)。

**Python:**
```python
db.update_vector(vector=[0.5, 0.6, 0.7, ...], id=42)
```

### delete — 删除节点


**三层原子联删**:同时清除该节点的向量、元数据以及所有关联的图谱边(包括其他节点指向它的入边)。

**Python:**
```python
db.delete(42)
```

**Rust:**
```rust
db.delete(42)?;
```

> ⚠️ 删除操作不可逆。删除后,该节点的向量区间被逻辑置零,待 Compaction 时物理回收。

---

## 图谱操作


### link — 建立有向边


在两个节点之间建立一条有向带权边。两个端点必须已存在,否则返回错误。

**Python:**
```python
db.link(src=1, dst=2, label="knows", weight=0.95)
```

**Rust:**
```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)`
### unlink — 断开边


移除从 `src` 到 `dst` 的**所有**边(无论 label 是什么)。

**Python:**
```python
db.unlink(src=1, dst=2)
```

**Rust:**
```rust
db.unlink(1, 2)?;
```

### neighbors — N 跳邻居


从指定节点出发,沿有向边进行广度优先遍历(BFS),返回 N 跳以内所有可达节点的 ID。

**Python:**
```python
neighbor_ids = db.neighbors(id=1, depth=2)  # 2 跳以内的所有邻居
```

**Rust:**
```rust
let ids = db.neighbors(1, 2);
```

---

## 搜索与召回


### search_hybrid — 双路混合认知检索 (强推)


TriviumDB 核心杀手锏:引入稀疏文本表示(BM25/AC自动机)与稠密向量(Dense Vector)构成双路融合召回锚定,再在第二阶段进行图谱激活扩散。这极大弥补了纯向量检索容易导致的专有名词幻觉(Hallucination)。

**Python:**
```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}")
```

### search — 纯向量图扩散检索 (基础)


TriviumDB 的基础检索能力(退化态):**先用核心稠密向量相似度找到锚点,再沿图谱关系向外扩散**。

**Python:**
```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:**
```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)
                           最终排序结果
```

---

### search_advanced — 认知管线检索


内置九层认知管线的全功能入口。通过 `SearchConfig` 参数化控制 FISTA 残差寻隐、PPR 图扩散、DPP 多样性采样等高级特性。

**Python:**
```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:**
```javascript
const results = db.searchAdvanced(queryVector, {
    topK: 10,
    expandDepth: 2,
    teleportAlpha: 0.15,
    enableAdvancedPipeline: true,
    enableSparseResidual: true,
    enableDpp: true,
});
```

**Rust:**
```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` | 文本混合查询分数提权倍率 |
| `enable_bq_coarse_search` | `bool` | `false`| 是否开启 BQ 第一阶段二进制指纹粗筛 |
| `bq_candidate_ratio` | `f32` | `0.05`| BQ 粗排后候选集占总数据量的比例 |
| `hybrid_alpha` | `f32` | `0.7` | 混合检索中向量权重 (0~1),(1-alpha) 为稀疏文本权重 |
| `custom_query_text` | `str`| `None` | (可选) 手动传入用于文本匹配的原始文本 |

> 💡 所有参数均内置安全钳位:`teleport_alpha` 被约束在 [0, 1],`fista_lambda` 在 [1e-5, 100],`dpp_quality_weight` 在 [0, 10],`bq_candidate_ratio` 在 [0.001, 1.0]。传入越界值不会崩溃,而是被静默钳平。

> 💡 当 `enable_advanced_pipeline = false` 时,`search_advanced` 的行为与 `search` 完全一致。

---

## 元数据过滤


### filter_where — 高级条件过滤


使用类 MongoDB 语法对所有节点的 Payload 进行条件过滤。返回匹配的 `NodeView` 列表。

**Python:**
```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"]}}` |
| `$and` | 逻辑与 | 条件数组 | `{"$and": [{...}, {...}]}` |
| `$or` | 逻辑或 | 条件数组 | `{"$or": [{...}, {...}]}` |

**Rust:**
```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);
```

---

## Cypher 图谱查询


### query — 类 Cypher 语法查询


使用类似 Neo4j Cypher 的语法,沿图谱路径模式进行匹配查询。

**Python:**
```python
# 沿 knows 边查找

rows = db.query("MATCH (a)-[:knows]->(b) RETURN b")
for row in rows:
    node = row.row["b"]    # {"id": ..., "payload": {...}, "num_edges": ...}
    print(node["payload"])

# 带内联属性过滤

rows = db.query("MATCH (a {id: 1})-[]->(b) RETURN a, b")

# 带 WHERE 条件

rows = db.query('MATCH (a)-[:knows]->(b) WHERE b.age > 18 RETURN b')

# AND / OR 复合条件

rows = db.query('MATCH (a)-[]->(b) WHERE b.age > 18 AND b.role == "admin" RETURN b')
```

**Rust:**
```rust
let rows = db.query("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);
    }
}
```

**语法规范:**

```
Query     := MATCH Pattern (WHERE Condition)? RETURN ReturnList
Pattern   := NodePat (EdgePat NodePat)*
NodePat   := '(' Ident? ('{' PropList '}')? ')'
EdgePat   := '-[' (':' Ident)? ']->'
Condition := CompareExpr ((AND | OR) CompareExpr)*
ReturnList:= Ident (',' Ident)*
```

**返回值 `QueryRow`:**

| 属性 | 类型 | 说明 |
|------|------|------|
| `row` | `dict[str, dict]` | 变量名 → `{"id": int, "payload": dict, "num_edges": int}` |

> 💡 当起始节点已知 ID 时,强烈建议将 `id` 写入节点属性过滤器。远主键 `id`**O(1) 哈希短路扫描**,而 `type` 等非主键字段会触发 O(N) 全表扫描。

> 💡 当前仅支持**有向**边模式 `-[]->` ,不支持无向匹配或反向匹配。

---

## 持久化与压缩


### flush — 手动落盘


将当前内存中的全部数据写入 `.tdb` 文件。安全写入流程:先写临时文件 → fsync → 原子 rename → 清除 WAL。

**Python:**
```python
db.flush()
```

### WAL 同步模式


通过构造函数参数或运行时方法切换 WAL(Write-Ahead Log)的同步策略:

| 模式 | 安全性 | 性能 | 说明 |
|------|--------|------|------|
| `"full"` | ★★★ | 最慢 | 每条写入后 fsync,断电零丢失 |
| `"normal"` | ★★☆ | 均衡 | flush 到 OS 缓冲区,操作系统崩溃可能丢少量数据(**默认**|
| `"off"` | ★☆☆ | 最快 | 不主动 flush,仅适合测试/批量导入 |

**运行时切换:**
```python
db.set_sync_mode("full")   # 切到最安全模式
db.set_sync_mode("off")    # 批量导入时临时提速
```

### enable_auto_compaction — 后台自动压缩


启动后台守护线程,定时在后台串行化执行数据压缩与全量落盘(包含 `flush` + WAL 截断清理)。

**Python:**
```python
db.enable_auto_compaction(interval_secs=30)  # 每 30 秒后台自动落盘
db.disable_auto_compaction()                 # 停止后台压缩线程
```

**Rust:**
```rust
db.enable_auto_compaction(Duration::from_secs(30));
db.disable_auto_compaction();
```

### compact — 手动强制压实 (Manual Compaction)


主动触发一次全量数据重写与压实。**此调用会阻塞当前线程**,直到所有的内存数据被安全落盘,并彻底截断清理旧的 WAL 文件。
为了极致的崩溃安全性,执行压实时会短暂阻塞前台读写。强烈建议在关闭了自动压缩后,于业务低峰期(如凌晨调度)执行此方法。

**Python:**
```python
db.compact()
```

**Rust:**
```rust
db.compact()?;
```


---

## 内存管理


### set_memory_limit — 内存预算控制


设置 MemTable 内存使用上限。当估算内存超过限额时,写操作完成后自动触发 flush。

**Python:**
```python
db.set_memory_limit(mb=256)  # 限制为 256 MB
db.set_memory_limit(mb=0)    # 取消限制(默认)
```

### estimated_memory — 查询当前内存占用


**Python:**
```python
usage_bytes = db.estimated_memory()
print(f"当前内存占用: {usage_bytes / 1024 / 1024:.1f} MB")
```

---

## 文本索引与稀疏检索


### index_text — 建立全文稀疏索引

对指定节点的长文本内容提取 BM25 特征,用于后续的混合检索召回。需在节点 insert 后调用。

**Python:**
```python
db.index_text(id=42, text="Rust 在嵌入式领域取得突破")
```

### index_keyword — 建立精确关键词索引

建立基于 AC 自动机 (Aho-Corasick) 的精确词汇匹配索引,极速锁定特征锚点。

**Python:**
```python
db.index_keyword(id=42, keyword="Rust")
```

### build_text_index — 编译倒排字典树

在数据初始化批量调用完毕后,**必须调用此方法**完成底层 AC 自动机的编译与全局文本 IDF 频率汇算。之后方可进行 `search_hybrid` 混合检索。

**Python:**
```python
db.build_text_index()
```

---

## 工具方法


### all_node_ids — 获取全部节点 ID


返回当前数据库中所有活跃节点的 ID 列表(顺序不定)。可用于遍历全库或批量操作。

**Python:**
```python
ids = db.all_node_ids()          # 返回 list[int]
print(f"共 {len(ids)} 个节点")
```

**Rust:**
```rust
let ids = db.all_node_ids();     // Vec<NodeId>
```

### BQ 自动索引说明


TriviumDB v0.5.0 起采用**全自动双引擎向量索引路由**,不再提供手动 `rebuild_index()` 接口:

| 条件 | 检索引擎 | 召回行为 |
|------|----------|----------|
| < 2 万节点 或 Mmap 未就绪 | **BruteForce** | 100% 精确召回,零误差 |
| ≥ 2 万节点 + Mmap 模式 + 索引就绪 | **BQ 三阶段火箭** | 二进制粗排 + f32 精排,Recall@10 > 97% |

BQ 索引在**后台 Compaction 线程**中自动构建,无需也无法手动触发。索引元数据持久化在 `.tdb` 文件的 BQ Metadata Block 中,重启后零延迟恢复。

> 💡 如果你的业务对 100% 召回率有强需求(如金融/医疗),可以通过 `StorageMode::Rom` 模式强制使用 BruteForce(BQ 仅在 `Mmap` 模式下激活)。

---

## 维度迁移


当需要更换 Embedding 模型(维度发生变化)时,使用 `migrate` 将旧库的结构迁移到新维度。

### migrate — 迁移到新维度


将当前数据库的所有节点 Payload、图谱边复制到一个全新的数据库文件中,向量以零向量占位(因为维度变了,旧向量无法直接复用)。

**参数:**

| 参数 | 类型 | 说明 |
|------|------|------|
| `new_path` | `str` | 新数据库文件路径 |
| `new_dim` | `int` | 新的向量维度 |

**返回值:** 所有已迁移节点的 ID 列表(`list[int]`)

**Python:**
```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:**
```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")`
## 事务支持 (Rust Only)


TriviumDB 提供轻量级事务,采用**验证前置(Dry-Run)架构**:所有操作先缓冲在内存中,`commit()` 分两阶段执行——首先在纯内存验证全部约束(维度、节点存在性、ID 冲突),全部通过后才一次性写入。

**特性:**
- `commit()` 返回 `Err` 时,**底层数据没有被修改一个字节**,可加入日志后安全重试
- 在同一事务内,`insert_with_id(999)` 后立即 `link(..., 999)` 是完全合法的(虚拟状态叠加给 999 号打过标记)
- `rollback()`(或直接 `drop` 事务对象)将丢弃所有缓冲操作

```rust
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 侧暂未暴露。

---

## Pythonic 魔术方法


| 语法 | 等价调用 | 说明 |
|------|----------|------|
| `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()` |

---

## 数据类型说明


### NodeView


节点的完整视图,通过 `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` | 快速获取出边数量 |

### SearchHit


向量检索命中结果,通过 `search()` 返回。

| 属性 | 类型 | 说明 |
|------|------|------|
| `id` | `u64` | 命中节点 ID |
| `score` | `f32` | 相似度得分 |
| `payload` | `dict` | 节点元数据 |

### QueryRow


Cypher 查询结果行,通过 `query()` 返回。

| 属性 | 类型 | 说明 |
|------|------|------|
| `row` | `dict[str, dict]` | 变量名 → 节点摘要字典 |

### Edge (Rust)


图谱边的内部结构。

| 字段 | 类型 | 说明 |
|------|------|------|
| `target_id` | `NodeId (u64)` | 目标节点 ID |
| `label` | `String` | 关系类型标签 |
| `weight` | `f32` | 权重(支持负值) |