一次目录查找。
一次连续扫描。
过滤向量搜索通常是在对过滤条件一无所知的索引上进行散乱跳转。Telys 转而掌控物理布局:在分区键上,"最近邻且键等于 x"是一次 O(1) 目录查找加一次连续块的顺序扫描。本页先介绍今日已交付的运行时,再介绍其正在收敛的架构——后者标注为规范。
引擎掌控每个向量的存储位置。
集合在创建时声明 partition_by,布局随键而定。基础段按分区聚簇——每个键映射至一段连续切片——近期写入则紧邻其旁,存于可变的 Arrow 形态增量中。
按分区聚簇
向量按分区键排序存储,每个分区构成一段连续块。范围查询读取内存中的一段连续区间,而非散布于索引各处的行。
O(1) 键 → 切片
目录将每个分区值映射至其在基础段中的 (offset, length)。解析过滤条件是一次字典查找,而非索引遍历。
Arrow 形态写入
add 与 upsert 追加于此,每行附有单调递增的写入 LSN。增量可立即查询,并通过统一扫描路径与基础切片合并。
一次范围查询的执行过程。
col.search(qvec, where={"tenant_id": "acme"}, top_k=10)
过滤条件指定集合创建时所用的分区键。
O(1) 查找:分区值解析为基础段中的 (offset, length)。无需候选生成,无需图入口点。
对一段连续块进行 SIMD 精确评分。此路径召回率为 1.0——这是扫描,而非近似。该步骤的实测 p50/p95 发布于基准测试页面,每项数据均绑定其召回门限与测试机信息。
同一键的行在 Arrow 形态的 delta 中经由相同路径评分。写入对紧随其后的查询立即可见。
命中项在快照 LSN 处过滤:已标记墓碑及被取代的版本永不浮现。Top-k 结果携带 explain 载荷返回。
超大分区走声明式分叉:build_ivf 对超过行数阈值的分区构建逐分区 IVF,查询经由该索引路由并附带精确重排——以召回率下限为校准基准,并在执行计划中具名标注。
每条结果均具名其执行计划。
explain=True 返回查询实际所走的物理计划。命中分区键时,返回连续切片扫描;超大分区声明 IVF 分叉;偏离键的过滤器回退至 scatter-gather——载荷中说明原因。
hits = col.search(qvec, where={"tenant_id": "acme"}, top_k=10, explain=True)
hits["explain"]["plan"]
# on the partition key → "PartitionSliceExactF32" # one contiguous slice, exact, recall 1.0
# oversized partition → "PartitionIVFRerankF32" # per-partition IVF + exact rerank
# off-key filter → "ScatterGatherExact" # fallback — and it says why:
hits["explain"]["fallback_reason"]
# "path is not the physical partition key"无任何内容被覆写。版本只会被取代。
写入模型为仅追加 MVCC。upsert 为逻辑 id 写入新版本,并将前一版本标记为已取代;delete 在删除 LSN 处放置墓碑;snapshot() 固定一致读视图;compact() 将 delta 折叠入基础段,并丢弃所有快照均不可见的内容。
col.upsert(vectors, ids=ids, metadata=metadata) # a new version; the prior one is superseded col.delete(["doc-41"]) # tombstone at a delete LSN — no in-place erase lsn = col.snapshot() # pin a consistent read view at an LSN col.compact() # fold delta into base; drop superseded rows col.build_ivf(min_rows=20000, target_recall=0.98)
| 调用 | 功能说明 |
|---|---|
| 添加 / add_texts | 插入新行。重复 id 将被拒绝——同一逻辑 id 的第二条物理行须使用 upsert,此为有意设计。 |
| 更新插入 / upsert_texts | 为逻辑 id 写入新版本;前一版本被取代,不会原地覆写。 |
| 搜索 / search_text | 带过滤的 top-k 检索。explain=True 将物理计划附加至结果。 |
| delete | 在删除 LSN 处为逻辑行放置墓碑。 |
| compact | 将 delta 折叠入基础段;丢弃已标记墓碑及被取代的版本。 |
| build_ivf | 对超过行数阈值的分区构建逐分区 IVF,以召回率下限为校准基准。 |
| snapshot | 返回一个固定一致读视图的 LSN。 |
| save / stats | 将集合持久化至磁盘;报告行数、分区及布局信息。 |
以下内容为规范说明,而非已发布的 API 参考。这是运行时正在收敛的底层基础。面向 SDK 的接口层已冻结,底层替换对调用方不可见。
一个规划器。一套扁平 IR。一个执行器。
三个前端汇入同一规划器,规划器生成一套扁平物理中间表示,由一个 Mojo 向量化执行器直接在 Arrow 缓冲区上执行。
内存模型(remember · recall · as_of)、查询 API(point_get · scan · search · hybrid_search)及 fabric。统一入口契约,无逐 API 引擎。
逻辑规划与物理规划集于一处。选择率由段统计信息估算;执行计划显式呈现并随结果返回。
由整数槽位绑定的扁平算子数组。算子间寄存器为行集——位图、有序行 id 或选择向量。
在 Arrow 缓冲区与 FAISS 候选数组上向量化执行。SIMD 热路径不经过 Python;压缩的 Parquet 页面优先解码至暂存缓冲区。
变更层
预写日志提供持久性与顺序保证,可变 Arrow 形态 delta 提供即时可见性——这是 Parquet 单独作为表层所欠缺的能力。
已封存,不可变
持久化压缩列式段。页脚统计信息驱动段与行组裁剪;已封存文件永不被修改。
FAISS ANN
逐段 FAISS 索引,绑定至段的校验和与版本,以只读方式映射,生命周期与读快照绑定。
裁剪与词法检索
Zone map、布隆过滤器及位图用于裁剪;BM25 sidecar 用于稀疏检索与分数融合。
SCAN FILTER PROJECT POINT_GET RANGE_GET AGGREGATE TOP_K HASH_JOIN HASH_GROUP_BY SORT ANN_SEARCH SPARSE_SEARCH FUSE RERANK MATERIALIZE
WAL 优先。立即可见。后台封存。
带校验和与单调 LSN 的仅追加帧。恢复时重放最后封存 LSN 之后的记录,并在首个校验和错误处截断。
写入落入可变 delta 后立即可查询——已封存段与 delta 通过同一扫描路径合并。
超过大小、行数或时效阈值后,delta 将被排序并写入 Parquet 段,连同其 .vidx 及附属文件,再通过原子 manifest 替换发布。
后台合并将小段折叠合并,丢弃已墓碑的行并重建附属文件——受预算约束,确保设备端部署保持静默。
已封存的段永不被修改。读取操作固定(manifest 快照、LSN);写入方封存新段并替换 manifest,不干扰进行中的读取。垃圾回收等待最旧的活跃快照。
由过滤器选择执行计划,而非反其道而行。
过滤式 ANN 是基于选择率的自适应规划:规划器从段统计信息中估算通过过滤器的行数,再选取能满足召回率约定的最低成本策略。
预过滤 → 精确
先执行标量或位图预过滤,再对存活行进行精确 SIMD 评分。行数低于阈值时完全跳过 ANN——精确扫描,召回率 1.0。
Allow-bitmap 遍历
ANN 遍历携带 allow-bitmap,索引仅返回通过过滤器的行。
ANN → 后过滤
先执行 ANN 并自适应超量获取,再进行后过滤。过滤器淘汰率低,候选生成优先。