Annoy (Approximate Nearest Neighbors Oh Yeah) 使用二叉树森林来构建索引,每棵树通过递归空间划分来构建。每棵树的构建过程是随机选择数据集中的两个点,然后创建一个超平面,将数据分成两个子集。此过程对每个子集递归重复,直到达到预定义的深度或达到每个节点的最小点数。通过构建多个独立的树,Annoy 确保索引捕获数据空间的不同潜在分区。在查询期间,该算法同时遍历所有树,从每棵树收集候选节点,然后聚合结果以找到最近邻。树的数量和每棵树的深度是可调参数——更多的树通常会提高准确性,但会增加查询时间,而较浅的树会减少计算,但可能会遗漏更细粒度的分区。
多棵树的使用解决了准确性和效率之间的权衡。由于每棵树以不同的方式划分数据,因此来自所有树的组合结果降低了错过在单棵树的结构中可能被忽略的真实最近邻的风险。例如,在高维空间中,数据分布复杂,单棵树可能会沿着不太理想的超平面分割数据。多棵树通过多样化分区策略来缓解这种情况。此外,Annoy 将索引以二进制格式存储在磁盘上,从而实现高效的内存映射访问。此设计允许跨进程共享索引而无需重新加载,这在分布式系统中非常有用。这些树也是独立构建的,从而可以在索引期间进行并行构建,但默认情况下查询仍然是单线程的,除非用户显式并行化。
在简单性、内存效率和静态数据集是优先考虑事项的情况下,Annoy 是首选。例如,在部署具有预计算嵌入的推荐系统(例如,音乐或文章推荐)时,Annoy 基于磁盘的索引允许在服务之间轻松共享而无需消耗 RAM。它也适用于资源有限的环境,因为它避免了像 FAISS 这样的库的大量内存占用,FAISS 优先考虑 GPU 加速和动态更新。Annoy 的最小依赖性和简单的 API 使其易于集成到轻量级应用程序或脚本管道中。一个实际的例子是 Spotify 的音乐推荐系统,其中 Annoy 可以低延迟地高效处理数百万首歌曲的嵌入。然而,Annoy不太适合频繁更新的数据(因为需要重建索引)或超高精度场景,在这种情况下,像 HNSW(Hierarchical Navigable Small World,分层可导航小世界)这样的库可能会以更高的内存使用量为代价提供更好的召回率。它的优势在于平衡了可用性、速度和资源效率,适用于静态的大规模数据集。