核心功能
Annoy(Approximate Nearest Neighbors Oh Yeah)由 Spotify 编写,用随机投影建成二叉树森林做近似最近邻查询。它最大的特点是把索引写成只读静态文件并 mmap 进内存,多个进程可以共享同一份索引。Spotify 用它做音乐推荐。与 FAISS、hnswlib 相比,它放弃了在线增删,换来极小的内存占用和几乎瞬时的索引加载。
功能亮点
索引就是文件
建索引与加载完全解耦,索引文件可以分发到生产环境或 Hadoop 任务里被直接映射使用
多进程共享内存
load 走 mmap,同机多个进程映射同一份索引,不必每个进程各自复制一遍向量数据
两个参数就够调
官方称 n_trees 与 search_k 大致相互独立,分别对应索引体积精度和单次查询耗时
内存占用优先
README 说明设计上刻意压小索引体积,Spotify 在数百万音轨的高维空间中以此为首要约束
适用场景
• 推荐系统中对用户/物品 embedding 做相似召回,索引离线构建后作为文件分发到线上
• 多进程或多 worker 的服务共用一份只读索引,避免每个进程各占一份向量内存
• 内存受限的机器上检索大规模向量,用 on_disk_build 把索引直接建在磁盘上
安装配置
bash
PyPI(README 给出的方式): pip install --user annoy C++(header-only): 克隆仓库后在代码中 #include "annoylib.h" 即可 README 另外指出 Annoy 在 conda-forge 上有 python-annoy 包,覆盖 Linux、macOS 与 Windows。
使用方法
python
README 中的 Python 示例:
from annoy import AnnoyIndex
import random
f = 40 # Length of item vector that will be indexed
t = AnnoyIndex(f, 'angular')
for i in range(1000):
v = [random.gauss(0, 1) for z in range(f)]
t.add_item(i, v)
t.build(10) # 10 trees
t.save('test.ann')
# ...
u = AnnoyIndex(f, 'angular')
u.load('test.ann') # super fast, will just mmap the file
print(u.get_nns_by_item(0, 1000)) # will find the 1000 nearest neighbors
要点(来自官方 API 说明):
- AnnoyIndex(f, metric) 中 metric 可取 "angular"、"euclidean"、"manhattan"、"hamming"、"dot"
- build(n_trees, n_jobs=-1) 之后不能再 add_item
- get_nns_by_item(i, n, search_k=-1, include_distances=False),search_k 不传时默认为 n_trees * n
- 也可用 get_nns_by_vector(v, n, ...) 按向量查询
- C++ API 与之基本一致,#include "annoylib.h" 即可关键指标
尚未核验对标产品,此处只列本工具自身指标,不做对比结论。
指标Annoy
价格免费
开源是
上手难度入门
相关工具
优点
- 索引以静态文件形式存在、load 走 mmap,加载几乎瞬时且可跨进程共享,README 明确把这点列为区别于其他库的核心特性
- 官方说明设计上尽量压小索引体积,Spotify 在数百万音轨的高维向量场景中把内存占用作为首要约束
- 调参面很窄,只有 n_trees 和 search_k 两个参数,且官方说明两者大致相互独立
- 支持 angular / euclidean / manhattan / hamming / dot 五种度量,Hamming 距离底层打包成 64 位整数并使用位计数原语
缺点
- 索引一旦 build 完成就不能再 add_item,也没有删除接口——README 明确写明 index creation is separate from lookup
- 只接受非负整数作为 item id,并且会按 max(id)+1 预分配内存,其他 id 体系需要自己维护映射表
- README 说明维度不太高(小于 100)时效果更好,虽然到 1000 维仍能用
- README 直言不做数值边界检查(no bounds checking performed on the values),传错数据不会报错