向量分析性能测试
本文介绍云原生数据仓库 AnalyticDB PostgreSQL 版向量分析的性能测试。
测试环境
云原生数据仓库 AnalyticDB PostgreSQL 版实例与客户端ECS应处于同一VPC中,以避免网络波动带来的误差。
AnalyticDB PostgreSQL服务端规格
|
引擎版本 |
基础版(原高性能版)节点规格 |
计算节点数量 |
计算节点存储空间 |
计算节点存储类型 |
|
v6.6.2.5 |
8C32G |
2 |
1000 GB |
ESSD 云盘 PL1 |
客户端ECS规格
|
CPU |
内存 |
磁盘 |
|
16 核 |
32 GB |
2 TB |
准备工作
准备测试环境
-
本地安装3.8及以上版本的Python环境。
-
下载适配云原生数据仓库 AnalyticDB PostgreSQL 版的ann-benchmark测试工具到本地。下载链接,请参见adbpg_ann_benchmark_20250430.tar.gz。
-
执行如下语句,安装测试工具依赖。
pip install -r requirements.txt -
安装20版本以上的Docker。具体操作,请参见Docker官方安装指南。
-
执行以下语句,构建测试镜像。
python install.py --proc 4 --algorithm adbpg
准备测试数据集
下载所需的数据集,将数据集放置于ann-benchmarks项目的data目录下。
|
数据集 |
维度 |
样本数 |
度量函数 |
dataset参数 |
下载地址 |
|
GIST |
960 |
1,000,000 |
L2相似度 |
gist-960-euclidean |
|
|
SIFT-10M |
128 |
10,000,000 |
L2相似度 |
sift-128-euclidean |
|
|
SIFT-100M |
128 |
100,000,000 |
L2相似度 |
sift100m-128-euclidean |
|
|
Deep |
96 |
10,000,000 |
余弦相似度 |
deep-image-96-angular |
|
|
Cohere |
768 |
1,000,000 |
L2相似度 |
cohere-768-euclidean |
|
|
Dbpedia |
1536 |
1,000,000 |
余弦相似度 |
dbpedia-openai-1000k-angular |
测试流程
步骤一:配置测试工具连接信息
编辑测试工具中ann_benchmarks/algorithms/adbpg/module.py文件,根据实际情况填写配置信息:
# AnalyticDB PostgreSQL实例的内网地址。
self._host = 'gp-bp10ofhzg2z****-master.gpdb.rds.aliyuncs.com'
# AnalyticDB PostgreSQL实例的端口号。
self._port = 5432
# AnalyticDB PostgreSQL实例的数据库名称。
self._dbname = '<database_name>'
# AnalyticDB PostgreSQL实例的账号。
self._user = '<user_name>'
# AnalyticDB PostgreSQL实例的账号密码。
self._password = '<YOUR_PASSWORD>'
步骤二:配置测试参数
根据测试数据集,编辑测试工具中ann_benchmarks/algorithms/adbpg/config.yml文件。
float:
any:
- base_args: ['@metric']
constructor: ADBPG
disabled: false
docker_tag: ann-benchmarks-adbpg
module: ann_benchmarks.algorithms.adbpg
name: adbpg
run_groups:
nopq_mmap:
arg_groups: [{M: 64, efConstruction: 600, parallel_build: 8, external_storage: 1, pq_enable: 0, pq_segments: 120}]
query_args: [[ {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 1},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 5},
{ef_search: 400, max_scan_points: 3200, pq_amp: 10, parallel: 10},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 15},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 20},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 25},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 30},
{ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 50}]]
arg_groups:创建索引的相关参数。如何创建向量索引,请参见创建HNSW向量索引。
|
参数名 |
说明 |
|
M |
HNSW索引的M值参数。M越大,构建越慢,构建精度越高。 |
|
efConstruction |
HNSW索引用于控制搜索质量。 |
|
parallel_build |
构建索引的并行度,一般设置为计算节点的CPU数量。 |
|
external_storage |
设置缓存索引方式,取值说明:
重要 仅6.0版本支持参数external_storage。7.0版本暂不支持。 |
|
pq_enable |
是否开启PQ,取值说明:
|
|
pq_segments |
PQ切分的segment数量,一般取向量维度 |
query_args:检索相关参数。
|
参数名 |
说明 |
|
ef_search |
HNSW索引中控制搜索过程候选最近邻数量。 |
|
max_scan_points |
控制索引最多检索的样本数。 |
|
pq_amp |
开启PQ时的检索放大系数,在非PQ时不起作用。 |
|
parallel |
检索的并发数,仅在Batch模式中生效。 |
在测试过程中,需要对上述参数进行微调,以保证95%的召回率。对于上述的测试数据集,云原生数据仓库 AnalyticDB PostgreSQL 版提供以下配置供参考,可根据相应的数据集选取对应的参数配置。
# for gist 960
float:
any:
- base_args: ['@metric']
constructor: ADBPG
disabled: false
docker_tag: ann-benchmarks-adbpg
module: ann_benchmarks.algorithms.adbpg
name: adbpg
run_groups:
nopq_mmap:
arg_groups: [{M: 64, efConstruction: 600, parallel_build: 8, external_storage: 1, pq_enable: 0, pq_segments: 120}]
query_args: [[ {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 1}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 5}, {ef_search: 400, max_scan_points: 3200, pq_amp: 10, parallel: 10}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 15}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 20}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 25}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 30}, {ef_search: 100, max_scan_points: 3200, pq_amp: 10, parallel: 50}]]
# for deep 96
float:
any:
- base_args: ['@metric']
constructor: ADBPG
disabled: false
docker_tag: ann-benchmarks-adbpg
module: ann_benchmarks.algorithms.adbpg
name: adbpg
run_groups:
nopq_mmap:
arg_groups: [{M: 64, efConstruction: 600, parallel_build: 8, external_storage: 1, pq_enable: 0, pq_segments: 12}]
query_args: [[ {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 1}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 5}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 10}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 15}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 20}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 25}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 30}, {ef_search: 400, max_scan_points: 1500, pq_amp: 10, parallel: 50}]]
# for cohere 768
float:
any:
- base_args: ['@metric']
constructor: ADBPG
disabled: false
docker_tag: ann-benchmarks-adbpg
module: ann_benchmarks.algorithms.adbpg
name: adbpg
run_groups:
nopq_mmap:
arg_groups: [{M: 64, efConstruction: 600, parallel_build: 8, external_storage: 1, pq_enable: 0, pq_segments: 96}]
query_args: [[ {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 1}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 5}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 10}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 15}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 20}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 25}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 30}, {ef_search: 400, max_scan_points: 600, pq_amp: 10, parallel: 50}]]
# for dbpedia 1536
float:
any:
- base_args: ['@metric']
constructor: ADBPG
disabled: false
docker_tag: ann-benchmarks-adbpg
module: ann_benchmarks.algorithms.adbpg
name: adbpg
run_groups:
nopq_mmap:
arg_groups: [{M: 64, efConstruction: 600, parallel_build: 8, external_storage: 1, pq_enable: 0, pq_segments: 192}]
query_args: [[ {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 1}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 5}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 10}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 15}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 20}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 25}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 30}, {ef_search: 400, max_scan_points: 425, pq_amp: 10, parallel: 50}]]
步骤三:测试检索召回率
完成上述参数配置后,执行以下命令进行召回率测试:
nohup python run.py --algorithm adbpg --dataset <数据集> --runs 1 --timeout 990000
> annbenchmark_deep.log 2>&1 &
dataset:需要替换为具体测试数据集。
等待测试结束后,执行以下命令以查看召回率结果:
python plot.py --dataset <数据集> --recompute
输出结果示例:
0: ADBPG(m=64, ef_construction=600, ef_search=400, max_scan_point=500, pq_amp=10) recall: 0.963 qps: 126.200
1: ADBPG(m=64, ef_construction=600, ef_search=400, max_scan_point=1000, pq_amp=10) recall: 0.992 qps: 122.665
检查召回率是否符合预期,若不符合,需要调节参数并重新执行测试。
步骤四:测试检索性能
在完成召回率调整后,即可进行性能测试,方法与召回率测试类似,但在此环节中,需要打开Batch模式,以检测并发性能:
nohup python run.py --algorithm adbpg --dataset <数据集> --runs 1 --timeout 990000 --
batch > annbenchmark_deep.log 2>&1 &
等待测试运行结束,查看输出文件annbenchmark_deep.log,可以查看不同并发下的QPS、平均RT及P99 RT表现:
2023-12-20 17:31:39,297 - INFO - query using 25 parallel
worker 0 cost 9.50 s, qps 315.92, mean rt 0.00317, p99 rt 0.00951
2023-12-20 17:31:49,097 - INFO - QPS: 7653.155
2023-12-20 17:31:49,113 - INFO - query using 30 parallel
worker 0 cost 13.87 s, qps 216.36, mean rt 0.00462, p99 rt 0.04298
2023-12-20 17:32:03,260 - INFO - QPS: 6361.819
2023-12-20 17:32:03,281 - INFO - query using 50 parallel
worker 0 cost 20.78 s, qps 144.36, mean rt 0.00693, p99 rt 0.02735
2023-12-20 17:32:24,385 - INFO - QPS: 7107.920
测试结果
下文提供了不同数据集在不同向量数据库配置,不同索引构建模式下的性能表现结果,所有测试的召回率调节为大于或等于95%,测试过程中检索统一取Top10。其中不同索引构建模式说明如下:
|
索引构建模式 |
说明 |
适用场景 |
|
PQ + mmap |
采用mmap向量索引的缓存与持久化存储,并且使用PQ量化方式压缩向量编码和加速向量计算。 |
1. 数据量大于100w。 2. 更新删除占比较小。 3. 内存资源不足以完全缓存所有向量。 4. 性能要求中等。 |
|
noPQ + mmap |
采用mmap做向量索引的缓存与持久化存储,不使用PQ量化压缩向量编码和加速向量计算。 |
1. 更新删除占比较小 。 2. 内存资源足以完全缓存所有向量和索引。 3. 性能要求最好。 |
|
PQ + shared_buffer |
采用PostgreSQL原生的shared_buffer机制进行向量索引的缓存,并且使用PQ量化方式压缩向量编码和加速向量计算。 |
1. 数据量大于100w。 2. 存在大量的删除更新操作。 3. 内存资源不足以存储所有向量。 4. 性能要求中等。 |
|
noPQ + shared_buffer |
采用PostgreSQL原生的shared_buffer机制进行向量索引的缓存,不进行PQ量化压缩向量编码和加速向量计算。 |
1. 数据量小于100w。 2. 内存资源足够存储所有向量和索引。 3. 更新删除占比非常多。 4. 性能要求中等。 |
实例规格:8C32G * 2 segment
数据集:GIST L2 (960 * 100w)
索引构建模式:noPQ + mmap
-
建索引参数:
-
M: 64
-
efConstruction: 600
-
parallel_build: 8
-
external_storage: 1
-
pq_enable: 0
-
-
搜索参数:
-
ef_search: 100
-
max_scan_points: 3200
-
-
测试结果:
索引构建时间(s)
查询并发
QPS
mean RT (ms)
P99 RT (ms)
485
1
396
1
2
5
1744
2
3
10
3073
2
4
15
3358
3
10
20
3511
5
15
25
3601
6
21
30
3689
7
25
50
3823
12
36
数据集:Deep IP (96 * 1000w)
索引构建模式:noPQ + mmap
-
建索引参数:
-
M: 64
-
efConstruction: 600
-
parallel_build: 8
-
external_storage: 1
-
pq_enable: 0
-
-
搜索参数:
-
ef_search: 400
-
max_scan_points: 1500
-
-
测试结果:
索引构建时间(s)
查询并发
qps
mean rt (ms)
p99 rt (ms)
1778s
1
878
1
2
5
4344
1
2
10
7950
1
3
15
10114
1
4
20
10629
1
5
25
10858
2
7
30
11093
2
9
50
11354
4
16
数据集:cohere L2 (768 * 100w)
索引构建模式:noPQ + mmap
-
建索引参数:
-
M: 64
-
efConstruction: 600
-
parallel_build: 8
-
external_storage: 1
-
pq_enable: 0
-
-
搜索参数:
-
ef_search: 400
-
max_scan_points: 600
-
-
测试结果:
索引构建时间(s)
查询并发
qps
mean rt (ms)
p99 rt (ms)
465s
1
561
1
2
5
2893
1
2
10
5108
1
3
15
5488
2
5
20
5969
2
8
25
6195
3
12
30
6098
4
19
50
6138
7
39
数据集:Dbpedia IP (1536 * 100w)
索引构建模式:noPQ + mmap
-
建索引参数:
-
M: 64
-
efConstruction: 600
-
parallel_build: 8
-
external_storage: 1
-
pq_enable: 0
-
-
搜索参数:
-
ef_search: 400
-
max_scan_points: 425
-
-
测试结果:
索引构建时间(s)
查询并发
qps
mean rt (ms)
p99 rt (ms)
807s
1
453
1
2
5
1948
1
3
10
2820
2
4
15
2903
4
11
20
2860
6
19
25
2897
7
27
30
2880
9
34
50
2877
16
63