hnswlib / Annoy / ScaNN 向量数据库手册

向量数据库手册 03-向量索引库 18.9 KB 原文

hnswlib / Annoy / ScaNN 向量数据库手册

适用版本:hnswlib v0.9.0(2026-03-28)/ Annoy 1.17.3(2023-06-14)/ ScaNN 1.4.2(2025-08-29,PyPI),核实于 2026-11 许可与形态:开源索引库(hnswlib / Annoy 官方 LICENSE 正文未核验、ScaNN 许可官方资料未提供,见第 11 章);嵌入式 / 进程内索引库,不是数据库 一句话定位:三个都只负责「建索引 + 算 top-k」,持久化、并发、鉴权、CRUD、分布式、元数据过滤全部由调用方自己实现 约定:$ 普通用户、# root 或 sudo、<xxx> 为占位符;标 ⚠️ 的是高危操作。 更新时间:2026-11(版本与 API 变化快,执行前请以官方文档复核)


目录

  1. 它是什么、什么时候选它
  2. 版本、许可与官方入口
  3. 安装与启动
  4. 核心概念与数据模型
  5. 快速上手:完整 CRUD 示例
  6. 索引与检索进阶
  7. 生产部署与运维
  8. 高频故障与排障
  9. 常见坑与避坑清单
  10. 速查表
  11. 参考与延伸

1. 它是什么、什么时候选它

1.1 三库一句话定位

子产品 定位 维护状态
hnswlib header-only C++/Python,只做 HNSW + brute-force,支持增量插入 / 删除标记 / 过滤 活跃
Annoy Spotify 随机投影树,mmap 只读静态索引,读多写少 成熟但停滞,继任者 Voyager
ScaNN Google Research,各向异性量化 + 分区树 + 精确重排 研究型发布,google-research monorepo 子目录

1.2 核心命题:索引库不是数据库

三者都是进程内库:没有守护进程、没有网络端口、没有存储引擎、没有用户体系。你灌进去向量,它给你 top-k 的距离/相似度与下标。检索链路里它们只占中间一格:

层 谁负责 三库是否提供
文档 → Embedding 向量化 调用方 / 模型服务 不提供
向量 + 业务字段的事实源 调用方 不提供
建索引 + 算 top-k hnswlib / Annoy / ScaNN 唯一提供的一层
元数据 / 标量过滤 调用方自己写(hnswlib 有过滤能力,但仍是进程内、无服务端) 部分 / 需自己封装
持久化、快照、崩溃恢复、WAL 调用方自己写;Annoy 只有 mmap 静态文件 不提供托管
并发控制、鉴权、多租户 调用方自己写 不提供
分布式、分片、副本、扩缩容 调用方自己写 不提供
服务化(REST/gRPC)、SLA、监控 调用方自己写 不提供

避坑:官方资料明确的共同坑是「无网络服务、无持久化管理、无权限与并发控制」。把这三个库当数据库用,是选型阶段最该避免的错误 —— 它们甚至连「单条改完立即生效」都不保证(Annoy build 后只读,改一条要重建)。

1.3 横向对照表(一):定位 / 维护状态 / 许可 / 平台支持 / 增量写

维度 hnswlib Annoy ScaNN
定位 HNSW + brute-force,header-only 随机投影树,mmap 只读静态索引 各向异性量化 + 分区树 + 精确重排
最新发布 v0.9.0(2026-03-28);0.10.0-rc.2 预发布 1.17.3(2023-06-14) 1.4.2(2025-08-29,PyPI)
维护状态 活跃 成熟但停滞,继任者 Voyager 研究型发布,monorepo 子目录
许可 官方 LICENSE 正文未核实,以官方为准 官方 LICENSE 正文未核实,以官方为准 官方资料未提供,以官方为准
平台支持 header-only C++/Python,通常可跨平台编译,wheel 以 PyPI 为准 C++/Python + mmap,通常跨平台,wheel 以 PyPI 为准 仅 Linux manylinux_2_27 x86-64 / aarch64 wheel(x86 需 AVX+FMA),无 macOS / Windows;Python ≥3.9
是否可增量写 可:支持增量插入 / 删除标记 / 过滤 不可:build 后只读,改一条要重建 官方资料未明确,以官方为准;通常建好后以批量检索为主

表中「通常可跨平台」「通常建好后以批量检索为主」为经验性表述,非官方结论;许可与 ScaNN 增量写能力见第 11 章未核实清单。

1.4 适合 / 不适合

适合:离线批量建索引与召回评测;数据量能装进单机内存且少变;作为自研检索系统的 ANN 内核;读多写少(Annoy 尤其);需要 HNSW 增量插入与删除标记(hnswlib);Linux x86 平台上做高精度量化检索(ScaNN)。

不适合:多进程 / 多机并发写与事务一致性;按标量字段做服务端 pre-filter;单条即时删除 / 更新且马上生效;账号、权限、审计、TLS、多租户;崩溃自动恢复、弹性扩缩容、SLA 与告警;数据量超单机内存或需要分片副本;macOS / Windows 上想用 ScaNN;依赖活跃维护与快速安全响应(Annoy 已停滞)。

1.5 规模与链路位置(经验值,非官方承诺)

量级 说明
百万级以内 × 768 维 精确基线常可接受,建议先做 brute-force 对照
千万级 × 768 维 通常要 HNSW / 随机投影树 / 量化,全扫吃紧
亿级 单机内存一般放不下,需自己分片或换分布式库
QPS / 维度 取决于索引参数与机器,以实测为准;示例用 3~4 维,实际常见 768 / 1024 / 1536

三者只承担「候选召回」:离线灌 embedding,在线取 top-k 下标,再回到自己的事实源取回文本与元数据做后过滤、重排、拼 prompt。RAG 的文档管理、增量更新、权限过滤全在库之外。

⚠️ 危险:把返回的下标当业务 ID 用,一旦做过删除、重排或重建,下标会整体错位,召回会静默串到错误文档。必须维护稳定的「下标 ↔ 业务 ID」映射,并在每次重建时同步重建。

1.6 什么时候该换真数据库(选型视角判断线)

出现任意一条且无法接受自研成本,就应改用真正的向量数据库或托管服务:

触发条件 为什么索引库兜不住 建议去处
多进程 / 多机并发写 进程内对象,无跨进程锁与一致性 Milvus / Qdrant / Weaviate / 云托管
需要服务端标量 pre-filter 无元数据引擎(hnswlib 的过滤仍是进程内) pgvector / Qdrant / Milvus
需要单条即时删除 / 更新 Annoy build 后只读;hnswlib 只有删除标记 真向量数据库
需要鉴权 / 多租户 / RBAC 无网络层、无用户概念 专用向量库或云托管
需要崩溃恢复 / WAL / 托管持久化 只有 mmap 静态文件 / 手动导出 真向量数据库
数据量超单机内存 / 需要分片副本 单进程内存索引 分布式向量库
需要 REST/gRPC、SLA、监控告警 完全没有服务化能力 真向量数据库 / 云托管
需要 macOS / Windows 上用 ScaNN ScaNN 仅 Linux wheel 换跨平台库

2. 版本、许可与官方入口

2.1 版本状态表

子产品 版本号 时间 状态 备注
hnswlib v0.9.0 2026-03-28 当前稳定 0.10.0-rc.2 为预发布,勿用于生产
Annoy 1.17.3 2023-06-14 最新发布 成熟但停滞,继任者 Voyager
ScaNN 1.4.2 2025-08-29(PyPI) 研究型发布 google-research monorepo 子目录

版本差异:三条版本线互不相干,不要横向比大小、也不要混用「SDK / 服务端 / 格式」版本号;官方资料未提供更早的发布史。

2.2 许可与商业边界

  • hnswlib / Annoy:官方 LICENSE 正文未核实(见第 11 章),许可名称与条款以官方仓库为准;ScaNN 许可官方资料未提供,同样以官方为准。
  • 三者都是开源研究型 / 工具型库,无「企业版 / 商业特性」分层。真正的成本在你要自己补齐的整套数据库能力,而非授权。
  • 许可变更史官方资料未提供,以官方仓库为准。

2.3 官方入口表

子产品 官方入口
hnswlib https://github.com/nmslib/hnswlib/releases
Annoy https://github.com/spotify/annoy/releases
ScaNN https://pypi.org/project/scann/

官方资料只给出以上三个入口;官网 / 文档站 / 镜像仓库地址未提供,以官方仓库导航为准,本篇不臆造 URL。

2.4 版本识别与近两年变更

无服务端 --version。用 Python 侧自检能否 import(包名以 PyPI 为准):

$ python -c "import hnswlib; print('hnswlib ok')"
$ python -c "import annoy; print('annoy ok')"
$ python -c "import scann; print('scann ok')"

版本差异:ScaNN 自 1.4.0 起 TensorFlow 集成需 pip install scann[tf];ScaNN 仅 Linux manylinux_2_27 x86-64 / aarch64 wheel;Annoy 已停滞并有继任者 Voyager;hnswlib 0.10.0-rc.2 是预发布。以上均为官方资料明确事实,别照抄旧教程的「默认就带 TF 集成 / 全平台可装」。


3. 安装与启动

3.1 前置条件与形态

Python 环境;向量一般需转 float32(经验性,以各库官方文档为准)。无服务端、无端口、无守护进程,「启动」= 在进程里 import 并构造索引对象。

3.2 方式一:pip(三库分小节)

hnswlib

$ pip install hnswlib

Annoy

$ pip install annoy

ScaNN

$ pip install scann
# 1.4.0 起 TensorFlow 集成需额外装
$ pip install scann[tf]

避坑:pip install hnswlib / pip install annoy 为按包名给出的通用安装命令,包名与 wheel 可用性以 PyPI 为准。ScaNN 的 scann[tf] 是官方资料明确的可选依赖,不要与基础包混为一谈。

3.3 方式二:平台前置检查(ScaNN 必做)

ScaNN 有硬平台限制,装之前先确认,避免白装:

import sys
import platform
assert sys.version_info >= (3, 9), "ScaNN 需 Python >= 3.9"
assert platform.system() == "Linux", "ScaNN 仅提供 Linux wheel"
print("平台前置检查通过:", platform.system(), platform.machine(), sys.version.split()[0])

避坑:x86 还需 AVX+FMA,可用 grep -m1 -o -E 'avx|fma' /proc/cpuinfo 粗查(经验性,以实测为准)。hnswlib 为 header-only C++(官方资料明确),可直接包含头文件;Annoy / ScaNN 的源码构建命令官方资料未给出,以各自官方仓库为准,本篇不臆造编译参数。

3.4 目录与端口表 / 健康检查 / 生产最小配置

项 值 / 做法
监听端口 无(三者均为进程内库)
数据目录 调用方自定;Annoy 为 mmap 静态索引文件
健康检查 第 2.4 节 import 自检;无 /health 端点
认证 无原生能力,服务层套鉴权(见第 7 章)
持久化路径 Annoy 静态文件只读挂载;hnswlib / ScaNN 由调用方决定导出路径
资源限制 用容器 / cgroup 限内存;占用 ≈ 向量矩阵 + 索引结构,见第 6.5 节
只读加载 索引文件只读挂载,避免多进程同时写坏文件

4. 核心概念与数据模型

4.1 术语对照表

术语 通用术语 关系型类比 说明
Index / 索引对象 ANN 索引 一张「索引」 进程内对象,非表
返回的下标 近邻下标 行号 / rowid 不是业务 ID
距离 / 相似度 打分 分数 方向见 4.3
mmap 静态索引(Annoy) 只读内存映射文件 只读快照 build 后不可改
删除标记(hnswlib) 软删除 逻辑删除位 非物理删除,需自己管

4.2 数据模型层级

三者都没有集合 / 数据库 / 字段 / schema 层级,只有向量矩阵 + 可选下标;「表」由调用方的 records 列表或外部数据库承担。hnswlib 支持过滤,但仍是进程内能力,不等于服务端标量查询。

4.3 距离度量与方向

官方资料未给出三库距离度量的完整枚举与参数名,以下为通用原理(经验性表述),具体取值与「值越大越相似还是越小越相似」以各库官方文档为准:L2 / 欧氏类距离越小越相似;内积 / 余弦类相似度越大越相似。查询时度量必须与建索引时一致,否则结果无意义。

4.4 横向对照表(二):许可 / 平台 / 数据模型 / 增量写 / 维护状态

维度 hnswlib Annoy ScaNN
许可 LICENSE 正文未核实 LICENSE 正文未核实 官方资料未提供
平台支持 通常跨平台(header-only C++) 通常跨平台(C++/mmap) 仅 Linux x86-64 / aarch64,x86 需 AVX+FMA
数据模型 HNSW 图 + brute-force 随机投影森林 + mmap 文件 分区树 + 各向异性量化 + 精确重排
持久化形态 由调用方导出 / 管理 mmap 只读静态文件 由调用方导出 / 管理
是否可增量写 可(增量插入 / 删除标记 / 过滤) 不可(build 后只读,改一条重建) 官方资料未明确,以官方为准
维护状态 活跃 成熟但停滞,继任者 Voyager 研究型发布

4.5 写入 → 建索引 → 可检索的生命周期

阶段 hnswlib Annoy ScaNN
构造 建索引对象 建索引对象 官方资料未给逐字 API,以官方为准
灌数据 支持增量插入 逐条加入后 build,此后只读 官方资料未给逐字 API,以官方为准
可检索 插入后即可查;删除走标记 build 之后才能查 以官方为准
落盘 调用方自己导出 / 加载 mmap 静态文件 调用方自己导出 / 加载
是否异步 官方资料未提,通常同步 通常同步 以官方为准

避坑:Annoy 的「build 后只读」是硬约束。官方资料明确「改一条要重建」,不要指望增量更新。


5. 快速上手:完整 CRUD 示例

说明:三者都没有「连接 / 表 / CRUD」概念,且官方资料未提供三库逐字的 API 方法名与参数名。为避免臆造,本篇以一段等价的、完整可运行的 numpy brute-force 基线示范「调用方必须自己维护的胶水层」—— 索引库只替换其中「相似度检索」一步;各库具体调用以官方文档为准(见第 11 章)。

5.1 完整可运行示例:调用方胶水层基线(Python)

import numpy as np

d = 4  # 示例用 4 维,实际常见 768 / 1024 / 1536
records = [
    {"id": "doc-0", "text": "三国演义", "category": "history", "vec": [0.1, 0.2, 0.3, 0.4]},
    {"id": "doc-1", "text": "红楼梦",   "category": "history", "vec": [0.1, 0.2, 0.3, 0.5]},
    {"id": "doc-2", "text": "三体",     "category": "scifi",   "vec": [0.9, 0.1, 0.2, 0.1]},
    {"id": "doc-3", "text": "流浪地球", "category": "scifi",   "vec": [0.8, 0.1, 0.2, 0.2]},
]

def build_matrix(rows):
    """C = 建集合 / U = 插入:索引库只吃数值矩阵,业务字段自己留着"""
    return np.asarray([r["vec"] for r in rows], dtype="float32")

def brute_topk(xb, query_vec, k):
    """R:精确 top-k 基线(hnswlib 自带 brute-force;另两库把这里换成自己的索引)"""
    xq = np.asarray(query_vec, dtype="float32")
    dist = np.sum((xb - xq) ** 2, axis=1)   # 平方 L2,越小越相似
    return [(int(i), float(dist[i])) for i in np.argsort(dist)[:k]]

def search_with_filter(xb, rows, query_vec, category, k):
    """带标量过滤检索:取回候选后自己按元数据后过滤"""
    return [(rows[i]["id"], rows[i]["text"], dist)
            for i, dist in brute_topk(xb, query_vec, k)
            if rows[i]["category"] == category]
xb = build_matrix(records)                       # 连接(无)+ 创建集合 + 插入
print("已灌入行数 =", len(records))
print("R 精确 top-2 =", brute_topk(xb, [0.1, 0.2, 0.3, 0.45], 2))
print("过滤 history =", search_with_filter(xb, records, [0.1, 0.2, 0.3, 0.45], "history", 4))
# U:更新(无行级 update,改事实源后重建矩阵;Annoy 还要重建整个索引)
records[1].update(text="红楼梦(修订)", vec=[0.1, 0.2, 0.3, 0.55])
xb = build_matrix(records)
print("更新后检索 =", search_with_filter(xb, records, [0.1, 0.2, 0.3, 0.55], "history", 2))
# D:删除(从事实源移除,再整表重建;hnswlib 的删除标记不是物理删除)
records = [r for r in records if r["id"] != "doc-3"]
xb = build_matrix(records)
print("删除后剩余行数 =", len(records))
# 清理 / 持久化:三库都不托管,Annoy 只有 mmap 静态文件,其余由调用方导出
np.save("vectors.npy", xb)
print("已写出 vectors.npy;索引文件与事实源必须一起备份")

5.2 输出怎么读

R 精确 top-2 的 i 是 add 矩阵行下标(不是业务 ID),dist 是平方 L2、越小越像;过滤 history 是后过滤结果 (业务ID, 文本, 平方L2);删除后剩余行数 是事实源行数,重建后旧下标全部失效。

避坑:把下标当业务主键是三库通用的错。Annoy 只有 mmap 静态索引文件、hnswlib / ScaNN 无持久化管理,业务字段永远在你自己的事实源里。

5.3 按子产品分小节:接入生命周期

5.3.1 hnswlib:header-only C++/Python,只做 HNSW + brute-force;支持增量插入 / 删除标记 / 过滤,是三者中唯一明确可增量写的。适合需要在进程内持续追加数据的场景。删除是标记而非物理删除,需自己管标记集合与重建时机。

5.3.2 Annoy:Spotify 随机投影树,mmap 只读静态索引,读多写少。逐条加入后 build,build 之后只读;官方资料明确「改一条要重建」。适合索引基本不变、靠 mmap 低内存加载的离线召回。

5.3.3 ScaNN:Google Research,各向异性量化 + 分区树 + 精确重排;仅 Linux manylinux_2_27 x86-64 / aarch64 wheel(x86 需 AVX+FMA),Python ≥3.9,1.4.0 起 TF 集成需 pip install scann[tf]。平台前置检查见第 3.3 节。官方资料未提供官方 Python 最小接入代码,逐字 API 以官方文档为准(见第 11 章)。

避坑:官方资料未提供三库逐字的 API 方法名与参数名,本篇不臆造。上面第 5.1 节的 numpy 基线是可运行的等价实现;上线前请把「相似度检索」一步替换为对应库的官方调用,并以官方 README / 文档核对参数。


6. 索引与检索进阶

6.1 横向对照表(三):调优 / 平台 / 增量写 / 维护状态

维度 hnswlib Annoy ScaNN
调优抓手 建图连接数、检索候选规模(概念性,参数名以官方为准) 树数量、检索候选规模(概念性) 分区数、量化阈值、重排候选(概念性)
平台支持 通常跨平台 通常跨平台 仅 Linux x86-64 / aarch64,x86 需 AVX+FMA
是否可增量写 可(增量插入 / 删除标记 / 过滤) 不可(build 后只读) 官方资料未明确
维护状态 活跃 成熟但停滞,继任者 Voyager 研究型发布
许可 LICENSE 未核实 LICENSE 未核实 官方资料未提供

6.2 索引参数调优表(概念层)

抓手 影响 建议范围
建图 / 建树规模 越大召回越高、内存与构建越慢 以实测为准
检索候选规模 越大召回越高、延迟越高 从小到大压测
量化 / 重排(ScaNN) 压缩内存、用精确重排补回精度 以实测为准

官方资料未给出三库逐字的参数名、默认值与推荐范围,本表为概念性经验表述,不是官方结论;具体参数以各库官方文档为准(见第 11 章)。

6.3 召回 / 延迟 / 过滤 / 混合检索

  • 候选规模调大 → recall 上升、延迟上升;建图 / 建树规模调大 → 召回上升、内存与构建时间上升。没有统一最优值,必须用自己的数据压测 recall@k 与 p99。
  • 三者都没有服务端标量过滤:hnswlib 的过滤是进程内能力,Annoy / ScaNN 更需调用方自己后过滤(第 5.1 节演示)。

⚠️ 危险:后过滤会让返回条数变少。k 取小、过滤条件又很 Selective 时可能一条不剩。生产上要么放大 k 再截断,要么换支持 pre-filter 的向量数据库。

  • BM25 + 稠密混合、RRF 融合、稀疏向量、重排都要在外部自己实现 —— 同样是「索引库不是数据库」的直接后果。

6.4 量化与压缩

ScaNN 的核心就是各向异性量化 + 分区树 + 精确重排(官方资料明确):用量化压缩候选、再用精确计算重排补回精度。Annoy 的 mmap 静态索引走的是随机投影树 + 只读内存映射。hnswlib 以 HNSW 图为主、另有 brute-force 基线。量化必然有召回损失,上线前必须用精确基线(第 5.1 节)算 recall@k。

6.5 内存与磁盘容量估算

  • 原始向量矩阵:n × d × 4 字节(float32 每元素 4 字节),再加索引结构开销。例:1,000,000 × 768 × 4 ≈ 2.86 GiB,这只是原始向量,HNSW 图 / 投影森林 / 量化码字另算。
  • Annoy 的 mmap 静态文件常可只读映射、按需换页,进程常驻内存可低于文件尺寸(经验性,以实测为准)。
  • 三者都无增量落盘、无 WAL,每次导出都是整份快照。以上为经验估算,以产物大小与 free -m 实测为准。

7. 生产部署与运维

7.1 把边界再讲透:三库不负责什么

缺失能力 自己要补的东西
持久化 hnswlib / ScaNN 自己导出与版本化;Annoy 只有 mmap 静态文件,无 WAL
并发 单写多读锁、进程间共享,或只读镜像 + 定期重建
鉴权 服务层做认证 / 授权 / 审计 / TLS,索引库完全不感知
CRUD 自己维护事实源;hnswlib 用删除标记,Annoy 改一条要重建
分布式 自己分片、聚合、路由、副本
元数据过滤 自己后过滤(第 6.3 节),或换支持 pre-filter 的库
服务化 自己包 REST/gRPC、连接池、超时、限流
监控 自己埋点:召回率、p99、索引行数、文件大小、内存

⚠️ 危险:多进程同时导出 / 覆盖同一索引文件会互相写坏。落盘要「写临时文件 → 原子改名」,并保留上一版可回滚。

高可用 / 集群 / 分片 / 副本三者原生都不提供,可行做法都是调用方自建:多副本各持只读索引、前置负载均衡、定期全量重建后滚动替换。这与「托管服务买的是运维责任转移」形成鲜明对比 —— 这里责任全在你(对比见 04 分册)。

7.2 什么时候该换真数据库(运维视角判断线)

第 1.6 节是选型视角,这里是上线前自检:任一问答「是」就别硬撑索引库。

上线自检 若为「是」 处置
需要 7×24 在线、有 SLA 与告警 无服务端、无监控端点 换真向量数据库 / 云托管
写入与检索来自多个进程 / 机器 无跨进程一致性 换分布式向量库
数据改一条要分钟级生效 Annoy 重建、hnswlib 仅标记 换支持 delete/upsert 的库
需要按租户 / 用户做数据隔离 无鉴权与多租户 换带 RBAC 的库
需要崩溃后自动恢复 无 WAL 换真数据库
索引超单机内存 / 要弹性扩容 无分片与扩缩容 换分布式 / 云托管
平台含 macOS / Windows 且选了 ScaNN ScaNN 仅 Linux wheel 换跨平台库
依赖厂商安全响应 Annoy 已停滞、ScaNN 研究型发布 换活跃维护的产品

7.3 备份与恢复(索引是否需要重建)

项 做法
备份对象 索引导出文件 / Annoy mmap 静态文件 + 业务事实源(缺一不可)
恢复 重新加载索引文件;加载 API 名以各库官方文档为准(见第 11 章)
是否需要重建 Annoy 改一条就要重建;hnswlib 删除标记累积后要重建;索引参数变更必须重建
恢复演练 定期用快照 + 事实源重建一遍并跑 recall 校验

避坑:不要只备份索引文件。没有事实源,你无法把返回下标还原成业务记录,等于数据丢了。

7.4 监控指标与告警阈值建议 / 容量与升级

三者无 /metrics 端点,需在服务层埋点:

指标 告警阈值建议(经验值)
进程内存 超过容器 limit 的 80% 告警(OOM 是头号故障)
单次检索 p99 超过业务 SLO 告警
recall@k(对比精确基线) 低于约定下限(如 0.95)告警
索引行数 vs 事实源行数 不一致即告警(下标错位前兆)
导出产物大小 / 失败次数 突增或连续失败告警
后过滤命中率 过低说明 k 偏小或过滤过强

按第 6.5 节公式估算内存并预留索引结构与峰值余量;扩缩容 = 重建索引 + 换机器 / 换副本,无在线弹性。升级:固定 pip 版本,升级前用同一份数据跑 recall 对比;索引文件跨版本兼容性官方资料未提供说明,稳妥做法是升级后用事实源重建索引;ScaNN 升级还要核对 Linux wheel 与 AVX/FMA 依赖。

版本差异:ScaNN 1.4.0 起 TF 集成需 scann[tf];hnswlib 0.10.0-rc.2 是预发布;Annoy 已停滞并有继任者 Voyager。别照抄旧教程的默认行为。

7.5 安全基线与日志

面 建议
认证 / RBAC 全部在服务层;三库无用户概念
TLS / 网络暴露面 进程内调用无需;理想暴露面为 0,别为调试把脚本直接暴露端口
索引文件权限 只读、最小权限;文件里可能含可反推的向量
输入校验 校验维度、dtype、k 上界,防畸形输入打爆内存

无自带日志,统一打到业务服务日志。系统级服务管理(systemd / 防火墙等)属通用运维,见根目录手册,本篇不重复。


8. 高频故障与排障

症状 可能原因 定位命令 / 方法 处置
连不上 / 服务无响应 把库当服务了,其实没有监听端口 查端口 + 第 2.4 节自检 改进程内调用;需要服务化就换真数据库
import scann 失败 / macOS、Windows 装不上 不是 Linux / Python <3.9 / x86 缺 AVX+FMA 第 3.3 节平台检查 换 Linux x86-64 / aarch64 且满足指令集;或换跨平台库
TF 集成报错 1.4.0 起需 pip install scann[tf] pip show scann 补装可选依赖,别以为基础包自带
Annoy 修改后不生效 build 后只读,改一条要重建 检查是否漏了重建 全量重建索引并原子替换
写入失败:dtype / 维度错 输入不是数值矩阵或形状不对 打印 dtype / shape 转 float32 并对齐维度(以各库文档为准)
查不到 / 召回低 / 查询慢 候选规模太小、量化损失、后过滤滤光、全扫 第 5.1 节精确基线算 recall;放大 k 调检索候选、降压缩、放大 k 或换 pre-filter 库
OOM 向量矩阵 + 索引结构超单机内存 free -m;按第 6.5 节估算 量化、分片、减副本、换分布式库
磁盘满 / 索引不生效 整份快照多版本累积;加载了旧文件 df -h;对比精确基线 只保留最近 N 版;重建索引、确认加载新文件
版本升级后报错 索引文件跨版本不兼容 / wheel 变了 固定版本复现;查 Releases 用事实源重建索引,核对平台依赖
过滤结果变少 / 删除后串位 后过滤在 k 之后;重建后旧下标未失效 打印过滤前后条数;比对事实源行数 放大 k 再截断;重建索引同时重建「下标→ID」映射

9. 常见坑与避坑清单

  1. 现象:把三者当数据库,直接拿返回下标当业务主键。原因:返回的是 add 矩阵行下标。怎么做:自己维护「下标 ↔ 业务 ID」映射,删改后同步重建。
  2. 现象:Annoy 改一条数据后结果不变。原因:build 后只读,改一条要重建。怎么做:全量重建 + 原子替换,别做增量幻想。
  3. 现象:macOS / Windows 上 pip install scann 失败。原因:仅 Linux manylinux_2_27 x86-64 / aarch64 wheel。怎么做:第 3.3 节先查平台,或换跨平台库。
  4. 现象:ScaNN 在老 x86 CPU 上崩或报指令错。原因:x86 需 AVX+FMA。怎么做:查 /proc/cpuinfo,换满足指令集的机器。
  5. 现象:ScaNN 的 TensorFlow 集成用不了。原因:1.4.0 起需 pip install scann[tf]。怎么做:补装可选依赖,别照抄旧教程「装了就有」。
  6. 现象:hnswlib 删除后旧向量仍被召回。原因:是删除标记,非物理删除。怎么做:自己维护标记并在结果层过滤,累积后重建。
  7. 现象:照旧教程以为有服务端 / /health。原因:三者无网络服务、无权限与并发控制。怎么做:服务层自建健康检查与鉴权。
  8. 现象:以为索引会自动持久化、崩溃能恢复。原因:Annoy 只有 mmap 静态文件,另两库无持久化管理。怎么做:自己导出 + 版本化 + 备份,且事实源一起备。
  9. 现象:只备份索引文件,恢复后拿不回文档。原因:业务字段本就不在库里。怎么做:索引文件与事实源一起备份,否则等于数据丢失。
  10. 现象:上了量化后召回明显掉。原因:量化是有损的。怎么做:用第 5.1 节精确基线算 recall@k,调候选规模 / 重排后再上线。
  11. 现象:带 category 过滤后一条不返回。原因:无服务端标量过滤,只能取回 top-k 后自己后过滤。怎么做:放大 k 再截断;高选择性过滤换 pre-filter 库。
  12. 现象:多进程同时导出把索引文件写坏。原因:无 WAL、无文件锁、整份覆盖写。怎么做:⚠️ 写临时文件 → 原子改名,保留上一版可回滚。

⚠️ 危险:第 9、12 条可能导致线上数据丢失;第 1、6 条会产生长期静默的错误召回结果,上线前必须做恢复演练与 recall 回归。


10. 速查表

10.1 横向对照表(四):速查版

维度 hnswlib Annoy ScaNN
定位 HNSW + brute-force 随机投影树,mmap 只读 各向异性量化 + 分区树 + 精确重排
最新发布 v0.9.0 1.17.3 1.4.2
维护状态 活跃 成熟但停滞,继任者 Voyager 研究型发布
许可 LICENSE 未核实 LICENSE 未核实 官方资料未提供
平台支持 通常跨平台 通常跨平台 仅 Linux x86-64 / aarch64,x86 需 AVX+FMA
是否可增量写 可 不可 官方资料未明确
持久化 调用方导出 mmap 静态文件 调用方导出

10.2 操作速查表

操作 命令 / 代码 说明
装 hnswlib pip install hnswlib 包名以 PyPI 为准
装 Annoy pip install annoy 包名以 PyPI 为准
装 ScaNN pip install scann 仅 Linux wheel
装 ScaNN TF 集成 pip install scann[tf] 1.4.0 起需要
查平台 python -c "import platform; print(platform.system(), platform.machine())" ScaNN 仅 Linux
查 AVX/FMA `grep -m1 -o -E 'avx fma' /proc/cpuinfo`
import 自检 python -c "import hnswlib; print('ok')" 无服务端版本命令
精确基线 第 5.1 节 brute_topk 算 recall@k 的 ground truth
强制 float32 np.asarray(x, dtype="float32") 经验性,以各库文档为准
增量插入 hnswlib 支持;Annoy 不支持 见横向对照表
删除 hnswlib 删除标记;Annoy 重建 非数据库式 delete
过滤 自己后过滤;hnswlib 有进程内过滤 无服务端 pre-filter
落盘 Annoy mmap 文件;其余调用方导出 无 WAL
备份 索引文件 + 事实源一起备 缺一不可
平台不符 换跨平台库或换机器 ScaNN 硬限制
换真数据库 见第 1.6 / 7.2 节判断线 别硬撑

常用端口与路径小表

项 值
网络端口 无(三者均为进程内库)
Python 版本 ScaNN ≥3.9;其余以官方文档为准
索引文件示例 Annoy mmap 静态文件;vectors.npy(调用方自定)
官方入口 https://github.com/nmslib/hnswlib/releases | https://github.com/spotify/annoy/releases | https://pypi.org/project/scann/

11. 参考与延伸

11.1 官方文档链接清单

子产品 地址
hnswlib https://github.com/nmslib/hnswlib/releases
Annoy https://github.com/spotify/annoy/releases
ScaNN https://pypi.org/project/scann/

官网 / 文档站 / 镜像仓库地址官方资料未提供,以官方仓库导航为准,本篇不臆造 URL。

11.2 与本册其他产品的关系

  • 同属「向量索引库(不是数据库)」:Faiss.md,四库选型对照见两篇的横向对照表。
  • 出现第 1.6 / 7.2 节任一判断线时,改用真向量数据库:Milvus / Qdrant / Weaviate / pgvector(见对应分册)。
  • 想买「运维责任转移」而非自建,见 04 分册:Pinecone.md、Zilliz-Cloud.md、国内云向量数据库.md。

11.3 进阶阅读方向

HNSW / 随机投影树 / 各向异性量化的原理与召回-延迟取舍;以精确基线为 ground truth 的 recall@k 评测方法学;mmap 静态索引的只读发布与原子替换;从索引库迁移到支持 pre-filter / 删除 / 分布式向量库的改造路径;Annoy 继任者 Voyager 的评估。

11.4 本篇「未核实 / 以官方为准」事项

事项 状态
hnswlib 官方 LICENSE 正文 未核实(官方资料「六、未核实清单」第 5 条),正文条款以官方仓库 LICENSE 为准
Annoy 官方 LICENSE 正文 未核实(同上),正文条款以官方仓库 LICENSE 为准
Faiss 官方 LICENSE 正文 未核实(同上,见 Faiss.md 第 11 章)
ScaNN 许可 官方资料未提供,以官方为准;正文未写成任何确定协议
三库逐字的 Python API 方法名 / 参数名 / 参数默认值 官方资料未提供,本篇不臆造;第 5.1 节以 numpy 等价基线代替,上线前以官方 README / 文档核对
ScaNN 是否可增量写 官方资料未明确,正文标注「以官方为准」
ScaNN 官方 Python 最小接入代码 官方资料未提供,以官方文档为准
三库距离度量完整枚举、健康检查端点、监控端点 官方资料未提供,第 4.3 / 7.4 节为经验性表述
各库官网 / 文档站 / 镜像仓库 URL 官方资料未提供,不臆造
hnswlib / Annoy 跨平台 wheel 的具体可用平台清单 官方资料未逐字给出,正文为「通常跨平台」的经验性表述