你早晚会用到,不收藏就找不到了
faiss是facebook发布的开源K近邻检索工具,结合服务可以进行在线的向量检索。比如在推荐和搜索领域,可以支持基于向量的召回、以图搜索等。但在某些场景下,我们也需要离线批量地进行大规模的向量检索。
举个例子,在一个相关推荐的场景,我们要在两个物品之间计算相关性,采用了向量距离度量的方式建模,当然我们可以把向量用faiss索引起来,取得当前商品的向量,进行k近邻检索,这没有问题。但是faiss在线部署也是有代价的,查询的性能远不如KV存储,甚至数据量超过单机容量后需要做分布式改造。所以如果在离线计算出每一个物品的K近邻,存储为KV或KKV的数据格式,最常见的NoSql数据库都可以轻松地地适用。
在给用户推荐的场景下,也有一些技术会离线计算item2item的数据,比如DeepI2I,采用深度学习的方法建模物品之间的关系,根据用户的历史行为,进行相似推荐;即便是根据用户实时推理得到向量,进行召回,无法离线提前构建的场景,在离线测评时,也需要进行大规模的K近邻检索。
直接将faiss用于离线检索,存在两个问题,第一是待索引的向量规模超过了单机规模,第二是查询的规模过大导致耗时不能接受,需要分布式解决。

通过MapReduce构建分布式查询的过程,在map阶段将数据切分至单机可接受的规模,对于索引来讲,一般闲置是内存大小,对于查询,闲置则是查询的整体耗时,设置合适的N和M,把query分成N份,每一份复制M份,把待索引的数据分成M份,每一份复制N份,在reduce阶段,每一个格子中,某一份查询在某一份索引上完成knn检索,然后再通过一个reduce进行topk的归并,保证每一份query都能在所有的候选向量索引分片上进行检索。
在单机K近邻查询上,使用了faiss,但faiss官方只提供了C++和Python的版本,而Hadoop MR的原生接口是Java的。Python实际上通过Swig调用了C++接口,Java也可以。在Docker里编译好Java的faiss库,用于MR的调用。
git地址:
文档
在离线大数据平台上进行K近邻检索,通过MapReduce进行分布式执行,可以达到在千万级索引上批量亿级查询的规模,真正地应用于工业级场景。
用途
- DeepI2I计算物品向量,离线构建i2i
- 深度向量召回的离线大规模测评
- 基于content-based的i2i数据
- 在同类目下进行knn查询
功能
- 全集合knn查询
- 分组knn查询
原理
通过MapReduce,将索引和查询的数据都进行分片,减少数据量到单机运行时间可接受的规模,调用faiss进行K进行查询,然后再对多个partition进行topk归并。
在Reducer上单机knn检索采用了faiss库,faiss通过java-jni调用。
start
网络环境不好的话,
docker build多试几次,最后一句执行成功不报错说明faiss-jni得到了编译和调用成功了执行之后,target目录下就得到了knn-tool-mr-0.0.1.jar,这是可以直接拿到hadoop上用的
src/main/java/com/gameofdimension/faiss/swig/下的代码和/cpu/src/main/resources/_swigfaiss.so的资源文件是为了方便使用IDE编码,从docker里拉出来的,然后其实在mac环境上,也可以用maven打包了,一样可以执行准备向量文件,格式为
执行mr任务,参数依次为query向量,索引向量,查询结果,选项
同组内查询,格式为
执行
参数

感谢
通过swig进行java-jni编译参考了 https://github.com/gameofdimension/jni-faiss
搭建hadoop-hive环境调试所用的库 https://github.com/big-data-europe/docker-hive