【annoy】高维空间求近似最近邻

介绍腾讯词向量时,用到了annoy,这里对annoy的用法详细做一下介绍。

GitHub地址:https://github.com/spotify/annoy

Annoy是Erik Bernhardsson在Hack Week期间花了几个下午写的(github原话),全称Approximate Nearest Neighbors Oh Yeah(这个Oh Yeah真是亮瞎眼)。这个包的优点就是快,内存占用也小,还可以静态存储索引用于更多任务。目前已经在音乐推荐系统Spotify中应用。

这个工具可以用来计算空间中点的距离,输入某个点,返回最近的若干点。

这个包直接pip install annoy就可以安装,C++版本的直接下载后#include "annoylib.h"

使用方法:

from annoy import AnnoyIndex
import random

f = 40
t = AnnoyIndex(f, 'angular')  # Length of item vector that will be indexed
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

默认的索引是从0到n-1。

API:

AnnoyIndex(f, metric) f 向量维度,metric 距离度量方式,取值 "angular", "euclidean", "manhattan", "hamming", or "dot". 计算angular是使用的sqrt(2(1-cos(u,v)))这个公式,用的欧几里得距离。euc = sqrt(2(1-cos))。

a.add_item(i, v) 添加元素 i 和向量 v

a.build(n_trees, n_jobs=-1) n_trees是森林的树数目,值越大结果越精确,n_jobs 进程数,默认-1使用所有的CPU。build调用之后,就不能再添加元素了。

a.save(fn, prefault=False) 保存到本地

a.load(fn, prefault=False) 从本地读取,prefault是预先读入内存,默认为False.

a.unload() 清除加载内容

a.get_nns_by_item(i, n, search_k=-1, include_distances=False) 返回n个最近元素。在查询过程中,它将检查search_k个节点,如果没有提供,默认为n_trees * n。search_k给了一个速度和准确率的折中。include_distances设为True,会提供一个由两个列表组成的二元组,第二个列表包含所有相关的距离。

a.get_nns_by_vector(v, n, search_k=-1, include_distances=False)结果一样,不过是通过向量v来查询。

a.get_item_vector(i) 返回索引i对应的向量

a.get_distance(i, j) 返回元素i和j的距离,squared distance

a.get_n_items() 返回元素数量

a.get_n_trees() 返回树数目

a.on_disk_build(fn) 指定在除了RAM之外的其他文件上构建索引(在添加元素之前执行)

a.set_seed(seed) 在构建树之前可以指定随机数

这里面主要有两个参数需要调,n_trees和search_k,一个是构建时的参数,一个是搜索时的参数。

下面这是qps和recall值之间的trade-off,使用时要综合考虑准确率和速度。

posted @ 2020-08-21 15:58  Yanqiang  阅读(2271)  评论(0编辑  收藏  举报