ほとんどの要素がゼロであるベクターを効率的に格納する場合、密ベクターテーブルの代わりにスパースベクターテーブルを作成して、ストレージ容量を削減できます。 このトピックでは、AnalyticDB for PostgreSQL ベクトルデータベースでスパースベクターを使用する方法について説明します。 スパースベクターテーブルの作成、スパースベクターインデックスの作成、スパースベクターを使用した検索の実行、およびスパースベクターと密ベクターを使用したハイブリッド検索の実行を行うことができます。
背景情報
ほとんどの場合、ベクターはベクトルデータベース内で密ベクターとスパースベクターに分類されます。 スパースベクターには、多数のゼロ値が含まれています。 数万のディメンションのうち、ゼロ以外の値を持つディメンションはごくわずかです。 スパースベクターを使用して、テキストや画像など、さまざまな種類のデータを指定できます。 キーワードベースの検索を実行する場合、各スパースベクターはドキュメントを表し、各ディメンションは辞書内のキーワードを指定し、各ディメンション値はキーワードの重要度を指定します。 BM25 アルゴリズムを使用してスパースベクターを生成する場合、ディメンション値には、キーワード一致数、キーワード出現頻度、およびその他のテキスト関連性係数が含まれます。 通常の配列やリストと比較して、スパースベクターは高次元データを効率的に格納および処理でき、ストレージ容量と計算リソースの使用量を大幅に削減できます。 スパースベクターのデータ構造は、スパース特徴シナリオに適しており、機械学習と自然言語処理を実装できます。
次の図は、密ベクターとスパースベクターの違いを示しています。

前提条件
V6.6.2.3 以降の AnalyticDB for PostgreSQL インスタンスが作成されていること。 詳細については、「インスタンスの作成」をご参照ください。
AnalyticDB for PostgreSQL インスタンスでベクトル検索エンジン最適化機能が有効になっていること。 詳細については、「ベクトル検索エンジン最適化の有効化または無効化」をご参照ください。
スパースベクターを使用する
スパースベクターテーブルを作成する
構文
CREATE TABLE <SparseVectorTable>
(
id int PRIMARY KEY,
description text,
...,
sparse_vector svector(MAX_DIM),
)DISTRIBUTED BY (id);パラメーター:
SparseVectorTable: スパースベクターテーブルの名前。
sparse_vector: スパースベクター列の名前。 列の値は SVECTOR 型です。
MAX_DIM: スパースベクターディメンションの最大数。これは、ゼロ以外の値を含むディメンションの数ではありません。
例
svector_test という名前のスパースベクターテーブルを作成します。
-- スパースベクター列を含むテーブルを作成します。
CREATE TABLE <svector_test>(
id bigint,
type int,
tag varchar(10),
document text,
sparse_features svector(250000)
) DISTRIBUTED BY (id);
-- スパースベクター列のストレージモードを PLAIN に設定します。
ALTER TABLE <svector_test> ALTER COLUMN sparse_features SET storage plain;PLAIN モード: PostgreSQL は、The Oversized-Attribute Storage Technique (TOAST) を使用して、大きなオブジェクト、大きなフィールド値、または通常のデータページに収まらないデータを格納します。 TOAST は、データの効率的な格納とアクセスを容易にします。 列のストレージモードを PLAIN に設定すると、列内のデータは圧縮または分割されません。 データは単一の行内に格納され、TOAST テーブルには移動されません。 ほとんどの場合、PLAIN ストレージモードは、TOAST による追加のオーバーヘッドを防ぐために、小さなフィールド値を処理するために使用されます。 また、PLAIN ストレージモードを使用して、整数や小さなテキストフィールドなど、効率的なストレージをサポートするデータ型を処理することもできます。
スパースベクターインデックスを作成する
構文
スパースベクターインデックスは、内積距離メトリックのみをサポートします。 スパースベクターインデックスは、積量子化 (PQ) 機能またはメモリマッピングテクノロジーをサポートしていません。 構文:
CREATE INDEX <idx_sparse_vector>
ON MyTable USING vector_index (sparse_vector_column);
WITH (DISTANCEMEASURE=IP,
HNSW_M=$M,
HNSW_EF_CONSTRUCTION=$EF_CONSTURCTION);パラメーター:
idx_sparse_vector: スパースベクターインデックスの名前。
DISTANCEMEASURE: 距離メトリックの名前。 エラーを防ぐために、値を IP に設定します。
HNSW_M および HNSW_EF_CONSTRUCTION: パラメーターの詳細については、「ベクトルインデックスの作成」をご参照ください。
例
この例では、svector_test スパースベクターテーブルを使用して、スパースベクターインデックスを作成します。
-- ハイブリッド検索の構造化フィールドに B ツリーインデックスを作成します。 構造化フィールドが ARRAY 型の場合、フィールドに汎用転置インデックス (GIN) インデックスを作成することもできます。
CREATE INDEX svector_test(type);
CREATE INDEX svector_test(tag);
-- スパースベクター列に階層型ナビゲーション可能な小規模ワールド (HNSW) インデックスを作成します。
CREATE INDEX ON svector_test USING ANN(sparse_features) WITH(DISTANCEMEASURE=IP,HNSW_M=64,pq_enable=0,external_storage=0);スパースベクターデータの表現
AnalyticDB for PostgreSQL では、SVECTOR 型を使用してスパースベクターデータを表すことができます。 SVECTOR 型は、JSON 形式の文字列をサポートしています。 indices フィールドを使用してインデックス配列 (負でない整数) を指定し、values フィールドを使用して値配列 (浮動小数点数) を指定できます。 次の例では、20 次元のスパースベクターについて説明します。
スパースベクターデータの例
[0, 0, 1.1, 0, 0, 0, 2.2, 0, 0, 3.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]スパースベクターデータの表現
{"indices":[2, 6, 9], "values":[1.1, 2.2, 3.3]}パラメーター:
indices:[2, 6, 9] は、スパースベクター内のゼロ以外の値のディメンション番号が 2、6、および 9 であることを指定します。
values:[1.1, 2.2, 3.3] は、スパースベクター内のゼロ以外の値が 1.1、2.2、および 3.3 であることを指定します。
AnalyticDB for PostgreSQL ベクトルデータベースでは、svector を使用して文字列を SVECTOR 型に変換できます。 サンプルステートメント:
postgres=# SELECT '{"indices":[2, 6, 9], "values":[1.1, 2.2, 3.3]}'::svector;
svector
--------------------------------------------
{"indices":[2,6,9],"values":[1.1,2.2,3.3]}
(1 ROW)スパースベクターデータをインポートする
INSERT または COPY ステートメントを使用して、スパースベクターデータをインポートできます。 この例では、svector_test スパースベクターテーブルと INSERT ステートメントを使用して、スパースベクターデータをインポートします。
-- スパースベクターデータを挿入します。
INSERT INTO svector_test VALUES (1, 1, 'a', 'xxx', '{"indices":[2, 6, 9], "values":[1.1, 2.2, 3.3]}'::svector);
INSERT INTO svector_test VALUES (2, 2, 'b', 'xxx', '{"indices":[50, 100, 200], "values":[2.1, 3.2, 4.3]}'::svector);
INSERT INTO svector_test VALUES (3, 3, 'b', 'xxx', '{"indices":[150, 60, 90], "values":[5, 1e3, 1e-3]}'::svector);スパースベクターを使用して検索を実行する
スパースベクター検索は、完全一致検索と近似検索に分けられます。
完全一致検索: 類似度に基づいて結果を厳密にソートする力まかせ探索。 このメソッドではすべてのベクターを比較する必要があるため、取得速度は遅くなりますが、最大 100% の再現率を実現できます。 精度が重要であるが、適時性が優先されないシナリオに適しています。
近似検索: 最適化されたアルゴリズムを使用して近似結果をすばやく見つけるメソッド。 精度は多少低下しますが、取得速度は大幅に向上します。 このメソッドは、適時性が重要であるが、絶対的な精度はそれほど重要ではないシナリオに適しています。
構文
スパースベクターテーブルの場合、スパースベクターインデックスは内積距離メトリックのみをサポートします。 完全一致検索と近似検索の構文:
完全一致検索
SELECT id, inner_product(<sparse_vector>, '{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector)
AS score FROM <SparseVectorTable> ORDER BY negative_inner_product(<sparse_vector>,
'{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector) LIMIT <topk>;パラメーター:
sparse_vector: スパースベクター列の名前。
SparseVectorTable: スパースベクターテーブルの名前。
topk: 結果セットから取得する上位 k 個の要素。
近似検索
SELECT id, inner_product(<sparse_vector>, '{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector)
AS score FROM <SparseVectorTable> ORDER BY <sparse_vector>
'{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector LIMIT <topk>;パラメーター:
sparse_vector: スパースベクター列の名前。
SparseVectorTable: スパースベクターテーブルの名前。
topk: 結果セットから取得する上位 k 個の要素。
例
この例では、svector_test スパースベクターテーブルを使用して、スパースベクター検索を実行します。
スパースベクター検索
SELECT id, sparse_features,
'{"indices":[2,60,50], "values":[2,0.01, 0.02]}' <#> sparse_features AS score
FROM svector_test
ORDER BY score
LIMIT 3;検索結果
id | sparse_features | score
--------+-------------------------------------------------+---------------------
3 | {"indices":[60,90,150],"values":[1000,0.001,5]} | -10
1 | {"indices":[2,6,9],"values":[1.1,2.2,3.3]} | -2.20000004768372
2 | {"indices":[50,100,200],"values":[2.1,3.2,4.3]} | -0.0419999957084656
(3 ROWS)fastann.sparse_hnsw_max_scan_points パラメーターと fastann.sparse_hnsw_ef_search パラメーターを使用して、スパースベクター検索の再現率を変更できます。 詳細については、このトピックの「付録」セクションをご参照ください。
密ベクターとスパースベクターを使用してハイブリッド検索を実行する
HYBRID_SEARCH_TEST という名前のテーブルを作成します。このテーブルには、ハイブリッド検索を実行するための密ベクターとスパースベクターが含まれています。 テーブルを作成するためのサンプルステートメント:
-- ハイブリッド検索用のテーブルを作成します。
CREATE TABLE IF NOT EXISTS HYBRID_SEARCH_TEST (
id integer PRIMARY key,
corpus text,
filter integer,
dense_vector float4[],
sparse_vector svector(250003)
) distributed BY (id);
-- スパースベクター列のストレージモードを PLAIN に設定します。
ALTER TABLE hybrid_search_test ALTER COLUMN dense_vector SET storage plain;
ALTER TABLE hybrid_search_test ALTER COLUMN sparse_vector SET storage plain;インデックスを作成するためのサンプルステートメント:
-- 構造化インデックスを作成します。
CREATE INDEX ON hybrid_search_test(FILTER);
-- 密ベクターインデックスを作成します。
CREATE INDEX ON hybrid_search_test USING ANN(dense_vector) WITH(DISTANCEMEASURE=IP, DIM=1024, HNSW_M=64, HNSW_EF_CONSTRUCTION=600, EXTERNAL_STORAGE=1);
-- スパースベクターインデックスを作成します。
CREATE INDEX ON hybrid_search_test USING ANN(sparse_vector) WITH(DISTANCEMEASURE=IP, HNSW_M=64, HNSW_EF_CONSTRUCTION=600);密ベクター検索、スパースベクター検索、およびハイブリッド検索を実行するためのサンプルステートメント:
-- 密ベクター検索 + フィルター
SELECT id, corpus FROM hybrid_search_test WHERE FILTER IN (0, 100, 200, 300, 400, 500, 600, 700, 800, 900) ORDER BY dense_vector <#> ARRAY[1,2,3,...,1024]::float4[] LIMIT 100;
-- スパースベクター検索 + フィルター
SELECT id, corpus FROM hybrid_search_test WHERE FILTER IN (0, 100, 200, 300, 400, 500, 600, 700, 800, 900) ORDER BY sparse_vector <#> '{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector LIMIT 100;
-- ハイブリッド検索 + フィルター
WITH combined AS (
(SELECT id, corpus, inner_product_distance(dense_vector, ARRAY[1,2,3,...,1024]::float4[]) AS dist1, sparse_vector <#> '{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector AS dist2 FROM hybrid_search_test WHERE FILTER IN (0, 100, 200, 300, 400, 500, 600, 700, 800, 900) ORDER BY dist2 LIMIT 100)
UNION ALL
(SELECT id, corpus, inner_product(sparse_vector, '{"indices":[1,2,..], "values":[1.1,2.2...]}'::svector) AS dist1, dense_vector <#> ARRAY[1,2,3,...,1024]::float4[] AS dist2 FROM hybrid_search_test WHERE FILTER IN (0, 100, 200, 300, 400, 500, 600, 700, 800, 900) ORDER BY dist2 LIMIT 100 )
) SELECT DISTINCT first_value(id) OVER (PARTITION BY id) AS id, first_value(corpus) OVER (PARTITION BY id) AS corpus, MAX(dist1 - dist2) OVER (PARTITION BY id) AS dist FROM combined ORDER BY dist DESC LIMIT 100;付録
スパースベクター検索に関連するエンジンパラメーター
スパースベクター検索に関連するエンジンパラメーター | 説明 | デフォルト値 | 有効な値 |
fastann.sparse_hnsw_max_scan_points | HNSW インデックスを使用してスパースベクター検索を実行する際の最大スキャンポイント数。 このパラメーターは、検索を事前に終了します。 このパラメーターを使用して、再現率をテストできます。 | 8000 | [1, 8000000] |
fastann.sparse_hnsw_ef_search | HNSW インデックスを使用してスパースベクター検索を実行する際の検索候補セットのサイズ。 このパラメーターを使用して、再現率をテストできます。 | 400 | [10, 10000] |
上記の パラメーターはセッションごとに構成できます。
スパースベクターでサポートされているベクター関数
目的 | ベクター関数 | 戻り値のデータ型 | 説明 | サポートされているデータ型 |
l2_distance | DOUBLE PRECISION | 2 つのスパースベクター間のユークリッド距離の平方根を計算します。 この関数は、2 つのスパースベクター間の距離を測定するために使用されます。 | SVECTOR | |
計算 | inner_product | DOUBLE PRECISION | 2 つのベクター間の内積距離を計算します。これは、ベクターの正規化後のコサイン類似度に相当します。 この関数は、ベクターの正規化後のコサイン類似度に代わるものとして使用されます。 | SVECTOR |
dp_distance | DOUBLE PRECISION | ドット積距離を計算します。これは、内積距離と同じです。 | SVECTOR | |
cosine_similarity | DOUBLE PRECISION | 2 つのスパースベクター間のコサイン類似度を計算します。 この関数は、スパースベクターの実際の長さに関係なく、方向に基づいて 2 つのスパースベクター間の類似度を測定するために使用されます。 コサイン類似度の有効な値: -1 から 1。 | SVECTOR | |
svector_add | SVECTOR | 2 つのスパースベクターの合計を計算します。 | SVECTOR | |
svector_sub | SVECTOR | 2 つのスパースベクターの差を計算します。 | SVECTOR | |
svector_mul | SVECTOR | 2 つのスパースベクターの積を計算します。 | SVECTOR | |
svector_norm | DOUBLE PRECISION | スパースベクターのノルムを計算します。 | SVECTOR | |
svector_angle | DOUBLE PRECISION | 2 つのスパースベクター間の角度を計算します。 | SVECTOR | |
ソート | l2_squared_distance | DOUBLE PRECISION | ユークリッド距離の2乗に基づいてベクターをソートします。 この関数は、ユークリッド距離の平方根に基づくソート方法よりも計算量が少ないです。 | SVECTOR |
negative_inner_product | DOUBLE PRECISION | 内積距離の負の値に基づいてベクターをソートします。 この関数は、内積距離に基づいてベクターを降順にソートするために使用されます。 | SVECTOR | |
cosine_distance | DOUBLE PRECISION | コサイン距離に基づいてベクターをソートします。 この関数は、コサイン類似度に基づいてベクターを降順にソートするために使用されます。 コサイン距離の有効な値: 0 から 2。 | SVECTOR |
ベクター関数の例
-- ユークリッド距離
SELECT l2_distance('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- 内積距離
SELECT inner_product('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- コサイン類似度
SELECT l2_distance('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- ベクトルの合計
SELECT svector_add('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- ベクトルの減算
SELECT svector_sub('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- ベクトルの乗算
SELECT svector_mul('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- ユークリッド距離の2乗
SELECT l2_squared_distance('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- 内積距離の負の値
SELECT negative_inner_product('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);
-- コサイン距離
SELECT cosine_distance('{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector, '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector);スパースベクターでサポートされているベクター演算子
演算子 | 計算 | ソート | サポートされているデータ型 |
<-> | 2 つのベクター間のユークリッド距離の2乗を計算します。 結果は、l2_squared_distance 関数の結果と同じです。 | なし | SVECTOR |
<#> | 2 つのベクター間の内積距離の負の値を計算します。 結果は、negative_inner_product 関数の結果と同じです。 | ドット積距離に基づいてベクターを降順にソートします。 | SVECTOR |
<#> | 2 つのベクター間のコサイン距離を計算します。 結果は、cosine_distance 関数の結果と同じです。 | なし | SVECTOR |
+ | 2 つのスパースベクターの合計を計算します。 | なし | SVECTOR |
- | 2 つのスパースベクターの差を計算します。 | なし | SVECTOR |
* | 2 つのスパースベクターの積を計算します。 | なし | SVECTOR |
ベクター演算子の例
-- ユークリッド距離の2乗
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector <-> '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS score;
-- 内積距離の負の値
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector <#> '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS score;
-- コサイン距離
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector <=> '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS score;
-- 2 つのベクターの合計
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector + '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS value;
-- 2 つのベクターの差
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector + '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS value;
-- 2 つのベクターの積
SELECT '{"indices":[1,2,3,4,5,6], "values":[1,2,3,4,5,6]}'::svector * '{"indices":[1,2,3,4,5,6], "values":[2,3,4,5,6,7]}'::svector AS value;