当前位置: 首页 > article >正文

向量数据库Faiss C++

目录

  • 1. Faiss简介
  • 2. FAISS 的主要特点
    • 2.1 高效性
    • 2.2 支持多种索引类型
    • 2.3 灵活性
    • 2.4 GPU 加速
    • 2.5 易于集成
  • 3. 应用场景
  • 4. 安装
    • 4.1 安装依赖
    • 4.2 编译源码
      • 4.2.1 下载Faiss源码
      • 4.2.2 编译
  • 5. Demo
    • 5.1 代码
    • 5.2 编译
    • 5.3 运行

1. Faiss简介

FAISS(Facebook AI Similarity Search)是由 Facebook AI Research 开发的一个高效的相似性搜索库,主要用于大规模向量数据的相似性搜索和聚类。它特别适合处理高维数据,如图像特征、文本嵌入等。

2. FAISS 的主要特点

2.1 高效性

FAISS 采用了多种高效的算法和数据结构,能够快速进行最近邻搜索(Nearest Neighbor Search),即使在大规模数据集上也能保持较好的性能。

2.2 支持多种索引类型

FAISS 提供了多种索引结构,包括:

  • 平面索引(Flat Index):简单直接,适合小规模数据。
  • 倒排索引(IVF):适合大规模数据,使用聚类来减少搜索空间。
  • HNSW(Hierarchical Navigable Small World):一种基于图的索引,适合高维数据。
  • PQ(Product Quantization):通过量化减少内存占用,适合处理大规模数据。

2.3 灵活性

FAISS 支持多种数据类型,包括浮点数和二进制数据。用户可以根据需求选择合适的索引类型和参数。

2.4 GPU 加速

FAISS 支持 GPU 加速,使得在处理非常大的数据集时能够显著提高性能。

2.5 易于集成

FAISS 提供了 C++ 和 Python 接口,方便用户在不同的应用场景中集成和使用。

3. 应用场景

FAISS 广泛应用于以下领域:

  • 图像检索:通过特征向量快速查找相似图像。
  • 自然语言处理:处理文本嵌入,进行相似句子或文档的检索。
  • 推荐系统:根据用户历史行为推荐相似项目。
  • 聚类分析:对高维数据进行聚类。

4. 安装

4.1 安装依赖

该项目依赖于BLAS 组件 OpenBLAS 和 IntelMKL BLAS 【官方支持】

4.2 编译源码

4.2.1 下载Faiss源码

Faiss源码地址

4.2.2 编译

cmake .. -DFAISS_ENABLE_GPU=OFF -DFAISS_ENABLE_PYTHON=OFF -DBUILD_SHARED_LIBS=ON -DFAISS_ENABLE_C_API=ON -DCMAKE_BUILD_TYPE=Release -DFAISS_ENABLE_CUVS=OFF -DBUILD_TESTING=OFF

基本参数介绍:

-DFAISS_ENABLE_GPU=ON *是否构建GPU支持

-DFAISS_ENABLE_PYTHON=OFF 是否构建Python 支持

-DBUILD_TESTING=ON 是否编译Testing 【依赖于googletest】

-DFAISS_ENABLE_C_API=ON 是否需要提高CAPI支持

-DCMAKE_BUILD_TYPE=Release 编译类型

-DBUILD_SHARED_LIBS=ON 是否生成动态库

GPU版本编译请参考:编译Faiss-gpu【InterMKL】C++

5. Demo

5.1 代码

FaissDB.h

#ifndef FACERECOGNITION_CPP_FAISSDB_H
#define FACERECOGNITION_CPP_FAISSDB_H
//faiss
#include <faiss/IndexHNSW.h>
#include <faiss/IndexIDMap.h>
#include <faiss/index_io.h>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <filesystem>

class FaissDB {
public:
	FaissDB(int dim, const std::string &db_name);
	~FaissDB();
	int insert(int n, const std::vector<float> &vec, const std::vector<faiss::idx_t> &ids);
	int query(int n, const std::vector<float> &vec, int topk, std::vector<float> &distances, std::vector<faiss::idx_t> &indices);
	int remove(const std::vector<faiss::idx_t> &ids);
private:
	std::unique_ptr<faiss::IndexHNSWFlat> _indexHNSW_ptr;
	std::unique_ptr<faiss::Index> _indexIDMap_ptr;
	std::mutex _rw_lock;
	std::string _db_name;
};

#endif //FAISSDB_H

FaissDB.cpp

#include "FaissDB.h"
#include <iostream>

using namespace std;

FaissDB::FaissDB(int dim, const std::string &db_name)
{
	this->_db_name = db_name;
	if (std::filesystem::exists(db_name))
	{
		_indexIDMap_ptr = unique_ptr<faiss::Index>(faiss::read_index(db_name.c_str()));
		std::cout<<"load faiss data success from file"<<std::endl;
	}
	else
	{
		_indexHNSW_ptr = unique_ptr<faiss::IndexHNSWFlat>(new faiss::IndexHNSWFlat(dim, 200));
		_indexIDMap_ptr= unique_ptr<faiss::IndexIDMap>(new faiss::IndexIDMap(_indexHNSW_ptr.get()));
	}
}

FaissDB::~FaissDB()
{
}

int FaissDB::insert(int n, const std::vector<float>& vec, const std::vector<faiss::idx_t>& ids)
{
	std::lock_guard<std::mutex> lk(_rw_lock);
	_indexIDMap_ptr->add_with_ids(n, vec.data(), ids.data());
	faiss::write_index(_indexIDMap_ptr.get(),  _db_name.c_str());
	return 0;
}

int FaissDB::query(int n, const std::vector<float>& vec, int topk, std::vector<float>& distances,
	std::vector<faiss::idx_t>& indices)
{
	std::lock_guard<std::mutex> lk(_rw_lock);
	if (_indexIDMap_ptr->ntotal == 0)
	{
		std::cerr << "Index is empty. Please add data before searching." << std::endl;
		return -1;
	}
	_indexIDMap_ptr->search(n, vec.data(), topk, distances.data(), indices.data());

	return 0;
}

int FaissDB::remove(const std::vector<faiss::idx_t>& ids)
{
	faiss::IDSelectorBatch selector(ids.size(), ids.data());
	return _indexIDMap_ptr->remove_ids(selector);
}

faiss-demo.cpp

#include "FaissDB.h"
using namespace std;

int main(){
	const int d = 128;
    const int n = 5;
    std::vector<float> data(d * n);

    for (int i = 0; i < d * n; ++i) {
        data[i] = static_cast<float>(rand()) / RAND_MAX;
    }

    std::vector<faiss::idx_t> ids = {101, 102, 103, 104, 105};

    int M = 16;
    FaissDB faiss_db(d, "faiss.index");
	faiss_db.insert(n, data.data(), ids.data());

    const int k = 3;
    std::vector<float> query(d);

    for (int i = 0; i < d; ++i) {
        query[i] = static_cast<float>(rand()) / RAND_MAX;
    }

    std::vector<faiss::idx_t> result_ids(k);
    std::vector<float> distances(k);

    faiss_db.query(1, query.data(), k, distances.data(), result_ids.data());

    std::cout << "search result:" << std::endl;
    for (int i = 0; i < k; ++i) {
        std::cout << "vector ID: " << result_ids[i] << ", dis: " << distances[i] << std::endl;
    }
    
	return 0;
}

这里我封装了3个接口,索引类型为HNSW,insert的时候指定id。
注意:如果要使用add_with_ids方法插入index,必须使用faiss::IndexIDMap封装一下,否则会报错

5.2 编译

g++ faiss-demo.cpp FaissDB.cpp -o faiss-demo -I/usr/local/include -L/usr/local/lib -lfaiss -fopenmp -lopenblas

5.3 运行

在这里插入图片描述


http://www.kler.cn/a/440761.html

相关文章:

  • Hololens 2 Unity VS2019编译报错解决方案
  • Go, Jocko, Kafka
  • 渗透测试学习笔记(五)网络
  • u3d动画系统六【动画根运动】
  • AI视频配音技术创新应用与商业机遇
  • 基于 Cell 架构的安全防护:现代应用程序领域的深度剖析与应对策略
  • 中英文网店系统运营风险 跨境电商平台法律与税务处理
  • 工业大数据分析算法实战-day07
  • #Js篇:map结构转普通js普通对象
  • Python毕业设计选题:基于django+vue的宠物服务管理系统
  • 汽车故障码 B100117 供电电压过高的解析及消除方法
  • 如何通过命令行解锁 macOS Gatekeeper(并恢复默认设置)
  • Ubuntu 系统下安装 Nginx
  • 戴森球计划新玩法!利用MOD和cpolar实现公网环境多人游戏
  • 游戏引擎学习第53天
  • Kafka实现监听多个topic
  • 2、C#基于.net framework的应用开发实战编程 - 设计(二、一) - 编程手把手系列文章...
  • 第19天:信息收集-Web应用源码获取闭源备份开发泄漏WebPack打包资源搜索ICO定位
  • ElasticSearch系列:索引分片调整
  • 奇绩创坛公开课第01课_创业走出第一步_陆奇:学习笔记