4. mcVS编程指南

4.1. mcVS索引接口

使用mcVS时,通常遵循的接口调用顺序为:创建索引 -> 添加向量数据 -> 搜索向量

4.2. 索引的基本使用

本节介绍如何在曦云系列GPU上使用mcVS GPU索引。

4.2.1. 创建索引

创建一个索引类。

代码示例(C++)

使用C++ API时,首先需要创建一个Index类的实例:

raft::device_resources dev_resources;
ivf_flat::index_params index_params;
index_params.n_lists = 1024;
index_params.kmeans_trainset_fraction = 0.1;
index_params.metric = cuvs::distance::DistanceType::L2Expanded;
auto index = ivf_flat::build(dev_resources, index_params, dataset);

示例中,创建了一个GPU索引类,为使用欧式距离(L2)的IVFFlat索引类,nlist为1024。

代码示例(Python)

build_params = ivf_flat.IndexParams(n_lists=1024)
index = ivf_flat.build(build_params, xb)

4.2.2. 添加向量数据

将向量数据添加到索引中。

代码示例(C++)

int nb = 10000;     // 向量数据的数量
auto xb = raft::make_device_matrix<float, int64_t>(dev_resources, nb, d);
// 填充向量数据到xb
index = ivf_flat::extend(dev_resources, xb, std::nullopt, index);

代码示例(Python)

nb = 10000  # 向量数据的数量
# 填充向量数据到xb,这里使用随机数做示例
xb = cp.asarray(np.random.rand(nb, d).astype(np.float32))
index = ivf_flat.extend(index, xb)

添加操作可以反复进行,但是每次添加都有可能触发设备内存的重新分配。因此,为了提高数据添加的效率,建议批量添加数据。

4.2.3. 搜索向量

向量搜索是索引的核心功能,可以通过以下方式进行搜索。

代码示例(C++)

int nq = 10;        // 查询向量的数量
int topk = 3;       // 搜索的topk

auto xq = raft::make_device_matrix<float, int64_t>(dev_resources, n_queries, d);
// 填充查询向量数据到xq

auto neighbors    = raft::make_device_matrix<int64_t>(dev_resources, nq, topk);
auto distances    = raft::make_device_matrix<float>(dev_resources, nq, topk);
ivf_flat::search_params search_params;
search_params.n_probes = 2;
ivf_flat::search(
    dev_resources, search_params, index, xq, neighbors.view(), distances.view());

搜索结束后, distances 中保存了搜索结果的距离,neighbors 中保存了搜索结果的ID。

代码示例(Python)

nq = 10  # 查询向量的数量
topk = 3  # 搜索的topk
# 填充查询向量数据到xq,这里使用随机数做示例
xq = cp.asarray(np.random.rand(nq, d).astype(np.float32))
search_params = ivf_flat.SearchParams()
distances, neighbors = ivf_flat.search(
     search_params,
     index,
     xq,
     topk
)

通常情况下,GPU上的搜索效率会比CPU上的更高,但是在搜索之前需要将查询向量数据拷贝到GPU上,因此在实际使用的过程中,为了提高搜索的效率,建议进行批量搜索。