跳到主要内容

向量索引选取建议

seekdb 提供了多种不同算法的向量索引,用户可以依据使用场景选择合适的索引类型。

备注

本文档仅提供稠密向量索引类型的选型优化建议。

HNSW 还是 IVF?

seekdb 的稠密向量索引分为两大类:

  • 基于图的 HNSW 系列索引:HNSW、HNSW_SQ、HNSW_BQ。
  • 基于磁盘的 IVF 系列索引:IVF、IVF_PQ。

这两种索引类型各有侧重。HNSW 系列索引通常提供更高的查询性能,但需要占用更多常驻内存;而 IVF 系列索引在缓存充足时性能表现良好,且能够不依赖常驻内存运行。然而,选择 HNSW 还是 IVF 并非仅基于内存考量,业务场景、数据规模、性能指标以及资源约束等多个维度都需综合评估,下文将详细对比其核心差异并提供选择建议。

核心差异对比

对比维度HNSW 系列IVF 系列
存储方式基于内存的图结构索引基于磁盘的索引
内存占用需要完整载入内存,内存占用高可不占用常驻内存,内存占用低
查询性能(QPS)极高,毫秒级响应较高,在缓存充足时接近 HNSW
召回率高,可达 99%较高,略低于 HNSW,可通过参数调优
构建速度较慢,需要构建图结构较快,基于聚类算法
适用数据量百万级到亿级百万级到十亿级
成本内存成本高存储成本低,适合大规模数据
实时性支持实时 DML 操作支持实时 DML 操作

决策流程图

备注
  1. 在选择索引类型前,您需要先参考向量索引内存管理估算内存用量。
  2. 决策流程图中的选择建议均以 1024 维向量为参考,若实际维度不同,可按比例近似换算所需资源。
  3. 决策流程图主要从内存成本角度出发,帮助您决策索引类型。
  4. 即使租户内存充足,也不一定总是选择 HNSW 等最高规格索引。如果对极致性能有较高需求,可以考虑 HNSW_SQ 等更具性价比的选项。

决策流程图

备注

这里仅列举了部分常用场景的决策流程,如果通过上述路径无法判断,或有其他需求,请联系 seekdb 技术支持。

是否使用分区表?

使用分区表的主要目的是为了解决大数据量的场景,其次是如果查询条件可以用于做分区键,那么通过分区裁剪可以提升查询性能。在以下两种场景下建议使用分区表:

  • 数据量达到几千万或亿级以上:当数据量非常大时,使用分区表可以将数据分散到多个分区,每个分区独立构建索引,从而降低单次查询负载,提升整体查询性能。
  • 查询条件中有明确的标量列可以用作分区裁剪:例如,如果 label 字段总是会出现在 WHERE 条件中,那么就可以考虑以 label 作为分区键创建分区表,通过分区裁剪减少需要查询的分区数量。

具体使用建议如下:

分区划分

在使用向量索引时,分区数量不宜过多。与标量索引不同,向量索引(如 HNSW)在相同配置下,索引规模从 100 万向量增大到 200 万向量,查询 TopK 所需的计算开销并不会显著增加。因此,如果不能利用分区裁剪,过多的分区反而可能降低性能。另外,单个分区过大不仅会导致索引重建耗时增加,还会影响与标量条件联合查询时的效率。

综上,推荐将每个分区内的数据量控制在 2000 万以下,并优先选择能够支持分区裁剪的字段作为分区键

算法选择

在大数据量下建议选择 HNSW_BQ 或 IVF_PQ 索引。如需使用其他索引,请参考下文内存占用章节进行估算。

内存占用

HNSW_BQ

对于 HNSW_BQ 索引,建议 租户内存 > HNSW_BQ 查询时总内存占用 + 单分区 HNSW_SQ 索引占用。内存预估流程如下:

  1. 优先通过 INDEX_VECTOR_MEMORY_ADVISOR 函数计算 HNSW_BQ 及 HNSW_SQ 索引在构建及查询过程中的推荐内存值。
  2. 基于上述工具获得的推荐内存值,计算并确定租户所需内存总量。

例如,假设拥有 1 亿条 1024 维向量数据,采用 10 个分区(每个分区约 1000 万向量)。按照上述流程,具体计算过程如下:

-- 指定 REFINE_TYPE=SQ8 即可直接准确获取 HNSW_BQ 索引在构建及查询过程中的推荐内存值,
-- 无需再额外单独计算 HNSW_SQ 索引的占用。这是因为 HNSW_BQ 在构建时默认使用 SQ8 量化算法构图,
-- 指定 refine_type=sq8 后,函数会自动将该索引构建时所需的 SQ8 量化向量所需的内存计算在内
-- HNSW_BQ 索引的推荐内存值为 74.6 GB,查询时内存占用为 57.4 GB,我们取用推荐内存值
SELECT DBMS_VECTOR.INDEX_VECTOR_MEMORY_ADVISOR('HNSW_BQ',100000000,1024,'FLOAT32','M=32,DISTANCE=COSINE,REFINE_TYPE=SQ8', 10000000);
+------------------------------------------------------------------------------------------------------------------------------+
| DBMS_VECTOR.INDEX_VECTOR_MEMORY_ADVISOR('HNSW_BQ',100000000,1024,'FLOAT32','M=32,DISTANCE=COSINE,REFINE_TYPE=SQ8', 10000000) |
+------------------------------------------------------------------------------------------------------------------------------+
| Suggested minimum vector memory is 74.6 GB, memory consumption when providing search service is 57.4 GB |
+------------------------------------------------------------------------------------------------------------------------------+
1 row in set

-- 向量内存在租户内存中的占比默认为 50%,因此总租户内存为
SELECT 74.6/0.5;
+--------------------------------------------------------------------------------------------------------------+
| 74.6/0.5 = 149.2 GB |
+--------------------------------------------------------------------------------------------------------------+
1 row in set

-- 考虑到实际环境中新写入数据未及时压缩的情况,建议适当预留冗余
SELECT 149.2 * 1.2;
+--------------------------------------------------------------------------------------------------------------+
| 149.2 * 1.2 = 179.04 GB |
+--------------------------------------------------------------------------------------------------------------+
1 row in set

-- 因此,建议租户内存配置为 179 GB

IVF 系列

对于 IVF 和 IVF_PQ 索引,建议 租户内存 > 单个分区构建内存 + 所有分区常驻内存总和。例如,1 亿条数据,采用 10 个分区,每个分区约 1000 万向量,单分区构建时大约需要 2.7 GB 内存,查询时 10 个分区的 IVF_PQ 索引合计常驻约 1.1 GB(110 MB/分区)。因此,最低需配置大约 3 GB 内存。建议在此基础上适当留有富余,推荐配置 6 GB 内存。其他数据量场景可参照上述方法估算。

构建和查询参数

索引构建与查询参数建议以单分区的最大数据量为基准设置。详见下文索引参数建议章节。

性能和召回率

  • 若查询条件可以裁剪到单个分区:则性能和召回率与单分区场景一致,详见下文不同规模数据量详细说明的章节。
  • 若无法裁剪到单分区:QPS 可按单 OBServer 节点上的分区数量等比例预估(例如,单节点包含 3 个分区,则 QPS 约为单分区性能的 1/3);由于跨分区查询会合并更多候选结果,实际召回率通常高于单分区情形。

索引参数建议

HNSW 系列

同系列的索引在不同的数据量下,推荐的索引构建和查询参数是不相同的。本节给出百万和千万数据量下,768 维度向量,HNSW/HNSW_SQ/HNSW_BQ 索引的建议配置供参考。对于亿级别的向量数据,请参考本文后续章节选用 IVF_PQ 索引,或分区表下的 HNSW_BQ 索引。

备注

对于数据量预计会增长的场景,建议根据最终数据量进行参数设置。

提示

HNSW_BQ 是高压缩率的量化算法,在低维向量下的召回率上限可能较低。为避免性能损失,建议 HNSW_BQ 使用在 512 维及以上的向量上。

场景索引类型参数建议
最高召回
(内存占用最多)
HNSW百万数据量:m = 16,ef_construction = 200,ef_search = 100,其他参数默认
最高性能
(内存占用较少)
HNSW_SQ百万数据量:m = 16,ef_construction = 200,ef_search = 100,其他参数默认
千万数据量:m = 32,ef_construction = 400,ef_search = 350,其他参数默认
最佳性价比
(内存占用少,性能好)
HNSW_BQ百万数据量:m = 16,ef_construction = 200,ef_search = 100,其他参数默认
千万数据量:m = 32,ef_construction = 400,ef_search = 1000,refine_k = 10,其他参数默认
亿级数据量:使用分区表,m = 32,ef_construction = 400,ef_search = 1000,refine_k = 10,其他参数默认

百万级数据量详细说明

以 100 万条 768 维向量数据为例(使用上表中的构建参数),补充说明内存占用和召回率调优:

内存占用:

索引类型建议租户内存说明
HNSW15 GB向量索引内存大小建议值为 7.3 GB。租户内存大于 8 GB 时,向量索引默认最多使用租户内存的 50%;租户内存小于等于 8 GB 时,向量索引默认最多使用租户内存的 40%。因此大约需要 15 GB 的租户内存。
HNSW_SQ6 GB向量索引内存大小建议值为 2.1 GB。
HNSW_BQ6 GBHNSW_BQ 索引在构建时需要用到高精度的向量,所以构建过程中和 HNSW_SQ 的内存需求一样,都是 6 GB。HNSW_BQ 索引默认采用 SQ8 量化方法,索引构建完成后,内存占用会大幅降低,仅约 405 MB。
上述说明适用于非分区表场景。如果使用分区表,seekdb 会根据租户分配的内存动态调节可以同时构建的分区数量。实际配置时,建议租户内存至少包括 HNSW_BQ 查询时的内存占用量,加上构建某个分区时 HNSW_SQ 需要的内存,留有一定冗余,具体计算方式请参考上文 内存占用 章节。

召回率调优:

通过调整 ef_searchrefine_k(仅 HNSW_BQ)参数,可以通过更多的向量计算来提高召回率,但相应的会降低查询性能。在不同 TopN 下可将参数设置为下表中的建议值,如果需要进一步提升召回率,则可将参数值设置得更大一些。

提示

召回率和数据特征有直接关系,下表给出的是 768 维标准数据集下,召回率达到 0.95 左右的建议值。

TopNef_searchrefine_k(仅 HNSW_BQ)
Top10644
Top1002404

极限召回率说明:

几种索引算法的极限召回率不同。在本节设置建议的构建参数下,将 ef_search 设置为 1000 时,查询的召回率可能有所提升,但QPS 会降低到 0.95 召回率时的 1/3,同时调大ef_search,并不是所有类型的索引召回率都能无限提升,仅有 HNSW 能达到 0.99 以上的召回率。HNSW_BQ 索引可以通过进一步增加 refine_k 来提高召回率,但性能也会进一步下降。

极限召回率参考值(ef_search = 1000):

  • HNSW 索引:召回率 0.991
  • HNSW_SQ 索引:召回率 0.9786
  • HNSW_BQ 索引:召回率 0.9897(ef_search = 1000,refine_k = 10)

千万级数据量详细说明

以 1000 万条 768 维向量数据为例(使用上表中的构建参数),补充说明内存占用和召回率调优:

内存占用:

索引类型建议租户内存说明
HNSW160 GB向量索引内存大小建议值为 76.3 GB。
HNSW_SQ48 GB向量索引内存大小建议值为 22.6 GB。
HNSW_BQ48 GBHNSW_BQ 索引在构建过程中需要使用高精度的向量。HNSW_BQ 默认使用 HNSW_SQ 作为索引构建中的缓存,因此对于非分区表,HNSW_BQ 所需要的内存和 HNSW_SQ 相同。构建完成后,HNSW_BQ 索引只占用约 5.4 GB 的内存。

召回率调优:

通过调整 ef_searchrefine_k(仅 HNSW_BQ)参数,可以通过更多的向量计算来提高召回率,但相应的会降低查询性能。在不同 TopN 下可将参数设置为下表中的建议值,如果需要进一步提升召回率,则可将参数值设置得更大一些。

提示

召回率和数据特征有直接关系,下表给出的是 768 维标准数据集下,召回率达到 0.95 左右的建议值。

TopNef_searchrefine_k(仅 HNSW_BQ)
Top101004
Top100(HNSW/HNSW_SQ)350-
Top100(HNSW_BQ)100010

IVF 系列

场景索引类型参数建议
低维度
(384 维及以下)
IVF千万数据量:使用分区表,nlist=3000
亿级数据量:使用分区表,nlist=3000
低成本
(内存占用极少)
IVF_PQ百万数据量:nlist=1000, m=向量维度/2
千万数据量:nlist=3000, m=向量维度 / 2
亿级数据量:使用分区表,nlist=3000, m=向量维度 / 2

为了兼顾聚类中心数量与每个中心包含的数据量,通常推荐将 nlist 设置为数据量的平方根。例如,1000 万数据建议 nlist 选取 3000 左右。在使用 IVF_PQ 时,m 参数建议取向量维度(dim)的一半。

提示

IVF_PQ 是高压缩率的量化算法,在低维向量下的召回率上限可能较低。为避免性能损失,建议 IVF_PQ 使用在 128 维及以上的向量上。

备注

对于数据量预计会增长的场景,建议根据最终数据量进行参数设置。

千万级数据量(结合分区表)

以 1000 万条 768 维向量数据为例(使用上表中的构建参数),补充说明内存占用和召回率调优:

内存占用:

索引类型索引参数内存开销(构建开销/常驻开销)
IVFdistance=l2, nlist=30002.7 GB/ 10.5 MB
IVF_PQdistance=l2, nlist=3000, m=3844.0 GB/ 1.3 GB
IVF_PQdistance=cosine, nlist=3000, m=3842.7 GB/ 11.4 MB

表格中构建开销表示索引在创建过程中临时占用的内存,构建完成后这部分内存会被释放;常驻开销是指索引构建完成后,IVF 向量索引持续占用的内存。

对于 IVF_PQ 索引,如果选择 distance = l2,会因需要存储额外的预计算结果而占用更多常驻内存;相比之下,使用 distance = inner_product 或 cosine 时常驻内存消耗较低。因此,实际应用中通常推荐优先选择 inner_product 或 cosine 作为距离类型,以优化内存资源。

召回率调优:

通过调整 nprobes 参数,可以通过更多的向量计算来提高召回率,但相应的会降低查询性能。在不同 TopN 下可将参数设置为下表中的建议值,如果需要进一步提升召回率,则可将参数值设置得更大一些。

提示

召回率和数据特征有直接关系,下表给出的是 768 维标准数据集下,召回率达到 0.95 左右的建议值。

TopNnprobes
Top101
Top10020

亿级数据量(结合分区表)

当向量数据量达到亿级及以上时,强烈推荐采用分区表结合 IVF 类索引。随着数据规模和 nlist 参数的增加,单个 IVF 索引的查询开销也会显著提升。通过将数据拆分到多个分区,每个分区分别构建较小规模的 IVF 索引,可有效降低单次查询负载,并通过分区并行查询进一步提升整体查询性能和召回率。

对于多分区表场景,由于 IVF 索引为本地索引,每个分区都会独立构建 IVF 索引,因此建议按照每个分区的平均数据量来计算 nlist 的取值。例如,1 亿条 768 维向量,分为 10 个分区时,每个分区约 1000 万条数据,nlist 推荐设为 sqrt(1000 万)=3162。

以 1 亿条 768 维向量数据为例(使用上表中的构建参数),补充说明内存占用和召回率调优:

内存占用:

对于多分区场景,由于 IVF 索引为本地索引,每个分区都会独立构建和维护一个 IVF 索引,因此常驻内存的总占用需按分区数量进行累加。例如,下表中单个 IVF 索引的常驻内存为 10.5 MB,若有 10 个分区,则总常驻内存约为 10.5 × 10 = 105 MB。

索引类型索引参数内存开销(构建开销/常驻开销)
IVFdistance=l2, nlist=30002.7 GB/ 10.5 * 10 MB
IVF_PQdistance=l2, nlist=3000, m=3844.0 GB/ 1.3 * 10 GB
IVF_PQdistance=cosine, nlist=3000, m=3842.7 GB/ 11.4 * 10 MB

表格中构建开销表示索引在创建过程中临时占用的内存,构建完成后这部分内存会被释放;常驻开销是指索引构建完成后,IVF 向量索引持续占用的内存。

召回率调优:

通过调整 nprobes 参数,可以通过更多的向量计算来提高召回率,但相应的会降低查询性能。在不同 TopN 下可将参数设置为下表中的建议值,如果需要进一步提升召回率,则可将参数值设置得更大一些。

在分区表场景下,由于每个分区会独立执行 IVF 索引查询,用户在查询时如果涉及多个分区,会分别从每个分区检索 TopN 结果,然后将所有分区的结果进行汇总和重排序。这样不仅提升了整体的搜索准确率,还使得实际召回率通常高于单分区场景。因此,在多分区表中,可以适当降低 nprobes 参数的设置,即可获得与单分区表相当的召回率。

提示

召回率和数据特征有直接关系,下表给出的是 768 维标准数据集下,召回率达到 0.95 左右的建议值。

TopNnprobes
Top101
Top10010

相关文档