Pgvector は、ベクトル類似検索用のオープンソース PostgreSQL 拡張機能です。 pgvector 拡張機能を使用すると、ベクトル インデックスを作成し、ベクトル類似検索、レコメンデーション システム、クラスタリング分析などのシナリオでベクトル間の類似度の計算とクエリを実行できます。
前提条件
AnalyticDB for PostgreSQL V6.0 インスタンスのマイナーバージョンは 6.6.1.0 以降です。 AnalyticDB for PostgreSQL インスタンスのマイナーバージョンを表示する方法については、「インスタンスのマイナーバージョンを表示する」をご参照ください。
AnalyticDB for PostgreSQL V6.0 インスタンスでベクトル検索エンジン最適化機能が有効になっています。 詳細については、「ベクトル検索エンジン最適化を有効または無効にする」をご参照ください。
pgvector 互換ベクトル検索の利点
AnalyticDB for PostgreSQL ベクトル データベースは、pgvector 拡張機能を使用してベクトル検索を実行するベクトル テーブルの読み取りおよび書き込み操作と完全に互換性があります。 インデックスを作成するための SQL 構文のみを変更する必要があります。 ビジネスで pgvector 拡張機能を使用している場合は、ビジネス コードを少し変更した後、ビジネスに pgvector 互換ベクトル検索を適用できます。 pgvector 互換ベクトル検索には、次の利点があります。
pgvector 互換ベクトル検索は、pgvector 拡張機能をインストールする必要なく、ベクトル検索エンジン最適化機能を有効にした後に使用できます。
pgvector 互換ベクトル検索は、pgvector 拡張機能の SQL 構文と完全に互換性があり、pgvector がサポートする言語クライアントを再利用できます。
pgvector 拡張機能はスタンドアロン PostgreSQL データベースに適していますが、pgvector 互換ベクトル検索は分散アーキテクチャを使用してより多くのベクトル データを処理します。
pgvector 互換ベクトル検索は、独自の FastANN ベクトル検索エンジンを使用して、pgvector 拡張機能よりも優れたパフォーマンスを提供します。
pgvector 互換ベクトル検索は、クエリ オプティマイザーとエグゼキューターを使用して、強力なハイブリッド検索機能を備えたハイブリッド実行プランを生成および実行しますが、pgvector 拡張機能はパーティションのみを使用して単純な検索を実行できます。
pgvector 互換ベクトル検索は FLOAT2 タイプを使用してベクトル テーブルを圧縮し、積量子化 (PQ) 機能を提供してベクトル インデックスを圧縮するため、ストレージ コストを削減します。
ベクトル テーブルを作成する
AnalyticDB for PostgreSQL で通常のベクトル テーブルを作成する場合と同じ構文を使用して、pgvector 互換ベクトル テーブルを作成できます。 SMALLINT[]、FLOAT2[]、FLOAT4[] などの配列型のベクトル列を、pgvector 拡張機能でサポートされている VECTOR 型に変更するだけです。 各 pgvector 互換ベクトル テーブルは、複数のベクトル列をサポートしています。
構文
CREATE TABLE [TABLE_NAME]
(
C1 DATATYPE,
C2 DATATYPE,
......,
CN VECTOR(DIM),
PRIMARY KEY(C1 [,C2,...CN])
) DISTRIBUTED BY (C1);CN パラメーターは、VECTOR 型のベクトル列を指定します。 DIM パラメーターは、ベクトルの次元を指定します。
例
FACE_TABLE という名前のベクトル テーブルを作成します。 C1 をプライマリ キーとして指定し、C2 と C3 をベクトル列として指定します。
CREATE TABLE FACE_TABLE (
C1 INT,
C2 VECTOR(512) NOT NULL,
C3 VECTOR(1536) NOT NULL,
C4 TIMESTAMP NOT NULL,
C5 VARCHAR(20) NOT NULL,
PRIMARY KEY (C1)
) DISTRIBUTED BY (C1);ベクトル インデックスを作成する
AnalyticDB for PostgreSQL では、FastANN ベクトル検索エンジンの構文を使用して、pgvector 互換ベクトル テーブルのベクトル インデックスを作成できます。これは、pgvector 拡張機能の構文とは異なります。
構文
CREATE INDEX [INDEX_NAME]
ON [SCHEMA_NAME].[TABLE_NAME]
USING ANN(COLUMN_NAME)
WITH (DIM=<DIMENSION>,
DISTANCEMEASURE=<MEASURE>,
HNSW_M=<M>,
HNSW_EF_CONSTRUCTION=<EF_CONSTURCTION>,
PQ_ENABLE=<PQ_ENABLE>,
PQ_SEGMENTS=<PQ_SEGMENTS>,
PQ_CENTERS=<PQ_CENTERS>,
EXTERNAL_STORAGE=<EXTERNAL_STORAGE>;pgvector 拡張機能でサポートされている VECTOR 型には、すでに次元情報が含まれています。 ベクトル インデックスを作成するときに、DIM パラメーターを指定する必要はありません。 その他のパラメーターについては、「ベクトル インデックスを作成する」をご参照ください。
例
FACE_TABLE ベクトル テーブルのベクトル インデックスを作成します。
-- C2 列に 3 つのタイプのベクトル インデックスを作成します。
CREATE INDEX idx_c2_l2 ON FACE_TABLE USING ann(C2) WITH (distancemeasure=l2, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c2_ip ON FACE_TABLE USING ann(C2) WITH (distancemeasure=ip, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c2_cosine ON FACE_TABLE USING ann(C2) WITH (distancemeasure=cosine, hnsw_m=64, pq_enable=1);
-- C3 列に 3 つのタイプのベクトル インデックスを作成します。
CREATE INDEX idx_c3_l2 ON FACE_TABLE USING ann(C3) WITH (distancemeasure=l2, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c3_ip ON FACE_TABLE USING ann(C3) WITH (distancemeasure=ip, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c3_cosine ON FACE_TABLE USING ann(C3) WITH (distancemeasure=cosine, hnsw_m=64, pq_enable=1);この例では、複数のベクトル列に複数のベクトル インデックスが作成されます。 無効なインデックスを防ぐために、ビジネス要件に基づいてベクトル インデックスを作成する必要があります。
ベクトル データをインポートする
pgvector 拡張機能と同じ構文を使用して、pgvector 互換ベクトル テーブルにベクトル データをインポートできます。 たとえば、次の INSERT 文を実行して、FACE_TABLE テーブルにデータを挿入します。
INSERT INTO FACE_TABLE
values (1, '[1,2,3 ... 512]', '[1,2,3 ... 1536]', '2023-12-29 00:00:00', 'aaa.bbb.ccc/face1.jpg');ベクトル検索
pgvector 拡張機能と同じ構文を使用して、pgvector 互換ベクトル テーブルでベクトル検索を実行できます。
ベクトル検索の再現率に関連するエンジン パラメーターは、AnalyticDB for PostgreSQL ベクトル データベースのパラメーターと同じです。 詳細については、「ベクトル検索を実行する」をご参照ください。 たとえば、次の文を実行して、FACE_TABLE テーブルでベクトル検索を実行します。
-- ユークリッド距離に基づいて完全一致検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY vector_l2_squared_distance(C2, '[1,2,3 ... 512]') LIMIT 10;
-- 内積距離に基づいて完全一致検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY vector_negative_inner_product(C2, '[1,2,3 ... 512]') LIMIT 10;
-- コサイン類似度に基づいて完全一致検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY cosine_distance(C2, '[1,2,3 ... 512]') LIMIT 10;
-- ユークリッド距離に基づいて近似インデックス検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <-> '[1,2,3 ... 512]' LIMIT 10;
-- 内積距離に基づいて近似インデックス検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <#> '[1,2,3 ... 512]' LIMIT 10;
-- コサイン類似度に基づいて近似インデックス検索を実行します。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <=> '[1,2,3 ... 512]' LIMIT 10;FACE_TABLE テーブルの C2 列に、ユークリッド距離、内積距離、およびコサイン類似度に基づいてベクトル インデックスを作成しました。 近似インデックス検索メソッドを使用して、ベクトル インデックスを照合できます。 近似インデックス検索メソッドを使用する場合は、<->、<#>、および <=> 演算子が、対応する距離メトリックを使用して作成されたベクトル インデックスで機能することを確認してください。 演算子がベクトル インデックスで機能しない場合、近似インデックス検索は完全一致検索にダウングレードされます。
ベクトル検索の SQL 最適化
ベクトル距離のスコア値を返したい場合は、次の文を実行してパフォーマンスを向上させることができます。 計算に必要な時間を短縮するには、ベクトル インデックスのソート結果を使用して、ベクトル距離の最終的なスコア値を計算します。 例:
-- ユークリッド距離に基づいてベクトル データを検索します。 SELECT t.C1 as C1, sqrt(t.score) as score FROM (SELECT C1, C2 <-> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t; -- 内積距離に基づいてベクトル データを検索します。 SELECT t.C1 as C1, (-1 * t.score) as score FROM (SELECT C1, C2 <#> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t; -- コサイン類似度に基づいてベクトル データを検索します。 SELECT t.C1 as C1, (1.0 - t.score) as score FROM (SELECT C1, C2 <=> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t;ベクトル検索結果では、スコア値はユークリッド距離の二乗、内積距離、またはコサイン類似度を示します。
スコア範囲に基づいてフィルタリングされた結果を返したい場合は、次の文を実行してパフォーマンスを向上させることができます。 計算に必要な時間を短縮するには、ベクトル インデックスのソート結果を使用して、ベクトル距離の最終的なスコア値を計算します。 例:
-- ユークリッド距離に基づいてベクトル データを検索します。 SELECT t.C1 as C1, sqrt(t.score) as score FROM (SELECT C1, C2 <-> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t WHERE score < 100; -- 内積距離に基づいてベクトル データを検索します。 SELECT t.C1 as C1, (-1 * t.score) as score FROM (SELECT C1, C2 <#> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t WHERE score > 10; -- コサイン類似度に基づいてベクトル データを検索します。 SELECT t.C1 as id, (1.0 - t.score) as score FROM (SELECT C1, C2 <=> '[1,2,3 ... 512]' as score FROM FACE_TABLE ORDER BY score LIMIT topk) t WHERE score > 0.5;
ハイブリッド検索
AnalyticDB for PostgreSQL の通常のベクトル テーブルでハイブリッド検索を実行する場合と同じ構文を使用して、pgvector 互換ベクトル テーブルでハイブリッド検索を実行できます。 詳細については、「ハイブリッド検索を使用する」をご参照ください。 たとえば、次の文を実行して、FACE_TABLE テーブルでハイブリッド検索を実行します。
SELECT C1 FROM FACE_TABLE WHERE
C4 > '2023-10-01 00:00:00' AND C4 < '2024-01-01 00:00:00'
ORDER BY
C2 <-> '[1,2,3 ... 512]'
LIMIT 10;オープンソース コード リポジトリの適応
このセクションでは、簡単な変更を加えることで、pgvector 拡張機能を使用するビジネス アプリケーション コードを AnalyticDB for PostgreSQL ベクトル データベースに適応させる方法について説明します。 この例では、Dify という名前のオープンソース大規模言語モデル (LLM) アプリケーション開発プラットフォームが使用されます。 適応には、次の変更が含まれます。
pgvector 拡張機能のインストールをコメントアウトします。 AnalyticDB for PostgreSQL ベクトル データベースは、pgvector 拡張機能を使用するベクトル テーブルの読み取りおよび書き込み操作と互換性がありますが、pgvector 拡張機能は使用しません。 AnalyticDB for PostgreSQL ベクトル データベースに pgvector 拡張機能をインストールする必要はありません。 AnalyticDB for PostgreSQL ベクトル データベースを作成すると、FastANN ベクトル検索エンジンが自動的にインストールされます。 pgvector 拡張機能のインストールをコメントアウトするだけです。 例:
# コードは api/core/rag/datasource/vdb/pgvector/pgvector.py パスに保存されます。 def _create_collection(self, dimension: int): cache_key = f"vector_indexing_{self._collection_name}" lock_name = f"{cache_key}_lock" WITH redis_client.lock(lock_name, timeout=20): collection_exist_cache_key = f"vector_indexing_{self._collection_name}" if redis_client.get(collection_exist_cache_key): RETURN WITH self._get_cursor() AS cur: # pgvector 拡張機能のインストールをコメントアウトします。 #cur.execute("CREATE EXTENSION IF NOT EXISTS vector") cur.execute(SQL_CREATE_TABLE.format(table_name=self.table_name, dimension=dimension)) # TODO: インデックスを作成する https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing redis_client.set(collection_exist_cache_key, 1, ex=3600)ベクトル テーブルを作成するために使用されるメソッドを変更します。 AnalyticDB for PostgreSQL ベクトル データベースは PostgreSQL 9.4 に基づいて構築されているため、テーブルの作成時に USING heap 構文をサポートしていません。 AnalyticDB for PostgreSQL は分散データベース構造を使用しており、分散キーが必要です。 例:
# コードは api/core/rag/datasource/vdb/pgvector/pgvector.py パスに保存されます。 SQL_CREATE_TABLE = """ CREATE TABLE IF NOT EXISTS {table_name} ( id uuid PRIMARY KEY, text text NOT NULL, meta jsonb NOT NULL, embedding vector({dimension}) NOT NULL ) USING heap; """ # 前のテーブル作成文を次の文に変更します。 SQL_CREATE_TABLE = """ CREATE TABLE IF NOT EXISTS {table_name} ( id uuid PRIMARY KEY, text text NOT NULL, meta jsonb NOT NULL, embedding vector({dimension}) NOT NULL ) DISTRIBUTED BY (id); """ベクトル インデックスを作成するために使用されるメソッドを変更します。 AnalyticDB for PostgreSQL ベクトル データベースは、FastANN ベクトル検索エンジンを使用してベクトル検索を実装しますが、pgvector 拡張機能は使用しません。 AnalyticDB for PostgreSQL でベクトル インデックスを作成するために使用される構文、特にインデックス キーワードは、pgvector 拡張機能で使用される構文とは異なります。 AnalyticDB for PostgreSQL ベクトル データベースの構文を使用してインデックスを作成する必要があります。 例:
# コードは api/core/rag/datasource/vdb/pgvector/pgvector.py パスに保存されます。 # ベクトル インデックスを作成するための SQL 文を追加します。 データベースにインデックスを作成することもできます。 SQL_CREATE_INDEX = """ CREATE INDEX ON {table_name} USING ann(embedding) WITH (HNSW_M=16, HNSW_EF_CONSTRUCTION=500, PQ_ENABLE=1); """ def _create_collection(self, dimension: int): cache_key = f"vector_indexing_{self._collection_name}" lock_name = f"{cache_key}_lock" WITH redis_client.lock(lock_name, timeout=20): collection_exist_cache_key = f"vector_indexing_{self._collection_name}" if redis_client.get(collection_exist_cache_key): RETURN WITH self._get_cursor() AS cur: # pgvector 拡張機能のインストールをコメントアウトします。 #cur.execute("CREATE EXTENSION IF NOT EXISTS vector") cur.execute(SQL_CREATE_TABLE.format(table_name=self.table_name, dimension=dimension)) # TODO: インデックスを作成する https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing # AnalyticDB for PostgreSQL ベクトル データベースのベクトル インデックスを作成します。 cur.execute(SQL_CREATE_INDEX.format(table_name=self.table_name)) redis_client.set(collection_exist_cache_key, 1, ex=3600)
付録
pgvector 拡張機能でサポートされている言語クライアント
プログラミング言語 | クライアント ライブラリ コードの URL |
C | |
C++ | |
Go | |
Java、Kotlin、Groovy、および Scala | |
PHP | |
Python | |
Rust |
pgvector 拡張機能でサポートされている複数の言語クライアントを使用して、AnalyticDB for PostgreSQL ベクトル データベースにアクセスできます。 ベクトル インデックスに関連する SQL 文のみを変更する必要があります。
サポートされているベクトル関数
目的 | ベクトル関数 | 戻り値のデータ型 | 説明 | サポートされているデータ型 |
計算 | l2_distance | DOUBLE PRECISION | 2 つのベクトル間のユークリッド距離の平方根を計算します。 この関数は、2 つのベクトル間の距離を測定するために使用されます。 | VECTOR |
inner_product | DOUBLE PRECISION | 2 つのベクトル間の内積距離を計算します。これは、ベクトル正規化後のコサイン類似度に相当します。 この関数は、ベクトル正規化後のコサイン類似度に代わるものとして使用されます。 | VECTOR | |
cosine_similarity | DOUBLE PRECISION | 2 つのベクトル間のコサイン類似度を計算します。 この関数は、ベクトルの実際の に関係なく、方向に基づいて 2 つのベクトル間の類似度を測定するために使用されます。 コサイン類似度の有効値:-1 ~ 1。 | VECTOR | |
vector_dims | INTEGER | ベクトルの次元を計算します。 | VECTOR | |
vector_norm | DOUBLE PRECISION | ベクトルのノルムを計算します。 | VECTOR | |
vector_add | VECTOR | 2 つのベクトルの合計を計算します。 | VECTOR | |
vector_sub | VECTOR | 2 つのベクトルの差を計算します。 | VECTOR | |
vector_mul | VECTOR | 2 つのベクトルの積を計算します。 | VECTOR | |
vector_angle | DOUBLE PRECISION | 2 つのベクトル間の角度を計算します。 | VECTOR | |
並べ替え | vector_l2_squared_distance | DOUBLE PRECISION | ユークリッド距離の二乗に基づいてベクトルを並べ替えます。 この関数は、ユークリッド距離の平方根に基づく並べ替えメソッドよりも計算量が少ないです。 | VECTOR |
vector_negative_inner_product | DOUBLE PRECISION | 内積距離の負の値に基づいてベクトルを並べ替えます。 この関数は、内積距離に基づいてベクトルを降順に並べ替えるために使用されます。 | VECTOR | |
cosine_distance | DOUBLE PRECISION | コサイン距離に基づいてベクトルを並べ替えます。 この関数は、コサイン類似度に基づいてベクトルを降順に並べ替えるために使用されます。 コサイン距離の有効値:0 ~ 2。 | VECTOR |
ベクトル距離の公式については、「ベクトル インデックスを作成する」をご参照ください。
ベクトル関数の例:
-- ユークリッド距離
SELECT l2_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 内積距離
SELECT inner_product('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- コサイン類似度
SELECT cosine_similarity('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- ベクトルの次元
SELECT vector_dims('[1,1,1,1]'::vector);
-- ベクトルのノルム
SELECT vector_norm('[1,1,1,1]'::vector);
-- ベクトルの合計
SELECT vector_add('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- ベクトルの減算
SELECT vector_sub('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- ベクトルの乗算
SELECT vector_mul('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- ベクトルの角度
SELECT vector_angle('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- ユークリッド距離の二乗
SELECT vector_l2_squared_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 内積距離の負の値
SELECT vector_negative_inner_product('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- コサイン距離
SELECT cosine_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);サポートされているベクトル演算子
演算子 | 計算 | 並べ替え | サポートされているデータ型 |
<-> | 2 つのベクトル間のユークリッド距離の二乗を計算します。 結果は、l2_squared_distance 関数の結果と同じです。 | ユークリッド距離の二乗に基づいてベクトルを昇順に並べ替えます。 | VECTOR |
<#> | 2 つのベクトル間の内積距離の負の値を計算します。 結果は、negative_inner_product_distance 関数の結果と同じです。 | ドット積距離に基づいてベクトルを降順に並べ替えます。 | VECTOR |
<=> | 2 つのベクトル間のコサイン距離を計算します。 結果は、cosine_distance 関数の結果と同じです。 | コサイン類似度に基づいてベクトルを降順に並べ替えます。 | VECTOR |
+ | 2 つのベクトルの合計を計算します。 | なし | VECTOR |
- | 2 つのベクトルの差を計算します。 | なし | VECTOR |
* | 2 つのベクトルの積を計算します。 | なし | VECTOR |
ベクトル演算子の例:
-- ユークリッド距離の二乗
SELECT '[1,1,1,1]'::vector <-> '[2,2,2,2]'::vector AS score;
-- 内積距離の負の値
SELECT '[1,1,1,1]'::vector <#> '[2,2,2,2]'::vector AS score;
-- コサイン距離
SELECT '[1,1,1,1]'::vector <=> '[2,2,2,2]'::vector AS score;
-- 合計
SELECT '[1,1,1,1]'::vector + '[2,2,2,2]'::vector AS value;
-- 減算
SELECT '[1,1,1,1]'::vector - '[2,2,2,2]'::vector AS value;
-- 乗算
SELECT '[1,1,1,1]'::vector * '[2,2,2,2]'::vector AS value;