三种邻近搜索

一、Annoy

1. 介绍
Approximate Nearest Neighbor Oh Yeah,是一个带有Python bindings的C ++库。

  • 用于在海量文本中快速搜索相似的用户/物品(适合向量维度小于1000,向量数在百万级别)
  • Annoy是Spotify开源的高维空间求近似最近邻的库,在Spotify使用它进行音乐推荐
  • Annoy通过将海量数据建立成一个二叉树,使得每个数据查找时间复杂度是O(logn)

2. 原理
随机选择两点进行超平面划分,在划分的子空间内不停递归划分,直至每个子空间最多只剩下k个数据结束。(必须通过精度和性能之间的权衡来调整k)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
3. 查找
二叉树遍历,不断查看此点在分割超平面的哪一边
在这里插入图片描述

4. 问题和解决
问题:

  • 查询过程中最终落到叶子节点的数据节点数 < TopN相似节点数怎么办?
  • 两个相近的数据节点划分到二叉树不同分支怎么办?

解决:

  • 方法一:两边都遍历
    找到最近的切面,判断是否分割超平面的两边相似,对于相似的都进行遍历。 在这里插入图片描述
  • 方法二:多棵树
    建立多棵二叉树,构建一个森林,将多棵树的返回的近邻点插入到优先队列中,求并集(融合成一张图),对该图中的所有节点进行相似计算返回TopN近邻点集合。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    5. annoy算法的效果对比图
    在这里插入图片描述

6. 源码重点解释

https://blog.csdn.net/hero_fantao/article/details/70245387

Python代码示例:

from annoy import AnnoyIndex
import random

f = 20
t = AnnoyIndex(f, 'angular')  # Length of item vector that will be indexed
for i in range(1000):
	# 返回具有高斯分布的随机浮点数 random. gauss (mu, sigma) 参数:. mu:平均. sigma:标准偏差.
    v = [random.gauss(0, 1) for z in range(f)]  
    t.add_item(i, v)

t.build(10) # 10 trees
t.save('test.ann')
print(t.get_nns_by_item(0, 10))
# [0,45,16,17,61,24,48,20,29,84]
# ...

u = AnnoyIndex(f, 'angular')
u.load('test.ann') # super fast, will just mmap the file
print(u.get_nns_by_item(0, 10)) # will find the 1000 nearest neighbors
# [0,45,16,17,61,24,48,20,29,84]

7. 完整的Python API

  • AnnoyIndex(f, metric) 返回可读写的新索引,用于存储f维度向量。
    metric可以是"angular",“euclidean”,“manhattan”,“hamming”,或"dot"。
  • a.add_item(i,v) 用于给索引添加向量v,i(任何非负整数)是给向量v的表示。
  • a.build(n_trees) 用于构建 n_trees的森林。查询时,树越多,精度越高。在调用build后,无法再添加任何向量。
  • a.save(fn, prefault=False) 将索引保存到磁盘。保存后,不能再添加任何向量。
  • a.load(fn, prefault=False) 从磁盘加载索引。如果prefault设置为True,它将把整个文件预读到内存中。默认值为False。
  • a.unload() 释放索引。
  • a.get_nns_by_item(i, n, search_k=-1, include_distances=False)返回第i 个item的n个最近邻的item。在查询期间,它将检索 多达search_k(默认n_trees * n)个点。search_k为您提供了更好的准确性和速度之间权衡。如果设置include_distances为 True,它将返回一个包含两个列表的2元素元组:第二个包含所有对应的距离。
  • 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之间的距离。注意:此函数用于返回平方距离。
  • a.get_n_items() 返回索引中的向量数。
  • a.get_n_trees() 返回索引中的树的数量。
  • a.on_disk_build(fn) 用以在指定文件而不是RAM中建立索引(在添加向量之前执行
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值