ベクトル最近傍探索(Similarity Search)は、ベクトル空間における距離尺度に基づく検索手法であり、クエリベクトルに最も近いベクトルの集合を見つけることが核心です。計算過程では特定の距離尺度(Distance Metric)が用いられますが、最終的には距離が小さい順に並べた上位K個の最近傍ベクトルが出力されます。
本記事では、OceanBaseの2種類のベクトル検索方法、すなわち全量スキャンに基づく厳密最近傍探索とベクトルインデックスに基づく近似最近傍探索について主に紹介し、具体的な例を用いてその使用方法を説明します。
説明
読みやすさのため、本文中ではベクトル最近傍探索を単にベクトル検索、厳密最近傍探索を厳密検索、近似最近傍探索を近似検索と略称します。
厳密検索の実行
厳密検索は、データセット内のすべてのベクトルとクエリベクトルとの距離を計算するフルスキャン戦略を採用しています。この方法は検索結果の完全な正確性を保証しますが、全量の距離計算が必要なため、データ規模の増大に伴い検索性能は著しく低下します。
厳密検索を実行する際、システムはクエリベクトル vₑ とベクトル空間内のすべてのベクトルとの距離を計算し比較します。全量の距離計算が完了すると、システムは距離が最も近い上位 k 個のベクトルを検索結果として返します。
例:ユークリッド類似性検索
ユークリッド類似性検索(Euclidean Similarity Search)は、ベクトル空間内でクエリベクトルに最も近い上位k個のベクトルを検索するために使用されます。ここでは、ユークリッド距離を尺度として使用します。以下の例は、厳密検索を使用してテーブルからクエリベクトルに最も近い上位5個のベクトルを検索する方法を示しています。
-- テストテーブルの作成
CREATE TABLE t1 (
id INT PRIMARY KEY,
c1 VECTOR(3)
);
-- データの挿入
INSERT INTO t1 VALUES
(1, '[0.1, 0.2, 0.3]'),
(2, '[0.2, 0.3, 0.4]'),
(3, '[0.3, 0.4, 0.5]'),
(4, '[0.4, 0.5, 0.6]'),
(5, '[0.5, 0.6, 0.7]'),
(6, '[0.6, 0.7, 0.8]'),
(7, '[0.7, 0.8, 0.9]'),
(8, '[0.8, 0.9, 1.0]'),
(9, '[0.9, 1.0, 0.1]'),
(10, '[1.0, 0.1, 0.2]');
-- 厳密検索の実行
SELECT c1
FROM t1
ORDER BY l2_distance(c1, '[0.1, 0.2, 0.3]') LIMIT 5;
実行結果は次のとおりです:
+---------------+
| c1 |
+---------------+
| [0.1,0.2,0.3] |
| [0.2,0.3,0.4] |
| [0.3,0.4,0.5] |
| [0.4,0.5,0.6] |
| [0.5,0.6,0.7] |
+---------------+
5 rows in set
実行計画の分析
上記の例の実行計画を取得します:
EXPLAIN SELECT c1
FROM t1
ORDER BY l2_distance(c1, '[0.1, 0.2, 0.3]') LIMIT 5;
戻り値は次のとおりです:
+---------------------------------------------------------------------------------------------+
| Query Plan |
+---------------------------------------------------------------------------------------------+
| ================================================= |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ------------------------------------------------- |
| |0 |TOP-N SORT | |5 |3 | |
| |1 |└─TABLE FULL SCAN|t1 |10 |3 | |
| ================================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1]), filter(nil), rowset=16 |
| sort_keys([l2_distance(t1.c1, cast('[0.1, 0.2, 0.3]', ARRAY(18, -1))), ASC]), topn(5) |
| 1 - output([t1.c1]), filter(nil), rowset=16 |
| access([t1.c1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.id]), range(MIN ; MAX)always true |
+---------------------------------------------------------------------------------------------+
14 rows in set
分析は以下のとおりです:
実行方法:
- フルテーブルスキャン方式を採用しており、テーブル内のすべてのデータを走査する必要があります。これは実行計画の
TABLE FULL SCAN操作に対応し、この操作はテーブルt1のすべてのデータをスキャンします。 - 各レコードのベクトル距離を計算し、その後ソートします。これは実行計画の
TOP-N SORT操作に対応し、l2_distance関数を使用してベクトル距離を計算し、距離の昇順でソートします。 - 最終的に、距離が最小の上位5件のレコードを返します。これは実行計画の
topn(5)設定に対応し、ソート後の上位5件のレコードのみを返すことを意味します。
- フルテーブルスキャン方式を採用しており、テーブル内のすべてのデータを走査する必要があります。これは実行計画の
性能特性:
- 利点:結果は完全に正確であり、真の最近傍を返すことが保証されます。
- 欠点:テーブル全体のデータをスキャンし、すべてのベクトルの距離を計算する必要があるため、データ量の増加に伴い性能が著しく低下します。
適用シナリオ:
- データ量が少ないシナリオ。
- 結果の正確性に対する要求が非常に高いシナリオ。
- 大規模なデータセットに対するリアルタイムクエリには適していません。
ベクトルインデックスを使用した近似検索の実行
ベクトルインデックス検索は、近似最近傍(Approximate Nearest Neighbor、ANN)戦略を採用し、事前に構築されたインデックス構造を用いて検索処理を高速化します。結果の精度が100%保証されるわけではありませんが、検索性能を大幅に向上させることができ、実際のアプリケーションでは精度と性能の間で良好なバランスを実現できます。
例:HNSWインデックスによる近似検索
-- テーブル作成と同時にHNSWベクトルインデックスを作成
CREATE TABLE t2 (
id INT PRIMARY KEY,
vec VECTOR(3),
VECTOR INDEX idx(vec) WITH (distance=l2, type=hnsw, lib=vsag)
);
-- テストデータの挿入
INSERT INTO t2 VALUES
(1, '[0.1, 0.2, 0.3]'),
(2, '[0.2, 0.3, 0.4]'),
(3, '[0.3, 0.4, 0.5]'),
(4, '[0.4, 0.5, 0.6]'),
(5, '[0.5, 0.6, 0.7]'),
(6, '[0.6, 0.7, 0.8]'),
(7, '[0.7, 0.8, 0.9]'),
(8, '[0.8, 0.9, 1.0]'),
(9, '[0.9, 1.0, 0.1]'),
(10, '[1.0, 0.1, 0.2]');
-- 近似検索を実行し、最も類似する5件のデータを返す
SELECT id, vec
FROM t2
ORDER BY l2_distance(vec, '[0.1, 0.2, 0.3]')
APPROXIMATE
LIMIT 5;
データ量が少ないため、返される結果は上記の厳密検索の結果と一致します。
+------+---------------+
| id | vec |
+------+---------------+
| 1 | [0.1,0.2,0.3] |
| 2 | [0.2,0.3,0.4] |
| 3 | [0.3,0.4,0.5] |
| 4 | [0.4,0.5,0.6] |
| 5 | [0.5,0.6,0.7] |
+------+---------------+
5 rows in set
実行計画の分析
上記の例の実行計画を取得します:
EXPLAIN SELECT id, vec
FROM t2
ORDER BY l2_distance(vec, '[0.1, 0.2, 0.3]')
APPROXIMATE
LIMIT 5;
戻り値は次のとおりです:
+--------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------+
| ==================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------- |
| |0 |VECTOR INDEX SCAN|t2(idx)|10 |29 | |
| ==================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t2.id], [t2.vec]), filter(nil), rowset=16 |
| access([t2.id], [t2.vec]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t2.__vid_1750162978114053], [t2.__type_17_1750162978114364]), range(MIN,MIN ; MAX,MAX)always true |
+--------------------------------------------------------------------------------------------------------------------+
11 rows in set
分析は以下のとおりです:
実行方法:
- ベクトルインデックススキャン方式を採用し、事前に構築されたHNSWインデックスを通じて類似ベクトルを直接特定します。これは実行計画の
VECTOR INDEX SCAN操作に対応し、インデックスt2(idx)を使用して検索を行います。 - インデックスのグラフ構造を利用して近傍点を迅速に見つけるため、すべてのベクトルの距離を計算する必要はありません。これは実行計画の
is_index_back=true設定に対応し、インデックスを通じてテーブルに戻り完全なデータを取得することを示します。 - 最終的に、インデックスが最も類似していると判断した上位5件のレコードを返します。これは実行計画の
output([t2.id], [t2.vec])に対応し、idとベクトルデータを返すことを意味します。
- ベクトルインデックススキャン方式を採用し、事前に構築されたHNSWインデックスを通じて類似ベクトルを直接特定します。これは実行計画の
性能特性:
- 利点:検索性能が高く、データ量の増加にも安定して対応します。
- 欠点:結果にはわずかな誤差が生じる可能性があり、100%の正確性は保証されません。
適用シナリオ:
- 大規模データセットのリアルタイム検索。
- 検索性能に対する要求が高いシナリオ。
- 結果にわずかな誤差が許容されるシナリオ。
比較の概要
2つの検索方法の比較の概要は以下のとおりです。
比較項目 |
厳密検索 |
近似検索 |
|---|---|---|
| 実行方式 | フルテーブルスキャン (TABLE FULL SCAN) の後にソートする |
ベクトルインデックス (VECTOR INDEX SCAN) による直接検索 |
| 実行計画 | TABLE FULL SCAN と TOP-N SORT の2つのオペレーターを含む |
VECTOR INDEX SCAN の1つのオペレーターのみを含む |
| 性能特性 | 全テーブルデータをスキャンしてソートする必要があり、データ量の増加に伴い性能が著しく低下する | インデックスにより対象データを直接特定するため、性能が安定している |
| 結果の正確性 | 100% 正確で、真の最近傍を返すことが保証される | 近似的な正確さで、わずかな誤差が生じる可能性がある |
| 適用シナリオ | データ量が少なく、正確性が高いことが求められるシナリオ | 大規模データセットで、性能が求められるシナリオ |
関連ドキュメント
- SQL関数の詳細については、SQL関数の使用を参照してください。
- ベクトルインデックスの説明と例については、ベクトルインデックスを参照してください。
- 大規模なパフォーマンステストを実施する場合は、VectorDBBenchmarkツールを使用してテストデータセットを生成し、厳密検索と近似検索のパフォーマンス差をより適切に比較することを推奨します。