本トピックでは、ApsaraDB RDS for PostgreSQL インスタンス上で HNSW インデックスを使用した pgvector 拡張の性能ベンチマークを紹介します。このベンチマークでは、ann-benchmarks ツールを使用して、RDS 実装とコミュニティ版の取得率、秒間クエリ数 (QPS)、インデックス構築時間などの主要メトリックを比較評価します。
テスト環境
ネットワークの変動による誤差を避けるため、ご利用の RDS PostgreSQL インスタンスとクライアント ECS インスタンスを同一の Virtual Private Cloud (VPC) および VSwitch 内に配置してください。
|
コンポーネント |
説明 |
|
RDS PostgreSQL インスタンス |
|
|
ECS インスタンス |
|
|
テストツール |
重要
デフォルトでは、ANN-Benchmarks はシングルスレッドの性能をテストします。インスタンスの同時性能をテストするには、「pgvector 性能テスト (IVF インデックスに基づく)」をご参照ください。 |
前提条件
RDS for PostgreSQL インスタンス
-
高権限アカウント
ann_testuserとテストデータベースann_testdbを作成します。詳細については、「アカウントとデータベースの作成」をご参照ください。 -
ann_testdb データベースに pgvector プラグイン (ベクター) をインストールします。詳細については、「プラグインの管理」をご参照ください。
クライアント ECS インスタンス
-
Docker をインストールします。詳細については、「Docker をインストールする」をご参照ください。
-
次のコマンドを実行して、ann-benchmarks ツールをダウンロードします。
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-benchmarks の依存関係をインストールします。
cd ~/ann-benchmarks/ pip install -r requirements.txt
テスト手順
この手順のすべてのステップは ann_test 仮想環境内で実行されます。セッションがタイムアウトまたは何らかの理由で終了した場合は、コマンド conda activate ann_test を使用して環境に再入力してください。
ステップ 1: 接続設定の構成
ベンチマークツール内の ~/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' # 自動サービス起動を無効化
ステップ 2: 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) の 3 つのグループに分かれています。arg_groups は HNSW インデックス作成時のパラメーターを、query_args は取得時のパラメーターをそれぞれ設定します。
|
パラメーター |
説明 |
|
|
arg_groups |
M |
HNSW インデックスの 値を大きくするとグラフの密度が増し、一般に取得率が向上しますが、インデックス構築時間およびクエリ時間が長くなります。 |
|
efConstruction |
HNSW インデックスの 値を大きくすると一般に取得率が向上しますが、インデックス構築時間およびクエリ時間が長くなります。 |
|
|
query_args |
ef_search |
検索処理中に維持されるサンプル候補セットのサイズを指定するクエリ時設定です。 値を大きくすると一般に取得率が向上しますが、クエリ時間が長くなります。 |
ステップ 3: テスト用 Docker イメージのビルド
-
(任意)PostgreSQL のコミュニティ版(デフォルト)のテストをスキップするには、
~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/Dockerfileファイルを次のように変更します。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を実行します。
ステップ 4: データセットの取得
ベンチマークスクリプトは、指定されたパブリックデータセットを自動的にダウンロードします。
本トピックでは、テキスト類似検索の例として Angular 距離タイプを使用する nytimes-256-angular データセットを使用します。その他のパブリックデータセットについては、「ann-benchmarks」をご参照ください。
|
データセット |
ディメンション |
行数 |
テストベクター |
Top-N 近傍 |
距離タイプ |
|
NYTimes |
256 |
290,000 |
10,000 |
100 |
Angular |
パブリックデータセットがテスト要件を満たさない場合は、実際のベクトルデータを HDF5 などの標準フォーマットに変換して取得パフォーマンスをテストすることを推奨します。詳細については、「付録 II: カスタムテストデータセット」をご参照ください。
ステップ 5: テストの実行と結果の取得
-
次のコマンドを使用してベンチマークスクリプトを実行します。
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インデックス構築メトリックおよび同一取得率における性能向上に注目してください。
インデックス構築の比較:
インデックスタイプ
作成時間 (秒)
インデックスサイズ
HNSW コミュニティ版 (v0.8.0)
127.89
7820 MB
HNSW RDS 版 (v0.8.0.1)
77.72
3916 MB
同一取得率における QPS の比較:
再現率
v0.8.0 HNSW パラメーター
v0.8.0.1 HNSW パラメーター
v0.8.0 QPS
v0.8.0.1 QPS
97%
ef_search=10
ef_search=10
1635.41
1954.48
98%
ef_search=30
ef_search=20
1075.49
1379.61
99.3%
ef_search=120
ef_search=80
434.74
737.06
99.5%
ef_search=300
ef_search=350
200.06
319.19
99.6%
ef_search=500
ef_search=500
109.51
177.94
-
(任意)次のコマンドを実行して、詳細なテスト結果を CSV ファイルにエクスポートします。
cd ~/ann-benchmarks python data_export.py --out res.csvたとえば、
m、ef_constructionパラメーターとインデックス構築時間の関係を分析できます。m
ef_construction
構築時間 (秒)
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) を使用しないでください。
付録 I: RDS for PostgreSQL: インデックス構築へのパラメーター影響
この付録では、ann-benchmarks のテスト結果を使用して、RDS for PostgreSQL およびベクトル関連の各種パラメーターがインデックス構築に与える影響を示します。
RDS for PostgreSQL: インデックス構築へのパラメーター影響
たとえば、ann-benchmarks のテストパラメーターが m=16、efConstruction=64 に設定されている場合、RDS for PostgreSQL のパラメーターはインデックス構築に次のように影響します。
-
maintenance_work_mem
このパラメーターは、
VACUUMやCREATE INDEXなどのメンテナンス操作で使用できる最大メモリ量 (KB) を指定します。maintenance_work_memの値がデータセットサイズ未満の場合、値を増やすとインデックス構築時間が短縮されます。ただし、値がデータセットサイズを超えると、それ以上構築時間は短縮されません。たとえば、pg.x8.2xlarge.2c (16 コア、128 GB) タイプの RDS for PostgreSQL インスタンスで、
max_parallel_maintenance_workersパラメーターをデフォルト値の 8 に設定し、nytimes-256-angular データセット (約 324 MB) を使用した場合、maintenance_work_memパラメーターはインデックス構築に次のように影響します。maintenance_work_mem
インデックス構築時間 (秒)
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 コア、128 GB) タイプの RDS for PostgreSQL インスタンスで、
maintenance_work_memパラメーターを 2 GB (2048 MB) に設定し、nytimes-256-angular データセット (約 324 MB) を使用した場合、max_parallel_maintenance_workersパラメーターはインデックス構築に次のように影響します。max_parallel_maintenance_workers
インデックス構築時間 (秒)
1
76.00
2
51.34
4
32.49
8
19.66
12
14.44
16
13.07
24
13.15
ベクトルパラメーターのインデックス構築への影響
RDS for PostgreSQL のパラメーターを maintenance_work_mem=8 GB (8388608 KB)、max_parallel_maintenance_workers=16 に設定した場合、以下のセクションではベクトルパラメーターがインデックス構築に与える影響を示します。
-
ベクトルディメンション
以下のテストでは、GloVe データセット (1,183,514 ベクター) を使用し、ann-benchmarks のテストパラメーターを
m=16、efConstruction=64、ef_search=40に設定しています。結果からベクトルディメンションが大きくなるほど、インデックス構築時間およびクエリ遅延が増加し、取得率および QPS は低下することがわかります。ディメンション
構築時間 (秒)
再現率
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
説明クエリ遅延の 99 パーセンタイルを示します。つまり、99% のクエリリクエストはこの値より短い時間で完了し、残り 1% のみがより長い時間を要します。
-
ベクター数
これらのテストでは、
dbpedia-openai-{n}k-angularデータセットシリーズを使用します。ここでnはベクター数を千単位で表します (100 ~ 1,000)。ann-benchmarks のテストパラメーターをm=48、efConstruction=256、ef_search=200に設定した場合のテスト結果は次のとおりです。結果からベクター数が増加するにつれてインデックス構築時間が非線形的に増加し、取得率および QPS は低下し、クエリ遅延が増加することがわかります。ベクター数
行数 (×10,000)
構築時間 (秒)
再現率
QPS
p99 (ms)
100
10
54.05
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
付録 II: カスタムテストデータセット
以下の例では、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 for PostgreSQL データベースに接続 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 拡張をインストールするか、Alibaba Cloud Model Studio 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}") -
~/ann-benchmarks/ann_benchmarks/datasets.pyファイルのDATASETSセクションにカスタムテストデータセットを登録します。DATASETS: Dict[str, Callable[[str], None]] = { ......, "<custom_dataset>": None, } -
カスタムテストデータセットを
~/ann-benchmarksディレクトリにアップロードします。その後、run.pyテストスクリプトでデータセットを使用できます。