2025年7月23日水曜日

Oracle AI Vector SearchのFLOAT 32 Vector Generatorの例題をAPEXで実行する

Oracle AI Vector Search User's Guideに以下の章が含まれています。

Oracle AI Vector Search User's Guide
3 Getting Started
SQL Quick Start Using a FLOAT32 Vector Generator

ドキュメントではコマンドを実行して動作を確認する手順になっています。Getting Startedがコマンドラインの操作というのも敷居が高いように感じたので、SQL Quick Start Using a FLOAT32 Vector Generatorに記載されている作業を実行できるAPEXアプリケーションを作ってみました。

注意:
ドキュメントに「Do not use the vector generator on production databases. The program is made available for testing and demo purposes.」記載されているように、Getting Startedの作業を本番データベースで実施しないでください。

作成したAPEXアプリケーションは以下のように動作します。チャート表示にPlotlyのJavaScriptライブラリ(scatter3dチャート)を使用しています。


実行計画を表示するために、APEXのワークスペース・スキーマに以下の権限を割り当てています。

grant select_catalog_role to <APEXワークスペース・スキーマ>;
grant select on sys.v_$sql to <APEXワークスペース・スキーマ>;
grant select on sys.v_$session to <APEXワークスペース・スキーマ>;
grant select on sys.v_$sql_plan to <APEXワークスペース・スキーマ>;

Plotlyのscatter3dチャートに検索結果を表示するため、ベクトルの次元数は3以上である必要があります。次元数は3より大きい値にできますが、チャートは最初の3次元だけを表示に使います。

記述したコードのほとんどは、データベースからPlotly向けにデータを取得するためのコードなので、Oracle DatabaseのVector Searchのサンプルというよりは、PlotlyのチャートをOracle APEXのアプリケーションに組み込んで使うサンプルになっています。

作成したAPEXアプリケーションのエクスポートを以下に置いています。
https://github.com/ujnak/apexapps/blob/master/exports/vector-search-genvec-plotly.zip

以下よりAPEXアプリケーションの実装と使用しているAPEXの機能について、大まかに説明します。

Oracle APEXのアプリケーションには、サポートするオブジェクトという項目があります。


サポートするオブジェクトでは、APEXアプリケーションのインストールアップグレードおよび削除時の処理を定義できます。

ほとんどの場合、インストールではAPEXアプリケーションが必要としている表、ビューおよびパッケージの作成を行います。削除では、それらのデータベース・オブジェクトの削除を行います。


本記事のアプリケーションのインストール・スクリプトでは、表GENVECの作成とパッケージVECTOR_GEN_PKGの作成を行なっています。


削除スクリプトでは、パッケージVECTOR_GEN_PKGの削除と表GENVECの削除を行なっています。


そのため、APEXアプリケーションをインストールするとGetting Startedの作業を行うために必要な表GENVECとパッケージVECTOR_GEN_PKGが作成されます。また、アプリケーションを削除すると、表GENVECとパッケージVECTOR_GEN_PKGも合わせて削除されます。

APEXアプリケーションをインストールして実行します。

ナビゲーション・メニューには、ホームIndexTableConfigurationsの4つのメニューが含まれます。記事の先頭にあるGIF動画は、ホーム・ページでの作業になります。

Configurationsのページでは、上から近似近傍検索(ANN検索)に使用するSELECT文、完全一致検索に使用するSELECT文、検索条件が与えられていない場合に使用するSELECT文、HNSW索引を作成するDDL、IVF索引を作成するDDLの5つのスクリプトが登録されてます。概ねGetting Startedに記載されているSELECT文やCREATE INDEX文がデフォルトになっています。

索引名はHNSW、IVFともにGENVEC_VECTOR_IDXとしています。また、SELECT文にコメントとして/* my_vector_query */を含めることにより、実行計画を取り出しやすくしています。検索条件の第1引数としてベクトル値、第2引数として検索する件数が与えられます。

SELECT文やDDLを変更することで、例えば距離をEUCLIDEANからCOSINEに変更したり、索引の精度を変更したりできます。


これらのSELECT文やDDLを、共有コンポーネントアプリケーション・アイテムに保存しています。


それぞれのアプリケーション・アイテムアプリケーションの計算を作成し、デフォルト値を設定しています。計算ポイント新規インスタンス(新規セッション)開始時を選択し、計算タイプ静的値計算にデフォルトのスクリプトを記述しています。

結果として、セッション開始時アプリケーションの計算に設定したスクリプトがアプリケーション・アイテムに設定されます。


アプリケーション・アイテムはページに直接配置できません。そのため、アプリケーション・アイテムソースとしたページ・アイテムを作成しています。


ボタンSUBMITをクリックしたときに以下のコードを実行することにより、ページ・アイテムに記述したスクリプトをアプリケーション・アイテムに転記しています。
begin
    apex_session_state.set_value('SELECT_EXACT',     :P4_SELECT_EXACT);
    apex_session_state.set_value('SELECT_APPROX',    :P4_SELECT_APPROX);
    apex_session_state.set_value('SELECT_DEFAULT',   :P4_SELECT_DEFAULT);
    apex_session_state.set_value('CREATE_INDEX_IVF', :P4_CREATE_INDEX_IVF);
    apex_session_state.set_value('CREATE_INDEX_HNSW', :P4_CREATE_INDEX_HNSW);
end;

Tableのページでは、表GENVECへのデータの生成とトランケートを行います。データの生成にはVECTOR_GEN_PKG.GENERATE_VECTORSを呼び出します。ページ・アイテムはそれぞれ、VECTOR_GEN_PKG.GENERATE_VECTORSの引数に対応しています。


Oracle APEXではプロセス・タイプとしてAPIの呼出しを選択することにより、コードを記述せずにプロシージャおよびファンションを呼び出すことができます。


Truncate文のようなDDLは、EXECUTE IMMEDIATE文で実行します。こちらは若干ですが、コーディングが必要です。
begin
    execute immediate 'truncate table genvec';
exception
    when others then
        null;
end;

Indexのページでは、HNSWとIVFの索引の作成および削除を行います。索引GENVEC_VECTOR_IDXが作成済みの場合は、V$VECTOR_INDEXの内容を表示します。

ドキュメントのGetting StartedではVECSYS.VECTOR$INDEXを検索していますが、この表はAutonomous Databaseには存在しないため、V$VECTOR_INDEXに置き換えています。


画面上のボタンとしてDrop IndexCreate Hnsw IdxCreate Ivf Idxの3つがあります。

このボタンをクリックしたときに実行されるプロセスとして、以下の4つが作成されています。
  1. Drop Index
  2. Create Hnsw Index
  3. create Ivf Index
  4. Gather Table Stats
この内、Drop IndexおよびGather Tables Statsには、サーバー側の条件が無く、どのボタンを押しても実行されます。


ボタンCreate Hnsw Idxがクリックされた時に限り、プロセスCreate Hnsw Indexが実行されます。この時、アプリケーション・アイテムCREATE_INDEX_HNSWに設定されているコマンドが実行されます。


ボタンCreate Ivf Idxがクリックされたは、プロセスCreate Ivf Indexが実行されます。この時、アプリケーション・アイテムCREATE_INDEX_IVFに設定されているコマンドが実行されます。


このようにサーバー側の条件を設定して、単一の処理を組み合わせた簡単な処理フローを定義することができます。これとは逆に、以下のようにプロセス中のコードで処理フローを記述することもできます。
declare
    C_DROP_INDEX   constant varchar2(400) := q'~DROP INDEX if exists genvec_vector_idx~';
begin
    /* 索引のドロップ */
    execute immediate C_DROP_INDEX;
    /* 索引の作成 */
    if :REQUEST = 'CREATE_HNSW_IDX' then
        execute immediate :CREATE_INDEX_HNSW;
    elsif :REQUEST = 'CREATE_IVF_IDX' then
        execute immediate :CREATE_INDEX_IVF;
    end if;
    /* 統計情報の収集 */
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname => null,
        tabname          => 'GENVEC',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        cascade          => TRUE
    );
end;
ホーム・ページには3つのボタン、SearchApprox SearchおよびResetがあります。ボタンResetはページ・アイテムに設定された値を空白にします。そのため、実質的な処理を行うボタンは、完全一致検索を行うSearch近傍近似検索を行うApprox Searchになります。


ページ・プロパティJavaScriptファイルURLに以下を記述し、Plotlyのライブラリを読み込みます。

https://cdn.plot.ly/plotly-3.0.1.min.js

ファンクションおよびグローバル変数の宣言にて、scatter3dチャートのレイアウトをlayoutとして設定します。rangenullを設定していますが、rangeは検索結果に基づいて設定されます。



ボタンSearchApprox Searchの双方とも、ボタンクリック時の動的アクションで以下のJavaScriptコードを実行します。


x01this.triggeringElement.idを与えることで、ボタンの違いを認識します。ボタン名をIDとして参照させるため、ボタンに静的IDを設定しています。Oracle APEXではHTML要素のIDにランダムな文字列を割り当てます。そのため、要素をID指定で参照する場合は、明示的に静的IDを設定する必要があります。


このコードでは、サーバー側に実装したAjaxコールバックGET_DATAを呼び出し、返されたデータを元にPlotlyのscatter3dチャート(DIV要素myDiv)を更新しています。また、ページ・アイテムに値を設定しリージョンをリフレッシュすることにより、実行計画(リージョンPLAN)および検索結果のレポート(リージョンVECTORS)を更新しています。

ベクトル検索の実行および呼び出し元に返すデータを生成するプロセスGET_DATAのコードは以下になります。



実行計画は動的コンテンツとして表示しています。ソースCLOBを返すPL/SQLファンクション本体に以下を記述しています。



対話モード・レポートによる検索されたベクトルの一覧は、プロセスGET_DATA内で保存したベクトルの名前を元にしています。

ソースSQL問合せは以下になります。

select * from genvec where name in (select column_value from apex_string.split(:P1_ALL_VECTORS,','))


今回の記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。