第 32 篇
工程技术
SQLite 流式 Top-K 与 pgvector 距离检索
结合实际开发项目,讨论SQLite 流式 Top-K 与 pgvector 距离检索,说明设计理由、关键源码、验证方法及适用边界。
本文目录 · 8 节
本文属于 Memory Center:AI 编程上下文与记忆系统工程实践,第 32 篇,位于“存储与运维治理”模块。案例背景统一采用实际开发项目;复现步骤使用脱敏教学样例,不代表特定生产事故。
从实际问题出发
向量很多时,先把全部结果读进内存再排序会带来较大峰值。流式 Top-K 可以限制保留的候选数,但它不会让逐条计算距离的工作自动消失。
区分空间与时间复杂度
扫描 N 个向量,只保留 K 个候选,内存可以主要随 K 增长,而距离计算仍随扫描量增长。扫描预算又会影响覆盖范围;“只保留一百条”不等于“只访问一百条”。

图中展示的是本篇关注的职责和顺序。正常流程之外,还要结合下面的源码与实验检查失败分支;它不是对某次线上调用的运行时追踪。
数据库索引也有适用条件
PostgreSQL 路径使用距离查询,是否建立近似索引与模型维度等条件有关。精确和近似召回的质量与延迟需分别测量,不能把后端名称等同于恒定性能。
Top-K 控制的到底是什么
假设 N 条向量逐项计算距离,以大小为 K 的堆保留当前最优候选。典型维护成本约为 O(N log K),额外候选存储约为 O(K);这描述算法框架,具体库函数可能采用不同实现。
当前 SQLite 路径的扫描预算是进入扫描前检查规模,超过预算会返回明确错误,不能描述成“悄悄截取前若干向量后仍返回完整结果”。PostgreSQL 的索引路径则要单独考虑近似召回与后过滤的覆盖边界。
关键源码与阅读方法
源码基线为 Memory Center 6e90553(文档标注 5.0.0b24)。定位:memory_center/platform/retrieval.py,函数 scored_rows,起始行 131。
以下为当前基线中的函数代码;依赖项目模块,不能作为独立脚本执行。
def scored_rows():
for row in rows:
other = json.loads(row['embedding'])
if visible(row) and len(other) == len(vector):
denom = norm * (math.sqrt(sum(v * v for v in other)) or 1)
yield sum(a * b for a, b in zip(vector, other, strict=False)) / denom, row
阅读时先找输入由谁提供,再区分纯计算、读取和写入;遇到异常或提前返回,追问调用方会得到什么,以及已有状态是否仍然有效。上面的代码只证明展示范围内的实现,跨模块行为应继续查看调用处和相应测试。
用一个小实验核对设计
建议在独立临时目录和隔离数据中操作,使用虚构的接口、文档与项目名称。
- 在隔离样本里固定 K、增加向量数量。
- 记录内存与耗时。
- 再改变扫描预算观察候选差异。
**要核对的结果:**图表须来自真实采样,明确预算截断和索引条件,不能只展示理想复杂度。
可把观察记录为下表;没有执行的项写“未执行”,不能用设计预期冒充实测结果。
| 核对项 | 应保留的证据 |
|---|---|
| 使用条件 | 源码版本、配置、输入与项目范围 |
| 正常行为 | 实际返回、来源位置或状态变化 |
| 关键失败分支 | 错误码、可见结果与原状态是否保留 |
| 结论范围 | 已覆盖、未覆盖和需要进一步验证的条件 |
适用边界与继续阅读
本篇以静态源码与项目设计为依据,给出可执行的核对方法,未据此宣称已经完成新的性能或生产环境测试。不同版本的入口、默认值和底层实现可能变化,应先核对当前合同,再把方法用于自己的实际开发项目。
理解这一节后,可以回到专题总导航,沿同一模块继续阅读;顺序学习时使用专栏内的上一篇和下一篇。涉及具体技术选择,应连同本篇的代价与限制一起采用。