本文介绍RDS PostgreSQL实例pgvector插件基于HNSW索引的性能测试,使用ann-benchmarks工具进行评估,涵盖了召回率、QPS、索引构建时间等关键指标。
测试环境
RDS PostgreSQL实例与客户端ECS应位于同一VPC和交换机,以避免网络波动带来的误差。
测试实例及工具 | 说明 |
RDS PostgreSQL实例规格 |
|
客户端ECS规格 |
|
测试工具 | 重要 ann-benchmarks默认测试单线程性能。如需测试实例的并发性能,请参见pgvector性能测试(基于IVF索引)。 |
准备工作
RDS PostgreSQL实例侧
客户端ECS侧
安装Docker,详情请参见安装Docker。
执行如下命令,下载ann-benchmark测试工具。
cd ~ git clone https://github.com/erikbern/ann-benchmarks.git
执行如下命令,使用Conda创建并激活一个虚拟环境ann_test,同时在该环境中安装Python 3.10.6。
yum install git yum install conda conda create -n ann_test python=3.10.6 conda init bash source /usr/etc/profile.d/conda.sh conda activate ann_test
执行如下命令,安装测试ann-benchmark测试工具的依赖。
cd ~/ann-benchmarks/ pip install -r requirements.txt
测试流程
测试流程中的所有步骤均在虚拟环境ann_test中进行。如果因超时或其他原因退出,请使用命令conda activate ann_test
重新进入该环境。
步骤一:配置测试工具连接信息
编辑测试工具中的~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/module.py
文件,增加如下的连接配置,并根据实际情况填写配置信息。
# 设置 PostgreSQL 的连接参数
os.environ['ANN_BENCHMARKS_PG_USER'] = 'ann_testuser' # RDS PostgreSQL实例的账号
os.environ['ANN_BENCHMARKS_PG_PASSWORD'] = 'testPawword' # RDS PostgreSQL实例账号的密码
os.environ['ANN_BENCHMARKS_PG_DBNAME'] = 'ann_testdb' # RDS PostgreSQL实例的数据库名称
os.environ['ANN_BENCHMARKS_PG_HOST'] = 'pgm-****.pg.rds.aliyuncs.com' # RDS PostgreSQL实例的内网地址
os.environ['ANN_BENCHMARKS_PG_PORT'] = '5432' # RDS PostgreSQL实例的内网端口号
os.environ['ANN_BENCHMARKS_PG_START_SERVICE'] = 'false' # 禁用自动启动服务
步骤二:配置ann-benchmarks的测试参数
根据实际测试需要,编辑测试工具中的~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/config.yml
文件。例如:
float:
any:
- base_args: ['@metric']
constructor: PGVector
disabled: false
docker_tag: ann-benchmarks-pgvector
module: ann_benchmarks.algorithms.pgvector
name: pgvector
run_groups:
M-16(100):
arg_groups: [{M: 16, efConstruction: 100}]
args: {}
query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]
M-16(200):
arg_groups: [{M: 16, efConstruction: 200}]
args: {}
query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]
M-24(200):
arg_groups: [{M: 24, efConstruction: 200}]
args: {}
query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]
本测试分为M-16(100)、M-16(200)和M-24(200)三组。每一组测试使用arg_groups
配置创建HNSW索引的相关参数;使用query_args
配置检索相关参数。
参数 | 说明 | |
arg_groups | M | 对应HNSW索引中的参数m,表示构建HNSW索引时,每层中每个节点的最大邻近节点数目。 该值越大,图的稠密度越高,通常会导致召回率的提高,同时构建和查询所需的时间也相应增加。 |
efConstruction | 对应HNSW索引中的参数ef_construction,表示构建HNSW索引时,候选集的大小,即搜索在构建过程中保留多少候选节点用于选择最优连接。 该值越大,通常召回率也越高,但构建和查询所需的时间也相应增加。 | |
query_args | ef_search | 查询阶段设置,表示搜索过程中维护候选集的大小。 该值越大,通常召回率越高,但查询时间也会相应增加。 |
步骤三:构建测试docker镜像
(可选)将测试工具中的
~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/Dockerfile
文件内容改为如下所示,以跳过对工具默认配置的社区版PostgreSQL的测试。FROM ann-benchmarks USER root RUN pip install psycopg[binary] pgvector
指定参数
--algorithm pgvector
来执行install.py,构建测试docker。cd ~/ann-benchmarks/ python install.py --algorithm pgvector
说明您可以执行
python install.py --help
查看支持配置参数。
步骤四:获取数据集
执行测试脚本时,将自动下载指定的公开测试数据集。
本文以文本相似性检索为例,采用Angular距离类型的数据集nytimes-256-angular进行测试。更多公开的数据集请参见ann-benchmarks。
数据集 | 维度 | 数据行数 | 测试向量数 | 最近邻Top N | 距离类型 |
NYTimes | 256 | 290,000 | 10,000 | 100 | Angular |
如果公开数据集无法满足测试需求,建议将实际的向量数据转换为标准格式HDF5或其他标准格式,以用于测试检索性能。详情请参见附录二:自定义测试数据集。
步骤五:进行测试并获取测试结果
执行如下命令,运行测试脚本进行测试。
cd ~/ann-benchmarks nohup python run.py --dataset nytimes-256-angular -k 10 --algorithm pgvector --runs 1 > ann_benchmark_test.log 2>&1 & tail -f ann_benchmark_test.log
参数
含义
--dataset
指定要测试的数据集。
--k
查询SQL的LIMIT值,即返回的结果数量。
--algorithm
被测试的向量数据库算法,此处指定为pgvector。
--runs
测试的运行次数,将从中选取最佳结果集。
--parallelism
并发数,默认为1。
执行如下命令,获取测试结果。
cd ~/ann-benchmarks python plot.py --dataset nytimes-256-angular --recompute
测试结果如下:
m
ef_construction
ef_search
召回率
QPS
16
100
10
0.630
1423.985
20
0.741
1131.941
40
0.820
836.017
80
0.871
574.733
120
0.894
440.076
200
0.918
297.267
400
0.945
162.759
800
0.969
84.268
16
200
10
0.683
1299.667
20
0.781
1094.968
40
0.849
790.838
80
0.895
533.826
120
0.914
405.975
200
0.933
272.591
400
0.956
148.688
800
0.977
76.555
24
200
10
0.767
1182.747
20
0.840
922.770
40
0.887
639.899
80
0.920
411.140
120
0.936
303.323
200
0.953
199.752
400
0.973
105.506
800
0.988
53.904
(可选)执行如下命令,获取详细的测试结果,包括召回率、QPS、响应时间、索引构建时间和索引大小等指标的结果。
cd ~/ann-benchmarks python data_export.py --out res.csv
例如,可以获取参数
m
、ef_construction
和索引构建时间之间的关系:m
ef_construction
build(索引构建时间,单位:s)
16
100
33.35161
16
200
57.66014
24
200
87.22608
测试结论
在构建HNSW索引时:
增加
m
、ef_construction
和ef_search
可以提高召回率,但会导致QPS降低。增加
m
和ef_construction
同样会提高召回率,同时也会导致QPS降低,并延长索引构建时间。如果对召回率的要求较高,不建议使用默认的索引参数(m=16、ef_construction=64和ef_search=40)。
附录一:RDS PostgreSQL参数、向量参数对索引构建的影响
在不同ann-benchmarks的测试参数下,通过对测试结果的分析,可以确定RDS PostgreSQL参数及向量参数对索引构建的影响。
RDS PostgreSQL参数对索引构建的影响
例如,当ann-benchmarks的测试参数设置为m=16和efConstruction=64时,RDS PostgreSQL参数对索引构建的影响如下。
maintenance_work_mem
用于维护操作的最大内存,包括VACUUM、CREATE INDEX等操作,单位为KB。当maintenance_work_mem值小于测试数据大小时,增大该值会缩短索引构建时间;然而,当maintenance_work_mem值超过数据大小后,索引构建时间将不再减少。
以pg.x8.2xlarge.2c(16核 128GB)规格的RDS PostgreSQL为例,实例参数max_parallel_maintenance_workers设置为默认值8,nytimes-256-angular数据集数据量约324MB,maintenance_work_mem参数对索引构建的影响:
maintenance_work_mem
索引构建时间(s)
64 MB(65536 KB)
52.82
128 MB(131072 KB)
46.79
256 MB(262144 KB)
36.40
512 MB(524288 KB)
18.90
1 GB(1048576 KB)
19.06
max_parallel_maintenance_workers
设置CREATE INDEX并行工作的最大数量。索引构建时间随max_parallel_maintenance_workers增加而减少。
以pg.x8.2xlarge.2c(16核 128GB)规格的RDS PostgreSQL为例,实例参数maintenance_work_mem设置为默认值2048(即2 GB),nytimes-256-angular数据集数据量约324 MB,max_parallel_maintenance_workers参数对索引构建的影响:
max_parallel_maintenance_workers
索引构建时间(s)
1
76.00
2
51.34
4
32.49
8
19.66
12
14.44
16
13.07
24
13.15
向量参数对索引构建的影响
例如,当RDS PostgreSQL参数设置为maintenance_work_mem=8 GB(8388608 KB)和max_parallel_maintenance_workers=16时,RDS PostgreSQL参数对索引构建的影响如下。
向量维度
使用GloVe数据集,行数固定为1183514。ann-benchmarks的测试参数设置为m=16、efConstruction=64和ef_search=40时,测试结果如下。根据测试结果可以得出,索引构建时间随着向量维度的增加而相应增加;同时,召回率和QPS均呈下降趋势,查询延迟则有所增加。
维度
构建时间(s)
召回率
QPS
p99(ms)
25
195.10
0.99985
192.94
7.84
50
236.92
0.99647
152.36
9.69
100
319.36
0.97231
126.89
11.14
200
529.33
0.93186
95.05
15.11
说明p99:将所有查询请求的响应时间按升序排序后,位于第99百分位位置的延迟值。即表示在所有查询请求中,99%的请求响应时间低于此值,也就是说,只有1%的请求响应时间超过这个值。
向量行数
使用dbpedia-openai-{n}k-angular数据集,向量行数(n)支持范围为100至1000。ann-benchmarks的测试参数设置为m=48、efConstruction=256和ef_search=200时,测试结果如下。根据测试结果可以得出,索引构建时间随向量行数的增加呈现出非线性增长趋势;同时,召回率和QPS均有所下降,查询延迟也随之增加。
向量行数
行数(万)
构建时间(s)
召回率
QPS
p99(ms)
100
10
54.05s
0.9993
171.74
8.93
200
20
137.23
0.99901
146.78
10.81
500
50
436.68
0.999
118.55
13.94
1000
100
957.26
0.99879
101.60
16.35
附录二:自定义测试数据集
如下数据集制作参考nytimes-256-angular数据格式,仅供参考。
执行如下命令,制作自定义数据集。
说明本示例中需要安装rds_ai插件,详情请参见AI(rds_ai)。
import h5py import numpy as np import psycopg2 import pgvector.psycopg2 # 假设 conn_info = { 'host': 'pgm-****.rds.aliyuncs.com', 'user': 'ann_testuser', 'password': '****', 'port': '5432', 'dbname': 'ann_testdb' } embedding_len = 1024 distance_top_n = 100 query_batch_size = 100 try: # 连接rds pg数据库 with psycopg2.connect(**conn_info) as connection: pgvector.psycopg2.register_vector(connection) with connection.cursor() as cur: # 获取向量数据 cur.execute("select count(1) from test_rag") count = cur.fetchone()[0] train_embeddings = [] for start in range(0, count, query_batch_size): query = f"SELECT embedding FROM test_rag ORDER BY id OFFSET {start} LIMIT {query_batch_size}" cur.execute(query) res = [embedding[0] for embedding in cur.fetchall()] train_embeddings.extend(res) train = np.array(train_embeddings) # 获取查询数据并计算嵌入 with open('query.txt', 'r', encoding='utf-8') as file: queries = [query.strip() for query in file] test = [] # 安装rds_ai插件或者使用百炼SDK for query in queries: cur.execute(f"SELECT rds_ai.embed('{query.strip()}')::vector(1024)") test.extend([cur.fetchone()[0]]) test = np.array(test) # 计算最近Top n距离 dot_product = np.dot(test, train.T) norm_test = np.linalg.norm(test, axis=1, keepdims=True) norm_train = np.linalg.norm(train, axis=1, keepdims=True) similarity = dot_product / (norm_test * norm_train.T) distance_matrix = 1 - similarity neighbors = np.argsort(distance_matrix, axis=1)[:, :distance_top_n] distances = np.take_along_axis(distance_matrix, neighbors, axis=1) with h5py.File('custom_dataset.hdf5', 'w') as f: f.create_dataset('distances', data=distances) f.create_dataset('neighbors', data=neighbors) f.create_dataset('test', data=test) f.create_dataset('train', data=train) f.attrs.update({ "type": "dense", "distance": "angular", "dimension": embedding_len, "point_type": "float" }) print("HDF5 文件创建成功,并已添加数据集。") except (Exception, psycopg2.DatabaseError) as error: print(f"Error: {error}")
在
~/ann-benchmarks/ann_benchmarks/datasets.py
文件的DATASETS
部分中,增加自定义数据集。DATASETS: Dict[str, Callable[[str], None]] = { ......, "<custom_dataset>": None, }
将自定义数据集上传至
~/ann-benchmarks
目录下,运行测试脚本run.py
时,即可使用。