Nova 向量检索引擎
Nova 是 AnalyticDB for PostgreSQL 7.0 的向量检索引擎,提供磁盘型 Novad 和内存型 Novam 两类索引。本文介绍 Nova 的功能特性、索引选型、容量评估、创建与查询方法、参数调优以及运维管理。
功能概述
什么是 Nova
Nova 是 AnalyticDB for PostgreSQL 7.0 内置的高性能向量检索引擎,提供磁盘型 Novad 和内存型 Novam 两类索引算法。Nova 在查询性能、存储效率和运维便捷性方面进行了深度优化,适用于大规模向量相似度检索场景,如 RAG(检索增强生成)、语义搜索和推荐系统。
核心能力
与传统的 HNSW 索引相比,Nova 提供以下增强能力:
|
能力 |
说明 |
|
自适应搜索 |
在查询速度和召回率之间自动取舍,无需手动调参即可获得良好的检索效果。 |
|
灵活的存储方案 |
Novad 将主要索引数据存储在磁盘,支持 RaBitQ、SQ8 等量化压缩方式以及 halfvec、bit、sparsevec、sq8vector 等多种向量类型,大幅降低存储成本。 |
|
Delta-Base 写入架构 |
将数据写入与主索引构建解耦,新数据先写入内存 Delta 文件,后台异步合并到主索引。写入积压时自动触发反压机制,保障系统稳定性。 |
|
并发创建索引 |
支持 |
|
INCLUDE 列 |
将额外列存入索引,查询命中这些列时可直接从索引返回结果,减少回表开销。 |
|
PCA 自动降维 |
支持按方差解释率自动选择目标维度,也支持手动指定维度,有效降低计算量和存储占用。 |
|
Autotune 自动调参 |
只需指定 topK 和目标召回率,系统自动评估并应用最优搜索参数。支持传入真实查询表进行精细调优,也可基于索引数据生成合成查询。 |
前提条件
-
AnalyticDB for PostgreSQL 7.0 实例,内核版本为 7.4.2.7 或更高。
-
已开启向量检索引擎优化 。
快速开始
以下示例演示如何创建表、建立 Nova 索引并执行向量查询。
创建示例表
创建一个包含文本内容和向量列的示例表。
CREATE TABLE chunks (
id SERIAL PRIMARY KEY,
chunk VARCHAR(1024),
intime TIMESTAMP,
url VARCHAR(1024),
feature REAL[]
) DISTRIBUTED BY (id);
示例返回
CREATE TABLE
创建 Nova 索引
使用默认算法 novamr(带 RaBitQ 量化的内存型索引)创建向量索引。RaBitQ 量化可显著降低内存占用。
-- 使用默认算法 novamr,RaBitQ 量化可显著降低内存占用
CREATE INDEX idx_feature_novamr ON chunks
USING ann(feature)
WITH (
dim = 1536,
distancemeasure = cosine
);
示例返回
CREATE INDEX
Novamr 当前固定使用 7 bit,不支持自定义 rabitq_bits。
执行向量查询
使用 <=> 运算符计算余弦距离,返回最相似的 10 条结果。
SELECT id,
chunk,
feature <=> ARRAY[0.1, 0.2, ...]::real[] AS distance
FROM chunks
ORDER BY distance
LIMIT 10;
示例返回(以实际数据为准)
id | chunk | distance
----+--------------------+----------
12 | Nova 向量检索 | 0.0831
7 | PostgreSQL 检索 | 0.1047
......
31 | 混合检索实践 | 0.1284
(10 rows)
索引选型与容量
Novad 与 Novam 对比
Nova 提供 Novad(磁盘型)和 Novam(内存型)两类索引,适用于不同的业务场景:
-
Novad(磁盘型):HNSW 加速层常驻内存,IVF 聚类数据保存在磁盘。对内存依赖低,索引构建速度快,磁盘占用小,支持 RaBitQ 和 SQ8 量化。适合大规模数据、成本敏感的检索场景。
-
Novam(内存型):基于图索引构建。内存充足时,同等规格下查询性能优于 Novad;内存不足时会回退到磁盘访问。支持 RaBitQ 和 SQ8 量化,可在内存占用与召回率之间灵活调整。适合实时推荐等低延迟场景。
Novam 索引变体
|
算法名 |
说明 |
|
|
不带量化压缩的图索引,全精度存储。 |
|
|
带 RaBitQ 量化的图索引(默认算法,固定使用 7 bit,不支持自定义 |
|
|
带 SQ8 标量量化的图索引。 |
Novad 索引变体
|
算法名 |
说明 |
|
|
带 RaBitQ 量化的分区索引( |
|
|
不带量化压缩的分区索引。全精度存储,召回率最高。 |
|
|
带 SQ8 标量量化的分区索引。使用 |
容量评估
以下表格列出不同向量维度和计算资源下的建议数据量上限。实际容量受数据分布、查询模式等因素影响,建议根据业务需求进行压测验证。
Novad 容量参考
|
总计算资源 |
128 维 |
256 维 |
512 维 |
768 维 |
1024 维 |
1536 维 |
2048 维 |
|
8c |
320M |
160M |
80M |
50M |
40M |
26M |
20M |
|
16c |
640M |
320M |
160M |
100M |
80M |
60M |
40M |
|
32c |
1.28B |
640M |
320M |
200M |
160M |
120M |
80M |
|
128c |
5.12B |
2.56B |
1.28B |
800M |
640M |
480M |
320M |
Novam 容量参考
|
总计算资源 |
128 维 |
256 维 |
512 维 |
768 维 |
1024 维 |
1536 维 |
2048 维 |
|
8c |
32M |
16M |
8M |
5M |
4M |
2.6M |
2M |
|
16c |
64M |
32M |
16M |
10M |
8M |
5M |
4M |
|
32c |
128M |
64M |
32M |
20M |
16M |
10M |
8M |
|
128c |
512M |
256M |
128M |
80M |
64M |
40M |
32M |
向量类型与距离度量
支持的向量类型
Nova 支持多种向量数据类型,覆盖稠密向量、稀疏向量和二值向量等场景。
|
数据类型 |
说明 |
最大维度 |
|
|
单精度浮点数组 |
8,000 |
|
|
pgvector 兼容的稠密向量类型 |
8,000 |
|
|
半精度浮点向量,存储空间约为 |
16,000 |
|
|
半精度浮点数组 |
16,000 |
|
|
二值向量,适用于哈希指纹等场景 |
256,000 |
|
|
pgvector 兼容的稀疏向量类型(最大非零元素 4,000) |
1,000,000,000 |
|
|
稀疏向量类型(最大非零元素 4,000) |
1,000,000,000 |
|
|
SQ8 压缩向量,以 INT8 格式存储,节省内存 |
8,000 |
支持的距离度量
|
距离度量 |
参数值 |
SQL 运算符 |
说明 |
适用向量类型 |
|
欧氏距离(平方) |
|
|
适用于图片相似度检索 |
vector, halfvec, float4[], float2[], int2[], sparsevec, svector, sq8vector |
|
反内积距离 |
|
|
向量归一化后可替代余弦相似度 |
vector, halfvec, float4[], float2[], int2[], sparsevec, svector, sq8vector, bit |
|
余弦距离 |
|
|
适用于文本相似度检索 |
vector, halfvec, float4[], float2[], int2[], sparsevec, svector, sq8vector |
|
曼哈顿距离 |
|
|
L1 距离 |
vector, halfvec, sparsevec |
|
杰卡德距离 |
|
|
适用于集合相似度度量 |
bit |
|
汉明距离 |
|
|
适用于二进制编码相似度 |
bit |
特殊向量类型使用示例
halfvec(半精度向量)
halfvec 使用半精度浮点数存储,内存占用约为 vector 的一半,适合对内存敏感的高维向量场景。
-- 创建 halfvec 类型的表
CREATE TABLE chunks_half (
id SERIAL PRIMARY KEY,
feature halfvec(1536)
) DISTRIBUTED BY (id);
-- 创建索引
CREATE INDEX idx_half ON chunks_half
USING ann(feature)
WITH (
dim = 1536,
algorithm = novamr,
distancemeasure = cosine
);
sq8vector(SQ8 压缩向量)
sq8vector 以 INT8 格式存储向量,进一步压缩内存。配合 Novam 或 Novad 索引使用。
-- 创建 sq8vector 类型的表
CREATE TABLE chunks_sq8 (
id SERIAL PRIMARY KEY,
feature sq8vector(1536)
) DISTRIBUTED BY (id);
-- 创建 Novam 内存型 SQ8 索引
CREATE INDEX idx_sq8 ON chunks_sq8
USING ann(feature)
WITH (
dim = 1536,
algorithm = novam,
distancemeasure = cosine
);
-- 也可创建 Novad 磁盘型 SQ8 索引
-- sq8vector + novadflat 自动切换为 novadsq8
CREATE INDEX idx_sq8_disk ON chunks_sq8
USING ann(feature)
WITH (
dim = 1536,
algorithm = novadflat,
distancemeasure = cosine
);
稀疏向量(svector)
Nova 使用 svector 存储稀疏向量。每个稀疏向量包含两组一一对应的数据:
-
indices:非零维度的编号(从 0 开始)。 -
values:对应维度的值。
例如,一个 8 维稀疏向量,索引 2、3、6 对应的值分别为 1.2、1.1、0.7,其余位置为 0:
SELECT '{"indices":[2,3,6],"values":[1.2,1.1,0.7]}'::svector(8);
示例返回
svector
------------------------------------------------------
{"indices":[2,3,6],"values":[1.2,1.1,0.7]}
(1 row)
indices 和 values 的元素数量必须相同,并按位置一一对应。svector(N) 使用从 0 开始的下标,有效范围为 [0, N-1]。例如,svector(8) 的有效下标为 0~7。
创建稀疏向量表示例并创建索引:
DROP TABLE IF EXISTS sparse_docs;
CREATE TABLE sparse_docs (
id BIGINT PRIMARY KEY,
title TEXT NOT NULL,
category TEXT NOT NULL,
publish_at TIMESTAMP NOT NULL,
embedding svector(8) NOT NULL
) DISTRIBUTED BY (id);
INSERT INTO sparse_docs(id, title, category, publish_at, embedding) VALUES
(1, 'PostgreSQL 全文检索', 'search', '2024-01-01',
'{"indices":[1,3,7],"values":[0.8,1.5,0.4]}'),
(2, 'Nova 稀疏向量检索', 'search', '2024-02-01',
'{"indices":[2,3,6],"values":[1.2,1.1,0.7]}'),
(3, '向量数据库实践', 'vector', '2024-03-01',
'{"indices":[1,4,7],"values":[0.9,1.3,1.0]}'),
(4, '数据分析基础', 'analytics', '2024-04-01',
'{"indices":[5,7],"values":[1.4,0.6]}'),
(5, '混合检索方案', 'search', '2024-05-01',
'{"indices":[2,4,6,7],"values":[0.6,1.1,1.2,0.9]}');
-- 使用内积衡量相关性,创建稀疏向量索引
CREATE INDEX sparse_docs_embedding_idx
ON sparse_docs
USING ann (embedding)
WITH (
algorithm = 'novam',
distancemeasure = 'ip'
);
ANALYZE sparse_docs;
使用一个 8 维查询向量返回最相关的 3 条数据:
SELECT
id,
title,
category,
-(embedding <#>
'{"indices":[2,3,6],"values":[1,1,0.5]}'::svector(8)
) AS score
FROM sparse_docs
ORDER BY embedding <#>
'{"indices":[2,3,6],"values":[1,1,0.5]}'::svector(8)
LIMIT 3;
示例返回
|
id |
title |
category |
score |
|
2 |
Nova 稀疏向量检索 |
search |
2.650 |
|
1 |
PostgreSQL 全文检索 |
search |
1.500 |
|
5 |
混合检索方案 |
search |
1.200 |
在上述查询中:
-
<#>计算负内积。负内积越小,内积越大,相关性越高。 -
ORDER BY embedding <#> 查询向量按相关性从高到低排序,并允许优化器使用 Nova 索引。
二值向量(bit)
bit 类型用于存储二值向量,适用于哈希指纹等场景。支持汉明距离和杰卡德距离。
-- 创建 bit 类型的表
CREATE TABLE chunks_bit (
id SERIAL PRIMARY KEY,
feature bit(256)
) DISTRIBUTED BY (id);
-- 使用汉明距离创建索引
CREATE INDEX idx_bit ON chunks_bit
USING ann(feature)
WITH (
dim = 256,
algorithm = novam,
distancemeasure = hamming
);
创建索引
基本语法
CREATE INDEX [CONCURRENTLY] [index_name]
ON [schema_name].[table_name]
USING ann(column_name)
WITH (dim = <dimension>,
algorithm = <algorithm>,
distancemeasure = <measure>,
...);
创建 Novad 索引
以下示例创建一个磁盘型 Novad 索引,使用余弦距离度量。
novad 和 novadr 要求向量维度至少为 32;低于 32 维时请使用 novadflat。
CREATE INDEX idx_feature_novad_cosine ON chunks
USING ann(feature)
WITH (
dim = 1536,
algorithm = novad,
distancemeasure = cosine,
nlist = 2048,
accel_m = 32
);
创建 Novam 索引
以下示例创建一个内存型 Novam 全精度索引,使用欧氏距离度量。
CREATE INDEX idx_feature_novam_l2 ON chunks
USING ann(feature)
WITH (
dim = 1536,
algorithm = novam,
distancemeasure = l2,
hnsw_m = 32,
hnsw_ef_construction = 200
);
并发创建索引
Nova 支持 PostgreSQL 的 CREATE INDEX CONCURRENTLY 语法。创建期间业务可继续读写,避免锁表影响在线服务。
CREATE INDEX CONCURRENTLY idx_chunks_feature_novad
ON chunks
USING ann(feature)
WITH (
dim = 1536,
algorithm = novad,
distancemeasure = cosine,
nlist = 2048
);
CREATE INDEX CONCURRENTLY 不能在显式事务块中执行。执行后必须检查 pg_index.indisvalid 和 indisready。如果任一为 false,不要使用该索引;请执行 DROP INDEX index_name 清理后重建。
INCLUDE 列
INCLUDE 可把额外列写入索引,命中这些列时减少回表:
CREATE INDEX [index_name]
ON [schema_name].[table_name]
USING ANN(column_name) INCLUDE (col1, col2, ...)
WITH (dim = <dimension>,
algorithm = <algorithm>,
distancemeasure = <measure>,
...);
使用示例
-- 将 id 和 url 列包含在索引中,支持 Index Only Scan 和 Index Scan 不回表
CREATE INDEX idx_feature_include ON chunks
USING ann(feature) INCLUDE (id, url)
WITH (
dim = 1536,
algorithm = novad,
distancemeasure = cosine
);
PCA 降维
PCA 降维可在保留主要信息的前提下降低向量维度,减少计算量和存储占用。支持自动和手动两种方式。
pca_dim 与 auto_reduction 不能同时设置:自动降维只设置 auto_reduction,手动降维只设置 pca_dim。
自动选择维度:按方差解释率自动选择目标维度(默认阈值 98%)。
CREATE INDEX idx_pca_auto ON chunks
USING ann(feature)
WITH (
dim = 1536,
algorithm = novamr,
distancemeasure = cosine,
auto_reduction = true
);
手动指定维度:通过 pca_dim
指定降维后的目标维度,目标维度需要需要为64的整数倍。
CREATE INDEX idx_pca ON chunks
USING ann(feature)
WITH (
dim = 1536,
algorithm = novamr,
distancemeasure = cosine,
pca_dim = 256
);
索引构建参数
基本参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
向量维度(必填,或从列类型自动推断) |
无 |
[1, 8192](视向量类型而定) |
|
|
索引算法 |
|
novam, novamflat, novamr, novamsq8, novad, novadflat, novadr, hnswflat |
|
|
距离度量算法 |
|
l2, ip, cosine, l1, jaccard, hamming |
Novam 构建参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
图中每个节点的双向连接数。值越大图质量越好,构建时间越长。 |
16 |
[2, 100] |
|
|
构建时搜索候选集大小。值越大图质量越好,构建时间越长。需 ≥ 2 × hnsw_m。 |
64 |
[4, 1000] |
|
|
Novamr 固定使用 7 bit,不支持自定义 rabitq_bits |
7 |
不支持配置 |
Novad 构建参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
IVF 聚类列表数 |
1024 |
[2, 1073741824] |
|
|
加速层(中心点导航 HNSW)邻居数 |
16 |
[8, 1024] |
|
|
加速层构建候选集大小 |
128 |
[1, 32768] |
|
|
RaBitQ 量化比特数(仅 novad/novadr) |
1 |
[1, 8] |
PCA 参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
PCA 降维后的目标维度。0 表示不启用。 |
0 |
需小于原始维度,且为 64 的整数倍 |
|
|
启用基于方差阈值的自动维度选择,与 |
false |
true / false |
|
|
启用 PCA 白化 |
false |
true / false |
|
|
启用 PCA 随机旋转 |
false |
true / false |
系统级构建参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
索引构建的最大并行进程数 |
75% 计算节点资源 |
[1, 128] |
|
|
IVF 聚类的最小训练向量数 |
100000 |
[1, 100000000] |
|
|
K-means 聚类迭代次数 |
10 |
[0, 100000] |
查询与调优
参数优先级
Nova 搜索参数可以配置在两个位置:
|
配置方式 |
生效范围 |
有效期 |
|
会话级 GUC |
当前数据库连接中的查询 |
连接断开后失效 |
|
索引级 Reloption |
使用指定索引的查询 |
持续生效,直到重新设置或 RESET |
Reloption 与会话 GUC 的对应关系如下:
|
索引级 Reloption |
对应的会话级 GUC |
适用索引 |
|
|
|
Novam |
|
|
|
Novam |
|
|
|
Novad |
|
|
|
Novam、Novad |
查询时按以下规则取值:
|
索引 Reloption 状态 |
实际使用的参数 |
|
设置了具体值 |
使用索引 Reloption |
|
未设置、已 RESET 或值为 -1 |
使用对应的会话 GUC |
一句话概括:会话级 GUC 是当前连接的默认值;索引级 Reloption 可以为指定索引覆盖这个默认值。
例如,会话 GUC 为 80,某个索引的 Reloption 为 200:
|
查询使用的索引 |
实际使用值 |
|
设置了 Reloption 的索引 |
200 |
|
其他未设置 Reloption 的索引 |
80 |
-1 只表示继承会话 GUC,不是实际搜索值。
会话级查询参数
使用 SET fastann.<参数名> = <值>; 配置当前会话。若索引支持同名 reloption,则只有该 reloption 为 -1 或已 RESET 时才会使用会话值。
Novam 查询参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
HNSW 搜索时的动态候选集大小。最关键的 Novam 调优参数,值越大召回率越高,查询越慢。 |
100 |
[1, 1000] |
|
|
稀疏向量搜索的 ef_search |
200 |
[1, 1000] |
|
|
HNSW 最大扫描点数 |
2000 |
[0, 10000000] |
|
|
量化索引(SQ/RaBitQ)的重排候选集放大倍数 |
1.0 |
[0.0, 1000.0] |
Novad 查询参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
IVF 搜索时探测的聚类列表数。最关键的 Novad 调优参数,值越大召回率越高,I/O 越多。 |
5 |
[1, 100000] |
|
|
加速层查询时的 ef_search |
128 |
[1, 32768] |
|
|
结果堆放大倍数 |
1.0 |
[1.0, 1000.0] |
|
|
RaBitQ 量化的重排放大倍数 |
1.0 |
[0.0, 1000.0] |
通用查询参数
|
参数名 |
说明 |
默认值 |
取值范围 |
|
|
混合查询(向量 + 过滤条件)的 topK 放大倍数 |
10 |
[1, 1000] |
|
|
计算节点 topK 乘数因子。计算节点 topK = topK × mul + add |
1.0 |
[0.0, 1000.0] |
|
|
计算节点 topK 加数因子 |
0.0 |
[0.0, 1000.0] |
索引级查询参数
当某个具体索引需要使用不同于会话默认值的搜索参数时,可为该索引设置 reloptions。其中索引级(reloption)查询参数 = -1 表示使用对应的会话级(GUC)查询参数。
|
Reloption |
适用索引 |
继承的 GUC |
默认值 |
取值范围 |
|
|
Novam |
|
-1 |
-1 或 [1, 1000] |
|
|
Novam |
|
-1 |
-1 或 [0, 10000000] 范围内 500 的整数倍 |
|
|
Novad |
|
-1 |
-1 或 [1, 100000] |
|
|
Novam、Novad |
|
-1 |
-1 或 [0.0, 1000.0] |
|
|
Novam、Novad |
无 |
0 |
0 或 [1, 1000] |
|
|
Novam、Novad |
无 |
0 |
0 或 [0.90, 0.99] |
nova_autotune_topk 和 nova_autotune_recall 必须成对设置,用于记录或切换 Autotune 配置。详细用法请参见Autotune 自动调参。
设置索引级参数
-- 固定 Novam 索引的搜索参数
ALTER INDEX idx_feature_novam_l2 SET (
nova_ef_search = 200,
nova_max_scan_points = 5000
);
-- 固定 Novad 索引的搜索参数
ALTER INDEX idx_feature_novad_cosine SET (
nova_nprobe = 20
);
恢复继承会话 GUC
-- Novam 索引恢复继承会话 GUC
ALTER INDEX idx_feature_novam_l2
RESET (nova_ef_search, nova_max_scan_points);
-- Novad 索引恢复继承会话 GUC
ALTER INDEX idx_feature_novad_cosine
RESET (nova_nprobe);
配置示例
使用索引 reloptions 固定单个索引的搜索参数:
-- 固定 Novam 索引参数
ALTER INDEX idx_feature_novam_l2 SET (
nova_ef_search = 200,
nova_max_scan_points = 5000
);
-- 固定 Novad 索引参数
ALTER INDEX idx_feature_novad_cosine SET (
nova_nprobe = 20
);
reloption 为 -1 或已 RESET 时,查询改用当前会话 GUC:
ALTER INDEX idx_feature_novam_l2
RESET (nova_ef_search, nova_max_scan_points);
SET fastann.hnsw_ef_search = 200;
SET fastann.hnsw_max_scan_points = 5000;
Autotune 自动调参
Autotune 可自动调优 Novam 和 Novad 的搜索参数。只需指定 topK 和目标召回率,系统会自动评估并应用最优参数配置。支持传入真实查询表进行精细调优,也支持基于索引数据生成合成查询。
调优任务异步执行,调用后立即返回 handle。传入多个 topK 或 target_recall 时,系统会评估全部组合。任务完成后,自动将索引的搜索参数设置为最大 topK、最大 target_recall 对应的配置。
启动调优
以下示例同时调优 topK = 10 和 100,目标召回率为 0.99。传入测试查询表 docs_eval_queries,可保证在该查询集上达到目标召回率。每个 topK 和 target_recall 组合分别保存一套配置;任务完成后,索引自动应用最大组合,即 topK = 100、target_recall = 0.99。
SELECT *
FROM fastann.nova_autotune(
index_relation => 'public.docs_embedding_novam_idx'::regclass, -- 必填;无默认值;作用:指定待调优索引
topk => ARRAY[10, 100], -- 必填;无默认值;作用:指定需要调优的 topK
target_recall => 0.99, -- 可选;默认值:0.99;作用:指定目标召回率
n_samples => 100, -- 可选;默认值:300;作用:指定采样查询数
n_trials => 100, -- 可选;默认值:500;作用:指定候选配置试验数
query_table => 'public.docs_eval_queries'::regclass, -- 可选;默认值:NULL;作用:指定测试查询表
query_column => 'embedding' -- 可选;默认值:NULL;作用:指定查询向量列
) AS result(handle);
没有测试查询表时,省略 query_table 和 query_column。系统会根据索引内部数据生成查询并拟合参数:
SELECT *
FROM fastann.nova_autotune(
index_relation => 'public.docs_embedding_novam_idx'::regclass, -- 必填;无默认值;作用:指定待调优索引
topk => ARRAY[10, 100], -- 必填;无默认值;作用:指定需要调优的 topK
target_recall => 0.99, -- 可选;默认值:0.99;作用:指定目标召回率
n_samples => 100, -- 可选;默认值:300;作用:指定采样查询数
n_trials => 100 -- 可选;默认值:500;作用:指定候选配置试验数
) AS result(handle);
示例返回
handle
-----------
123456790
(1 row)
不传入 query_table 时,Autotune 不能保证实际查询的召回率。需要召回率保证时,应传入有代表性的查询表。
查看调优进度
使用 nova_autotune 返回的 handle 查看任务进度:
SELECT
stage,
query_count,
work_done,
work_total,
updated_at
FROM fastann.nova_autotune_progress(
handle => 123456789
);
示例返回
stage | query_count | work_done | work_total | updated_at
------------+-------------+-----------+------------+------------------------
evaluating | 300 | 126 | 500 | 2026-07-28 14:20:42+08
(1 row)
work_done / work_total 表示任务进度百分比。进度函数返回 0 行时,表示任务已结束或 handle 已不在活动状态,不代表调优失败;此时可通过 nova_autotune_status 查看已筛选的配置,并回读索引 Reloption。
手动切换参数配置
Autotune 会保存每组 topK 和 target_recall 对应的参数。查看索引已有的全部调优结果:
SELECT
topk, target_recall, achieved, autotune_recall,
ef_search, max_scan_points, nprobe, rescore_amp, applied
FROM fastann.nova_autotune_status(
index_relation => 'public.docs_embedding_novam_idx'::regclass
)
ORDER BY topk, target_recall;
示例返回
topk | target_recall | achieved | autotune_recall | ef_search | max_scan_points | nprobe | rescore_amp | applied
------+---------------+----------+-----------------+-----------+-----------------+--------+-------------+---------
10 | 0.99 | t | 0.992 | 80 | 3000 | 0 | 1.2 | f
100 | 0.99 | t | 0.991 | 240 | 12000 | 0 | 1.5 | t
(2 rows)
每组 topK 和 target_recall 对应一套参数配置,切换时必须同时指定两者:
-- 使用 topK=10 时达到 99% 召回率的配置
ALTER INDEX public.docs_embedding_novam_idx SET (
nova_autotune_topk = 10,
nova_autotune_recall = 0.99
);
-- 切换到 topK=100 时达到 99% 召回率的配置
ALTER INDEX public.docs_embedding_novam_idx SET (
nova_autotune_topk = 100,
nova_autotune_recall = 0.99
);
一个索引同时只能运行一个 Autotune 任务。
Score Filter
Score Filter 在 ANN 扫描阶段按相似度或距离阈值淘汰候选,减少后续排序和返回的数据量。可通过 GUC 或 SQL Hint 启用。
|
参数名 |
说明 |
默认值 |
|
|
启用或禁用 Score Filter |
禁用 |
|
|
最小 Score 阈值 |
-3.40282e+38 |
|
|
最大 Score 阈值 |
3.40282e+38 |
通过 SET 启用
下面的查询只返回余弦相似度大于 0.75 的 topK 结果:
SET fastann_score_filter_switch = on;
SET fastann_score_filter_min = 0.75;
RESET fastann_score_filter_max;
SELECT id,
chunk,
1 - (
feature <=> ARRAY[0.1, 0.2, ...]::real[]
) AS score
FROM chunks
ORDER BY score
LIMIT 10;
示例返回(以实际数据为准)
SET
SET
RESET
id | chunk | score
----+--------------------+-------
12 | Nova 向量检索 | 0.921
7 | PostgreSQL 检索 | 0.884
(2 rows)
需要限定分数区间时,同时设置上下限:
SET fastann_score_filter_switch = on;
SET fastann_score_filter_min = 0.75;
SET fastann_score_filter_max = 0.95;
通过 SQL Hint 启用
Hint 必须放在一次独立 SQL 调用的最前面,前面不要拼接 SET、RESET 或其他语句。设计上只影响当前语句;使用前请在同一连接中验证当前版本是否会影响后续查询。
/*+ SET(fastann_score_filter_switch on)
SET(fastann_score_filter_min 0.75)
SET(fastann_score_filter_max 0.95) */
SELECT id,
chunk,
1 - (
feature <=> ARRAY[0.1, 0.2, ...]::real[]
) AS score
FROM chunks
ORDER BY score
LIMIT 10;
示例返回(以实际数据为准)
id | chunk | score
----+--------------------+-------
12 | Nova 向量检索 | 0.921
7 | PostgreSQL 检索 | 0.884
(2 rows)
写入与运维
Delta-Base 写入架构
Nova 使用 Delta-Base 架构接收实时写入,将数据写入与主索引构建解耦:
-
新向量先写入内存映射的 Delta 文件,最多同时存在 3 个。
-
每个 Delta 文件最多保存
max_delta_vecs个向量(默认约 100 万)。 -
后台 Flush 线程定期将 Delta 数据合并到主索引。
-
可调用
nova_flush_index()手动触发合并。 -
可调用
nova_delta_stats()查看 Delta 文件状态。
写入反压
当 Delta 文件接近容量上限时,系统自动限制写入速度,防止内存溢出。
|
参数名 |
说明 |
默认值 |
|
|
启用写入反压 |
true |
|
|
软限阈值(Delta 填充比),超过后开始添加延迟 |
0.1 |
|
|
软限最小延迟(毫秒) |
5 |
|
|
软限最大延迟(毫秒) |
15 |
|
|
硬限阈值(Delta 填充比),超过后阻塞写入 |
0.3 |
|
|
硬限最大等待时间(毫秒) |
1000 |
索引统计信息
-- 查看索引统计信息
SELECT nova_stats(
index_oid => 'idx_feature_novamr'::regclass::oid, -- 必填;无默认值;作用:指定 Nova 索引 OID
metadata_only => true -- 可选;默认值:true;作用:是否只返回静态元数据
);
-- 查看 Delta 文件状态
SELECT *
FROM nova_delta_stats(
'idx_feature_novamr'::regclass -- 必填;无默认值;作用:指定要查看的 Nova 索引
);
示例返回(节选,数值以实际索引为准)
nova_stats
--------------------------------------------------
{
"metadata": {
"dimensions": 1536,
"metric_kind": "cosine",
...
}
}
(1 row)
gp_segment_id | index_name | delta_index | vectors | fullness
---------------+-----------------------+-------------+---------+----------
0 | idx_feature_novamr | {0,1} | {120,0} | {0.12,0}
1 | idx_feature_novamr | {0,1} | {98,0} | {0.10,0}
(2 rows)
手动 Flush
手动触发 Delta 数据合并到主索引:
SELECT *
FROM nova_flush_index(
index_relation => 'idx_feature_novamr'::regclass
);
示例返回
gp_segment_id | success
---------------+---------
0 | t
1 | t
(2 rows)
REINDEX
使用标准 PostgreSQL REINDEX 命令重建 Nova 索引:
REINDEX INDEX CONCURRENTLY idx_feature_novamr;
示例返回
REINDEX
兼容性与限制
pgvector 兼容模式
pgvector 兼容模式提供 pgvector 0.8.2 的常用类型、运算符、索引语法和参数名。索引由 Nova 构建和查询,并非原生 pgvector 索引。兼容层与 USING ann 可在同一数据库中并存。
启用兼容模式
当前版本使用 pgvector 兼容模式前,请提交工单申请开通。开通完成后,普通用户即可创建和使用 pgvector 兼容索引。
如需使 <-> 返回与 pgvector 一致的欧氏距离,请在会话中设置 fastann.pgvector_compatibility = on;仅用于 TopK 排序且不读取距离值或按距离过滤时,无需设置。
索引语法与 Nova 后端
可直接使用 pgvector 索引语法,距离度量由运算符类确定:
CREATE INDEX docs_embedding_hnsw_idx
ON docs USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
CREATE INDEX docs_embedding_ivfflat_idx
ON docs USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 1024);
|
pgvector 语法 |
支持的列类型 |
Nova 后端 |
|
|
vector、halfvec |
|
|
|
bit、sparsevec |
|
|
|
vector、halfvec |
维度 ≥ 32 时使用 |
hnsw 和 ivfflat 的算法及距离度量分别由访问方法和运算符类决定。即使同时指定 algorithm 或 distancemeasure,也不会改变上述映射。
支持的运算符类
|
访问方法 |
列类型 |
支持的运算符类 |
|
|
|
vector_l2_ops、vector_ip_ops、vector_cosine_ops |
|
|
|
halfvec_l2_ops、halfvec_ip_ops、halfvec_cosine_ops |
|
|
|
sparsevec_l2_ops、sparsevec_ip_ops |
|
|
|
bit_hamming_ops、bit_jaccard_ops |
|
|
|
vector_l2_ops、vector_ip_ops、vector_cosine_ops |
|
|
|
halfvec_l2_ops、halfvec_ip_ops、halfvec_cosine_ops |
参数映射
|
pgvector 参数 |
Nova 参数 |
默认值 |
说明 |
|
|
|
16 |
HNSW 节点最大邻居数,取值范围 2~100 |
|
|
|
64 |
构建候选集大小,取值范围 4~1000,且不小于 2 × m |
|
|
|
1024 |
IVF 聚类数,取值范围 2~1073741824 |
|
|
|
100 |
两个名称引用同一会话参数,取值范围 1~1000 |
兼容 IVFFlat 查询通过 nova_nprobe 调整搜索范围;未设置时继承 fastann.nova_nprobe,默认值为 5。ivfflat.probes 和 fastann.ivfflat_probes 对该兼容索引不生效。
限制
-
不支持在 Nova 索引上使用 L1 运算符类。创建
vector_l1_ops或halfvec_l1_ops索引会报错。 -
sparsevec的余弦运算符类暂不支持 Nova 索引。余弦检索需要将索引向量和查询向量归一化后按内积搜索,当前 Nova 构建链路尚未接通稀疏向量的归一化处理。请使用 L2 或内积替代。 -
ivfflat仅支持vector和halfvec的 L2、内积和余弦距离。 -
pgvector 语法映射到 Nova 后端,索引结构、量化方式、存储占用、召回率和性能特征与原生 pgvector 不完全相同。
-
svector最多支持 10 亿维,最多包含 4,000 个非零值。indices和values必须包含相同数量的元素。values必须是有限数值,不能包含NaN、Infinity或-Infinity。
使用注意事项
Nova 会在后台执行 Delta 合并和图修复。即使没有业务请求,也可能占用系统资源。在资源规划时请考虑此因素。