pgvectorは、ApsaraDB RDS for PostgreSQLでサポートされている強力な拡張機能で、ベクトル類似性検索を実行します。 この拡張機能により、システムは新しいデータ型をサポートでき、効率的な方法でベクトル類似性検索を実行できます。
背景情報
ApsaraDB RDS for PostgreSQLはpgvector拡張機能をサポートしています。 拡張機能を使用して、ベクトルデータを保存し、ベクトル類似性検索を実行し、AIサービスの基礎となるデータを強化できます。
pgvector拡張機能には、次の利点があります。
これにより、システムはベクトルデータをサポートできます。 pgvector拡張機能を使用して、ベクトルデータを保存および検索できます。
これは、正確かつ近似の最近傍 (ANN) 検索をサポートする。 これにより、L2ユークリッド距離、コサイン類似度、または内積によって、ベクトル空間内のベクトル間の距離または類似度を計算できます。 Hierarchical Navigable Small World (HNSW) インデックスとIVFFLAT並列インデックスの構築、ベクトルの要素ごとの乗算、L1距離関数、および合計集計をサポートします。
最大16,000次元のベクトルを作成し、最大2,000次元のベクトルのインデックスを作成できます。
用語と実装の原則
埋め込み
埋め込みは、高次元データを低次元空間に変換する技術である。 機械学習および自然言語処理 (NLP) では、埋め込みは、スパース記号またはオブジェクトを連続ベクトルとして表すために使用される一般的な方法です。
NLPでは、単語埋め込みは、実数値ベクトルの形式で単語を表すために使用されるアプローチです。 これにより、コンピュータはテキストベースのコンテンツをよりよく理解できます。 単語埋め込みは、単語のセマンティクスと文法的関係をベクトル空間に変換するために使用されます。
実装の原則
埋め込みは、単語、画像、オーディオコンテンツ、ビデオなどのデータを複数の次元から抽象化し、データをベクトルに変換する手法です。
pgvector拡張機能は、ApsaraDB RDS for PostgreSQLがベクトルデータを保存できるようにするベクトルデータをサポートしています。
pgvector拡張を使用して、格納されたベクトルデータに対して正確なANN検索を実行できます。
RDSインスタンスに3つのオブジェクト (リンゴ、バナナ、猫) を格納し、pgvector拡張機能を使用してオブジェクト間の類似度を計算する必要があるとします。 次の手順を実行します。
埋め込みを使用して、リンゴ、バナナ、および猫のオブジェクトをベクトルに変換します。 次のセクションでは、2次元埋め込みの例を示します。
Apple: embedding [1,1] Banana: embedding [1.2,0.8] Cat: embedding [6,0.4]
RDSインスタンスにベクトルデータを保存します。 詳細は、「例」をご参照ください。
次の図は、2次元空間でのリンゴ、バナナ、および猫のオブジェクトの分布を示しています。
リンゴとバナナはどちらも果物であり、お互いに似ているため、近くにあります。 猫は動物であり、果物から遠く離れています。
果物の属性は、色、原産地、味などの寸法でグループ化できます。 細かい寸法から果物をグループ化すると、より正確な結果を得ることができます。
シナリオ
ベクトルデータを保存します。
ベクトル類似性検索を実行します。
前提条件
RDSインスタンスは次の要件を満たしています。
RDSインスタンスはPostgreSQL 14以降を実行します。
RDSインスタンスのマイナーエンジンバージョンが20230430以降です。
説明RDSインスタンスのメジャーエンジンバージョンのアップグレードまたはマイナーエンジンバージョンの更新方法の詳細については、「ApsaraDB RDS For PostgreSQLインスタンスのメジャーエンジンバージョンのアップグレード」または「ApsaraDB RDS for PostgreSQLインスタンスのマイナーエンジンバージョンの更新」をご参照ください。
拡張機能の管理
エクステンションを作成します。
CREATE EXTENSION IF NOT EXISTS vector;
拡張を削除します。
DROP EXTENSION vector;
拡張機能を更新します。
ALTER EXTENSION vector UPDATE [ TO new_version ]
説明上記のステートメントでは、new_versionパラメーターはpgvector拡張機能のバージョンを示します。 pgvector拡張機能の最新バージョンと関連機能の詳細については、「pgvectorの公式ドキュメント」をご参照ください。
例
このセクションでは、pgvector拡張の使用方法の例を示します。 詳細については、「pgvectorの公式ドキュメント」をご参照ください。
埋め込みを格納するベクトル型のアイテムという名前のテーブルを作成します。
CREATE TABLE items ( id bigserial PRIMARY KEY, item text, embedding vector(2) );
説明前述の説明では、2次元ベクトルが使用される。 pgvector拡張機能を使用すると、最大16,000次元のベクトルを作成できます。
作成したテーブルにベクトルを挿入します。
INSERT INTO items (item, embedding) VALUES ('Apple', '[1,1]'), ('Banana', '[1.2,0.8]'), ('Cat', '[6,0.4]');
コサイン類似演算子 (
<=>
) を使用して、バナナ、リンゴ、および猫のオブジェクト間の類似度を計算します。SELECT item, 1 - (embedding <=> '[1.2, 0.8]') AS cosine_similarity FROM items ORDER BY cosine_similarity DESC;
説明前述のステートメントでは、
cosine_similarity = 1 - cosine_distance
式を使用して類似性を計算しています。 ベクトル間の距離が短いほど、オブジェクトはより類似している。ユークリッド距離演算子 (
<->
) または内積演算子 (<#>
) を使用して類似度を計算することもできます。
サンプル出力:
item | cosine_similarity ------+-------------------- Banana | 1 Apple | 0.980580680748848 Cat | 0.867105556566985
前の出力では:
バナナの値1は、完全一致を示します。
リンゴの値0.98は、リンゴがバナナと高い類似性を有することを示す。
猫の値0.86は、猫がバナナとの類似性が低いことを示します。
説明ビジネス要件に基づいて類似度のしきい値を指定して、類似度の低い結果を除外できます。
pgvector拡張を使用してベクトル類似性検索の効率を向上させるために、ベクトルのインデックスを作成します。 次のステートメントを実行して、埋め込みパラメーターのインデックスを作成できます。
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
下表に、各パラメーターを説明します。
パラメータ /値
説明
items
インデックスが作成されるテーブルの名前。
埋め込み
インデックスが作成される列の名前。
vector_cosine_ops
ベクトルインデックスメソッドで指定されたアクセスモード。
コサイン類似度によるベクトル類似度検索の場合、このパラメーターを
vector_cosine_ops
に設定します。ユークリッド距離によるベクトル類似性検索の場合、このパラメーターを
vector_l2_ops
に設定します。内積によるベクトル類似性検索の場合、このパラメーターを
vector_ip_ops
に設定します。
lists = 100
listsパラメーターは、データセットが分割されるリストの数を示します。 値が大きいほど、データセットがより多くのリストに分割され、各サブセットのサイズが小さく、インデックス検索速度が速いことを示します。 listsパラメータの値が増加するにつれて、検索再呼び出し率は減少し得る。
説明再現率は、情報検索または分類タスクにおける関連サンプルの総数に対する、正確に検索されたサンプルまたは分類されたサンプルの数の比である。 再現率は、全ての関連サンプルを識別するシステムの能力を測定するために使用される測定基準である。
インデックスの作成には、多数のメモリリソースが必要です。 listsパラメーターの値が2000より大きい場合、
ERROR: memory required is xxx MB, maintenance_work_mem is xxx MB
というエラーメッセージが表示されます。 この場合、maintenance_work_memパラメーターの値をより大きな値に変更する必要があります。 しかしながら、過度に大きい値は、メモリ不足 (OOM) エラーを引き起こす可能性がある。 パラメーターの値を変更する方法の詳細については、「ApsaraDB RDS For PostgreSQLインスタンスのパラメーターの変更」をご参照ください。listsパラメーターの値を変更して、検索速度とリコール率のトレードオフを行うことができます。 これにより、特定のシナリオで要件を満たすことができます。
次のいずれかの方法を使用して、ivfflat.probesパラメーターを設定します。 このパラメーターには、インデックスで検索するリストの数を指定します。 より多くのリストを検索し、検索結果の再呼び出し率を向上させるには、ivfflat.probesパラメーターの値を増やすことができます。
セッションレベル
SET ivfflat.probes = 10;
取引レベル
BEGIN; SET LOCAL ivfflat.probes = 10; SELECT ... COMMIT;
ivfflat.probesパラメーターの値が大きい場合、検索結果の再現率は高くなりますが、検索速度は遅くなります。 最適な検索パフォーマンスとリコール率を確保するには、ビジネス要件とデータセットの特性に基づいて、ivfflat.probesおよびlistsパラメーターの値を調整する必要があります。
説明ivfflat.probesパラメーターの値が、インデックスの作成時に指定されたlistsパラメーターの値と同じである場合、ベクトルインデックスは無視され、検索に対して完全なテーブルスキャンが実行されます。 この場合、インデックスは使用されず、テーブル全体がスキャンされます。 これは、検索性能を低下させ得る。
パフォーマンスデータ
ベクトルのインデックスを作成するときは、ビジネス要件に基づいて検索速度とリコール率をトレードオフする必要があります。 以下のテスト結果は、性能最適化の例を示す。
このセクションでは、異なるデータボリュームのベクトルとインデックスによって別々に占有されるストレージについて説明します。 このセクションでは、listsおよびprobesパラメーターの値を調整したときの検索速度とリコール率への影響についても説明します。
テストデータの準備
テストデータベースを作成します。
CREATE DATABASE testdb;
拡張機能をインストールします。
CREATE EXTENSION IF NOT EXISTS vector;
固定長のランダムなベクトルを生成し、テストデータとして使用します。
CREATE OR REPLACE FUNCTION random_array(dim integer) RETURNS DOUBLE PRECISION[] AS $$ SELECT array_agg(random()) FROM generate_series(1, dim); $$ LANGUAGE SQL VOLATILE COST 1;
1,536次元のベクトルを格納できるテーブルを作成します。
CREATE TABLE vtest(id BIGINT, v VECTOR(1536));
テーブルにデータを挿入します。
INSERT INTO vtest SELECT i, random_array(1536)::VECTOR(1536) FROM generate_series(1, 100000) AS i;
インデックスを作成します。
CREATE INDEX ON vtest USING ivfflat(v vector_cosine_ops) WITH(lists = 100);
手順
ネットワーク遅延などの要因によるテストデータへの影響を防ぐため、RDSインスタンスの内部エンドポイントを使用することを推奨します。 この例では、テストは、RDSインスタンスと同じリージョンおよび仮想プライベートクラウド (VPC) にあるElastic Compute Service (ECS) インスタンスで実行されます。
ランダムベクトルを使用して、vtestテーブルのデータ間の類似度を計算し、最も類似した50のレコードを取得します。
その後のストレステストのために、SQLファイルを作成し、次の内容をファイルに書き込む必要があります。
WITH tmp AS ( SELECT random_array(1536)::VECTOR(1536) AS vec ) SELECT id FROM vtest ORDER BY v <=> (SELECT vec FROM tmp) LIMIT FLOOR(RANDOM() * 50);
pgbenchを使用してストレステストを実行します。
pgbenchは、PostgreSQLでベンチマークテストを実行するプログラムです。 CLIで次のコマンドを実行する必要があります。 PostgreSQLクライアントがインストールされていることを確認します。 この例では、PostgreSQL 15.1が使用されます。 詳細は、「PostgreSQL 公式ドキュメント」をご参照ください。
pgbench -f ./test.sql -c6 -T60 -P5 -U testuser -h pgm-bp****.pg.rds.aliyuncs.com -p 5432 -d testdb
下表に、各パラメーターを説明します。
パラメータ /値
説明
-fだ /test.sql
テストスクリプトファイルのパスとファイル名。
. /test.sql
は例です。 ビジネス要件に基づいてパラメーターを変更する必要があります。-c6
同時クライアント接続の数。 -cは、同時クライアント接続の数を示します。 この例では、6は6つの同時クライアント接続をテストに使用できることを示します。
-T60
テスト時間。 -Tは、テストの実行に必要な時間を示します。 この例では、60はテストが60秒間続くことを示します。
-P5
スクリプトパラメーター。 この例では、進捗レポートは5秒ごとに表示されます。
-Uテストユーザー
データベースのユーザー名。 testuserをデータベースのユーザー名に置き換える必要があります。
-h pgm-bp **** .pg.rds.aliyuncs.com
RDSインスタンスの内部エンドポイント。
-p 5432
RDSインスタンスの内部ポート。
-d testdb
接続するデータベース。 この例では、testdbが接続されています。
テスト結果
結論
listsパラメーターの値は、インデックスによって占有されているストレージにわずかな影響を与えます。 占有ストレージは、テーブル内のデータボリュームの影響を受けます。
リストおよびプローブパラメータの値は、検索速度および再現率に対して反対の影響を有する。 2つのパラメータの適切な設定は、検索速度と再呼び出し率との間のトレードオフを行うのに役立つ。
テーブル内のデータ行数に基づいてリストとプローブのパラメーターを設定することをお勧めします。 次のセクションでは、構成設定のサンプルを示します。
テーブル内のデータ行数が1百万以下の場合、次の式を使用してリストおよびプローブパラメーターの値を計算できます。
lists=データ行数 /1,000
およびprobes=リストの値parameter/10
テーブル内のデータ行数が1百万を超える場合は、
lists = sqrt (データ行数)
およびprobes = sqrt (listsパラメーターの値)
を使用して、listsおよびprobesパラメーターの値を計算できます。説明sqrtは平方根関数を示します。