HNSW索引のトランザクション・サポート

Hierarchical Navigable Small World (HNSW)索引は、効率的なベクトル検索のために設計された特殊なメモリー専用構造です。HNSW索引が作成されると、実表に対して実行された後続の挿入、更新または削除(DML操作)は索引に反映されません。

トランザクションは、1つ以上のSQL文を含むアトミックな論理作業単位です。HNSW索引のトランザクション一貫性は、プライベート・ジャーナルと共有ジャーナルという2つの主要な構造を使用してOracleデータベースで維持されます。

プライベート・ジャーナルは、トランザクションによって追加または削除されたベクトルを追跡する、トランザクションごとのインメモリー・データ構造です(更新は実際には削除の後に挿入が実行されます)。これは、インメモリー列ストア・データの保守に使用されるトランザクション・ジャーナル(『Oracle Database In-Memoryガイド』を参照)に類似しています。これらのインメモリー・データ構造は、読取り一貫性の維持に使用され、ベクトル・メモリー・プールにあります。

共有ジャーナルは、読取り一貫性のために使用されるディスク上の表ベースのオブジェクトです。これはHNSW索引の作成時に作成され、そのHNSW索引にのみ関連付けられます。共有ジャーナルには、実表のトランザクションに続いて、コミットされたシステム変更番号(SCN)と、対応する変更された行が含まれます。また、共有ジャーナルは開始以降、HNSW索引に影響する、コミットされたすべてのDML操作の順序を維持します。実表のトランザクションがコミットされると、プライベート・ジャーナルに記録された変更は、行に変換されてフラッシュされ、共有ジャーナルに書き込まれます。

前に定義した構造と相互に結合して使用し、HNSW索引を持つ表に対するトランザクション・メンテナンスおよび読取り一貫性の全体的なパフォーマンスを向上させる方法を見てみましょう:

  1. トランザクションの一貫性がある上位K件の結果の取得:

    DMLの後に、メモリー内の既存のHNSWグラフと問合せのプライベート・ジャーナルおよび共有ジャーナルの両方を考慮して、削除および挿入された一連のベクトルのトランザクション一貫性のあるリストを判別することで、読取り一貫性が確保されます。これは、ジャーナルから削除されたベクトルの正確なリストを識別し、削除されたベクトルを無視するようにフィルタを拡張して、現在のバージョンのHNSW索引で近似top-K検索を実行し、ジャーナルに新しく挿入されたベクトルの正確なtop-k検索を実行して、2つの検索の結果をマージすることで構成されます。

    次の図にこれを示します。

  2. HNSWグラフのリフレッシュ:
    索引の作成後に実行される問合せでは、索引に加え、上位K件の結果を取得するためにその後に発生したDMLを参照する必要があります。DMLが蓄積されるほど、共有ジャーナル・ベクトルの正確な検索は、現在索引付けされているHNSWグラフの近似検索よりもコストが高くなるため、問合せは遅くなります。この影響を最小限に抑えるために、増分スナップショットまたは完全再移入のいずれかを使用してグラフ・リフレッシュが実行されます。
    1. 増分スナップショット:

      増分スナップショットは、既存のインメモリー・グラフ索引の増分更新バージョンで、これまでに削除されたすべてのベクトルのリストを組み合せたものです。このスナップショットは、特定のコミットSCNにリンクされており、共有ジャーナルのサイズを小さくするのに役立ちます。ジャーナルが大きくなりすぎてパフォーマンスに影響すると、スナップショットが自動的に作成されます。スナップショットが作成されると、現在グラフ作成に使用されているものと同じアルゴリズムを使用して、新しいベクトルが既存のHNSWグラフに追加されます。このメソッドは、索引作成時に定義されたパラメータに基づいて、新しいベクトルがそれぞれ接続する他のベクトルを慎重に選択します。削除されたベクトルは、実際にはグラフから削除されません。かわりに、ビット・ベクトルを使用して追跡され、検索中に非表示になります。メモリーに関しては、新しい挿入が10%ある場合、増分スナップショットのベクトル・メモリー要件は、元のHNSWグラフより約10%多くなります。削除された頂点のビット・ベクトルは、メモリー・フットプリントの観点からは無視できるものとみなされます。

      次の図にこれを示します。

      図6-6 HNSWスナップショット



      ノート:

      • Oracle RAC環境では、スナップショットはサポートされていません。
      • 任意の時点で2つのスナップショットを使用できます。スナップショットの作成は、問合せに対して最新のスナップショットをオンラインに保つことによって、二重バッファ方式で実行されます。最も古いスナップショットは、新しいスナップショットが作成される前に削除されます。
      • 最新のスナップショットの作成SCNを下回る問合せは、エラーORA 51815 "INMEMORY NEIGHBOR GRAPH HNSWベクトル索引スナップショットが古すぎます。"になります。
      • V$VECTOR_GRAPH_INDEX_SNAPSHOTSビューを問い合せると、スナップショットID (SNAPSHOT_IDで示される)、スナップショットが作成されたSCN (BUILD_SCNで示される)、問合せに対してスナップショットがオープンされているSCN (VALID_SCNで示される)、スナップショットのグラフに存在するベクトルの数(NUM_VECTORSで示される)、グラフで削除済としてマークされたベクトルの数(NUM_DELETESで示される)など、スナップショットに関連するいくつかのパラメータを把握できます。
      • また、ベクトルの増加(NUM_VECTORSパラメータで示される)に伴ってMAX_SNAPSHOTパラメータがどのように変化するかを理解するために、使用されているHNSW索引についてV$VECTOR_GRAPH_INDEX表を問い合せることもできます。
    2. 完全な再移入:

      増分スナップショットによって多数のDML (特に削除)が蓄積されると、検索パフォーマンスとメモリー効率が低下し始めます。削除はマスクされるのみで、物理的に削除されないため、グラフは雑然としたものになり、問合せが遅くなり、領域の浪費となります。このオーバーヘッドが事前定義済のしきい値を超えると、HNSW索引の完全な再移入が自動的にトリガーされます。増分スナップショットは、最小限の更新を頻繁に行い、パフォーマンスとメモリー使用のバランスをとるために最適化されますが、完全な再移入(ただし、よりリソースを消費します)では、グラフが過度に断片化されると、検索品質と領域効率の両方をリストアする必要があります。

      既存のグラフを更新する増分スナップショットとは異なり、完全な再移入では、進行中の問合せに対して古いグラフをアクティブに保ちながら、新しいグラフが作成されます。たとえば、ベクトルの10%が新しい場合、新しいグラフに必要なメモリーは元のメモリーより約10%多くなるため、ピーク・メモリー使用量は2.1倍になり、切り替え後に1.1倍に減少します。

      次の図にこれを示します。

    ノート:

    • 完全再移入時(新しいHNSWグラフが使用可能になるまで)に、存在しなくなった古いバージョンのHNSWグラフに問合せでアクセスしようとすると、読取り一貫性エラー(ORA-51815 "INMEMORY NEIGHBOR GRAPH HNSWベクトル索引スナップショットが古すぎます。")がトリガーされます。

    • 新しく作成されたグラフに関する情報を含むHNSW索引についてV$VECTOR_GRAPH_INDEX表を問い合せることができます。V$VECTOR_GRAPH_INDEX_CHECKPOINTSビューおよびV$VECTOR_GRAPH_INDEX_SNAPSHOTSビューを使用して、最新のチェックポイントおよび新しいグラフの最初のスナップショットに関するデータを収集することもできます。

DBMS_VECTOR.REBUILD_INDEXプロシージャの idx_rebuild_modeパラメータを使用して、HNSWグラフのリフレッシュ方法を指定できます。このパラメータは、FULLという1つの値のみを受け入れます。これにより、完全なグラフ再構築が可能になります。デフォルトでは、idx_rebuild_modeNULLに設定されます。この場合、システムは既存の動作に従い、索引を削除して再作成します。idx_rebuild_modeでは、索引リフレッシュ操作を管理する際にきめ細かい制御が可能です。

完全な再移入をトリガーする例:

execute dbms_vector.rebuild_index('galaxies_hnsw_idx', 
                                           'galaxies', 
                                           'embedding', 
                                            NULL, 
                                            NULL, 
                                           'INMEMORY NEIGHBOR GRAPH', 
                                           'EUCLIDEAN', 
                                            95, 
                                            FULL, 
                                           '{"type" : "HNSW", "neighbors" : 3, "efConstruction" : 4 }') ;

ノート:

このコードは、索引galaxies_hnsw_idxgalaxies表にすでに作成されていることを前提としています。HNSW索引の作成に関するガイダンスは、Hierarchical Navigable Small World (HNSW)索引の構文およびパラメータに関するOracleドキュメントを参照してください。