题干与适用场景
这是检索系统设计题,不是背诵某个向量数据库名称。目标是对 embedding 做语义搜索,同时满足租户隔离、元数据和权限过滤、延迟、可检索新鲜度与相关性评估。假设 embedding 由上游模型生成,文档会更新和删除,系统既要支持批量回填,也要支持持续写入。
面试官考察点
- 能否拆分写入、向量生成、索引构建、查询服务和评估链路。
- 能否说明精确搜索为何昂贵,并根据约束选择近似最近邻(ANN)方案。
- 能否在不牺牲召回和租户隔离的前提下执行过滤。
- 能否定义更新、删除、模型升级和重建期间的可见性语义。
- 能否给出召回、延迟、成本和新鲜度指标,而不是把相似度当成正确性。
回答前需要澄清的问题
- 向量维度、距离函数、每租户文档量和查询 QPS 是多少?
- 租户与 ACL 是必须满足的硬过滤,还是允许检索后再删除结果?
- 一分钟新鲜度适用于每次写入,还是只适用于热点集合?
- 是否需要关键词与向量混合检索、重排,还是只做近邻检索?
- embedding 模型是否会更换?迁移期间旧向量是否必须继续可查?
30 秒回答框架
“我会把系统拆成持久化写入日志、embedding worker、有版本的向量索引和无状态查询层。每条记录带租户、ACL、文档版本、模型版本和删除状态。查询先做授权,再路由到租户分片,执行带过滤的 ANN,并可对小候选集重排。新写入进入可变 delta 索引,后台构建不可变 segment;查询合并两者并按版本隐藏旧数据。评估上用精确搜索或标注集校验召回@20,同时监控 p95、过滤错误、新鲜度延迟和每次查询成本。”
分步骤深入解答
第一步:定义数据与可见性契约
保存 documentid、tenantid、ACL 属性、embedding 模型版本、内容版本、向量和更新时间。删除应写成带版本的墓碑记录,不能假设所有副本已经立即删除。查询必须先完成授权;租户和 ACL 是硬约束,相关性排序只能在授权候选中进行。
第二步:选择 ANN 索引与分片
对 N 个 D 维向量做暴力搜索,大致需要 O(N × D) 次距离计算。一亿向量无法满足 150 毫秒目标,因此选择 HNSW 或倒排聚类等 ANN 索引。HNSW 通常以较高召回换取内存;聚类或量化能降低内存和成本,却增加调参与召回风险。先按租户命名空间或分片,再把热点租户单独拆分并复制读容量。不要声称某个库有通用复杂度或召回数字,必须按维度和实现基准测试。
第三步:把过滤纳入检索正确性
后过滤可能先找到 20 个相似但属于其他租户的向量,过滤后只剩很少结果;预过滤能缩小候选空间,却可能让低选择性过滤变慢。可行方案是让可过滤元数据与向量路径一起建索引,根据选择性动态扩大候选池,或为高选择性条件使用专用 segment。Pinecone 文档把元数据谓词作为查询契约的一部分;回答必须说明授权结果不足 20 条时的行为。
第四步:分离新写入与压缩 segment
先把写入追加到可靠日志和小型可变 delta 索引。查询同时读取基础 segment 与 delta,按文档版本合并并隐藏墓碑 ID。后台压缩生成新 segment,校验数量和采样召回后原子替换 manifest。一分钟 SLA 要从写入确认到查询可见来测量,而不是从 embedding 任务启动来测量。生成或建索引延迟时暴露 lag,并保留旧版本,不能把“写入成功”当成“已经可检索”。
第五步:处理模型与元数据迁移
更换 embedding 模型后,新旧向量通常不可直接比较,需要双索引或投影方案。给记录写入模型版本,回填新索引,对新旧索引做 shadow query,比较召回和延迟后再切换。回滚与保留窗口结束前保留旧索引。ACL 元数据升级也要分版本发布;向量相似绝不能绕过新增权限字段。
第六步:设计查询路径与过载策略
查询层先认证租户,规范化查询,选择模型版本,只向相关分片发请求。设置 deadline、候选上限和取消机制。分片超时时,只有 API 明确支持部分结果时才能返回并标记完整性;权限敏感查询应失败关闭。可以缓存 embedding 和稳定的公开查询,但缓存键不能跨授权范围共享。突发流量时用 admission control 保护索引内存和重排容量。
第七步:衡量相关性、新鲜度与成本
建立包含相关文档和禁止文档的标注查询集。对采样分片与精确搜索基线比较,报告 recall@20、precision 或 nDCG、过滤正确率和权限泄露测试。持续记录 p50/p95/p99 延迟、候选数、索引构建时间、写入到可见的 lag、墓碑积压、每向量内存和每千次查询成本。离线指标发现排序回归;在线点击会受位置偏差影响,不能单独作为正确性证明。
设计取舍与边界
HNSW 与聚类或量化索引
内存足够且读多写少时,HNSW 是合理起点。数据规模更大或内存成本敏感时可用 IVF 或乘积量化,但必须增加训练、调参与召回验证。选择依据应是更新率、维度、租户倾斜和硬件预算,而不是产品名称。
专用向量库与现有数据库
集合规模中等、ACL 数据需要事务连接时,已有数据库的向量索引更简单。向量检索成为主要容量、需要专用 ANN 索引或独立扩缩容时,再考虑专用服务。若向量库不能提供事务保证,应把文档与权限事实保留在外部源系统。
每租户索引与共享分片
每租户独立索引便于隔离和控制噪声,但运维开销会随租户增长。共享分片硬件利用率高,却要求严格元数据过滤和公平调度。普通租户使用命名空间或分区键,超大或强监管租户再使用独立容量。
高质量示范回答
“我会先建立持久化写入日志,并为每份文档、ACL 和 embedding 模型做版本管理。查询层先完成租户授权,只向相关分片发请求,执行带过滤的 ANN,再合并新鲜 delta 与不可变 segment。读多写少时可从 HNSW 起步,但要用 recall@20 和 p95 延迟与聚类或量化索引做基准。重建通过原子 manifest 发布,模型升级使用 shadow query,删除使用带版本的墓碑。服务还要报告过滤正确率、写入到可见 lag、权限泄露测试、每向量内存和查询成本;相关性必须是可测量契约。”
常见错误
- 只讨论 ANN 库选型,忽略写入、删除和重建。
- 检索后才执行 ACL 过滤,结果数量不足时却没有明确契约。
- 不说明向量维度、索引参数、硬件和负载,就声称固定召回率或延迟。
- 原地替换 embedding 模型,导致新旧向量不可比较。
- 只看点击率,不维护精确搜索或标注相关性基线。
追问及应对
ACL 过滤后只有三条结果怎么办?
按契约返回三条并标记完整性,或返回“结果不足”。绝不能用未授权或未过滤结果填满剩余位置。扩大候选池也必须在授权检索路径内完成。
如何重建索引而不丢写入?
从持久化日志回放到新 segment,记录高水位,补齐高水位之后的写入,校验数量和采样召回后原子发布 manifest。切换完成前保持 delta 路径,失败时恢复旧 manifest。
什么时候能删除旧模型向量?
只有 shadow 评估通过、新模型已服务、回滚与保留窗口结束,并且所有查询路径都拒绝旧模型版本后才能删除。仅按时间删除会遗漏延迟任务或回放消费者。