2025年7月24日木曜日

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

先日、FLOAT32 Vector Generatorの例題について記事を書いています。今回は、その次のセクションに記載されているBINARY Vector Generatorの例題をAPEXのアプリケーションに実装してみます。

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

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

作成したAPEXアプリケーションは以下のように動作します。今回は2次元の散布図なので、APEX標準のチャートを使用します。2次元の散布図にバイナリ・ベクトルを表示するため、バイナリ・ベクトルに対してt-SNEを適用し、2次元の埋め込み空間へ次元圧縮を行っています。t-SNEを適用するOML4Pyの埋め込みファンクションを定義し、OML4Py SQL APIから呼び出しています。


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

Plotlyを組み込んでいないため、FLOAT32 Vector Generatorを扱うAPEXアプリケーションより簡単な作りになっています。

OML4Pyを使うため、このAPEXアプリケーションを実行できるプラットフォームはx86_64に限定されます。本記事ではAlways FreeのAutonomous Database上でアプリケーションを開発しています。

Autonomous DatabaseでOML4PyのSQL APIを呼び出す手順については、以前に記事「Autonomous DatabaseでPythonで記述したファンクションを表関数として実行する」で紹介しています。以下の2つの作業は、あらかじめ実施しておきます。
  1. APEXのワークスペース・スキーマのOMLユーザーオンにします。
  2. 管理者ユーザーADMINにて、pyqAppendHostAceを呼び出してネットワークACLを追加します。
OML4Pyが標準で持っているパッケージのみを使用するため、condaによる環境作成とアップロードは不要です。

また、実行計画を表示するため、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ワークスペース・スキーマ>;

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

サポートするオブジェクトインストール・スクリプトで、アプリケーションの動作に必要なデータベース・オブジェクトを作成しています。


この中で、表GENBVECの作成(スクリプトgenbvec)、プロシージャgenerate_random_binary_vectorgenerate_binary_clustergenerate_binary_vectorsの作成スクリプトは、ドキュメントに記載されているコードをそのままインストール・スクリプトにしています。

スクリプトgenbvec_tsneにて、表GENBVEC_TSNEを作成します。OML4PyのSQL APIを呼び出してt-SNEを適用した結果が、表GENBVEC_TSNEに保存されます。
create table genbvec_tsne(
    name varchar2(500),
    x number,
    y number
);
スクリプトgenbvec_vにてビューGENBVEC_Vを作成します。
create or replace view genbvec_v
as
select name, bv from genbvec;
OML4PyのpyqTableEvalの引数inp_namに与える表はVECTOR型を含むことができないようです。t-SNEの適用に必要な列NAMEと列BV(バイナリ・ベクトルの文字列表現)のみを含むビューGENBVEC_Vを作成し、pyqTableEvalのinp_namに指定します。

スクリプトcompute_tsne_embeddingにて、OML4PyのSQL APIから呼び出すPythonファンクションcompute_tsne_embeddingを作成します。


Pythonスクリプトcompute_tsne_embeddingは、入出力仕様を与えた上で、Claude Sonnet 4とOpenAI GPT-4oの両方を使って書いてもらっています。

以上のインストール・スクリプトが実行されると、このAPEXアプリケーションが必要としているデータベース・オブジェクトが準備されます。

インストール・スクリプトによって作成されたオブジェクトは、削除スクリプトによる削除されます。そのため、APEXアプリケーションを削除すると元の状態に戻ります。

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

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

Configurationsのページでは、完全一致検索に使用するSELECT文と、検索条件が与えられていない場合に使用するSELECT文が登録されています。Getting Startedに記載されているSELECT文がデフォルトになっています。


OMLのページでは、OML4PyのSQL APIの呼び出しに必要な認証を実行します。APEXのワークスペース・スキーマのパスワードを入力し、ボタンGet Token / Set Auth Tokenをクリックします。

このページの実装については、OML4Pyの記事で説明しています。


Tableのページでは、表GENBVECへのデータ生成を行います。


プロセスGenerate Vectorsが、プロシージャGENERATE_BINARY_VECTORSを呼び出しています。ページ・アイテムはぞれぞれプロシージャGENERATE_BINARY_VECTORSの引数に対応しています。


表GENBVECへのデータ生成に続けてt-SNEを適用します。t-SNEの適用はプロセスcompute_tsne_embeddingが実行します。実行するPL/SQLコードは以下になります。適用結果は表GENBVEC_TSNEに保存されます。

Pythonファンクションcompute_tsne_embeddingは引数としてrandom_stateperplexitylearning_raten_tierを含んでいます。pyqTableEvalの引数par_lstに与えるJSONで、これらの引数の値を指定できます。


ボタンTruncate Tableをクリックすると、プロセスTruncate Tableが実行されます。表GENBVECおよびGENBVEC_TSNEがトランケートされます。


ホーム・ページには2つのボタン、SearchResetがあります。ボタンResetはページ・アイテムに設定された値を空白にします。そのため、実質的な処理を行うボタンはSearchのみになります。


ボタンSearchをクリックすると、以下のPL/SQLコードをサーバー側のコードとして実行します。検索されたバイナリ・ベクトルの名前をAPEXコレクションに保存します。

検索が完了した後に、チャート、実行計画、レポートのリージョンをリフレッシュして検索結果を反映します。


2次元の散布図はAPEXの標準チャートを使用しています。シリーズソースとして以下のSQL問合せを記述しています。

select REGEXP_SUBSTR(name, '^[^-]+') series, name, x, y from genbvec_tsne
where name in (
    select c001 from apex_collections where collection_name = 'SEARCH_RESULT'
)

列のマッピングシリーズ名に列SERIESラベルに列NAMEXに列XはいこれはYの翻訳ミスでしょう)に列Yを割り当てます。


Oracle APEXのチャートでは、チャートのX軸やY軸の最大値と最小値をページ・アイテムを元に設定できません。最大値と最小値が無指定の場合、表示するデータに合わせて最大値と最小値が決まります。

例えばベクトルC1の近傍20件を検索すると、チャートの表示は以下のようになります。


ベクトルC2の近傍20件を検索すると、チャートの表示は以下のようになります。検索されたベクトルに合わせてX軸やY軸の範囲が代わり、検索されたベクトルはつねにチャート全体に表示されます。


チャートのX軸、Y軸の最小値と最大値を、検索結果によらず、すべてのベクトルが表示できる値に固定するために、チャートの初期化JavaScriptファンクションに以下を記述しています。
function(config) {
    minVal = Number(apex.item("P1_MIN_VALUE").getValue());
    maxVal = Number(apex.item("P1_MAX_VALUE").getValue());
    config.xAxis.min = minVal;
    config.xAxis.max = maxVal;
    config.yAxis.min = minVal;
    config.yAxis.max = maxVal;
    return config;
}

X軸、Y軸の最小値(ページ・アイテムP1_MIN_VALUE)最大値(ページ・アイテムP1_MAX_VALUE)は表GENBVEC_TSNEの列XとYの値より算出しています。

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

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