Oracle APEX 24.2に検索構成として新たに
Oracleベクトル検索が追加されました。今回の記事では、この
Oracleベクトル検索を使ったAPEXアプリケーションを作成してみます。また、これまでのAPEXにあった
Oracle Textによる検索構成も作成し、それぞれ比較してみます。
作成したAPEXアプリケーションで、以下の文言で検索します。
「民泊を規制している条文を教えて」
検索結果にアイコンが含まれているカードは、ベクトル検索でヒットした条文になります。表示対象を5件にしているため、結果として5件表示されています。アイコンが表示されていないカードは無いので、Oracle Text検索でヒットした条文はありません。
以下の文言で検索します。
「民泊」
ベクトル検索だけが検索にヒットします。条文に「民泊」という単語は含まれていません。
ベクトル検索の結果より、法令では民泊のことを「住宅宿泊事業」と呼んでいることがわかります。「
住宅宿泊事業」で検索します。
単語として住宅宿泊事業が含まれている条文がリストされました。
以下より、
Oracleベクトル検索の
検索構成の作成と、それを使用したAPEXアプリケーションを作成します。
検索に使用するデータの準備から始めます。以前の記事に従って表JLAW_DATAに法令(対象は観光)のデータがロード済みとします。データがロードされていると本則をビューJLAW_LAW_MAINPROVISION_XVより参照できます。
select * from jlaw_law_mainprovision_xv;
本則のデータを投入した実表を、表JLAW_LAW_SENTENCESとして作成します。
create table jlaw_law_sentences as select * from jlaw_law_mainprovision_xv;
作成した表JLAW_LAW_SENTENCESには主キー列がありません。検索構成を作成する際に主キー列は必須なので、主キー列として列SIDを追加します。
alter table jlaw_law_sentences add (sid number generated by default on null as identity);
法令の条文は列
"Sentence"に含まれています。この列"Sentence"から生成したベクトル表現(embeddingのことです、以下、ベクトル表現とします)を保存する列を
SENTENCE_VECTORとして追加します。
alter table jlaw_law_sentences add (sentence_vector vector);
Oracle Text索引を列"Sentence"に作成します。Text索引に指定するレクサーを作成します。
begin
ctx_ddl.create_preference('ja_vgram_lexer', 'JAPANESE_VGRAM_LEXER');
end;
/ctx_ddlの実行権限がないというエラーが発生した場合は、管理者権限のあるユーザーでgrant文を実行します。
grant execute on ctx_ddl to <APEXワークスペース・スキーマ>;
Oracle Text索引JLAW_LAW_SENTENCES_CTXを列"Sentence"に作成します。
create index jlaw_law_sentences_ctx on jlaw_law_sentences("Sentence")
indextype is ctxsys.context
parameters('
lexer ja_vgram_lexer
sync (on commit)
');
全文検索を実行し、Oracle Text索引が正しく作成されたことを確認します。
select count(*) from jlaw_law_sentences where contains("Sentence", '観光') > 0
列"Sentence"に保存されている条文のベクトル表現を生成し、列SENTENCE_VECTORに保存します。
ベクトル表現の生成に、ローカルのLM Studioを使用します。embeddingモデルとしてtext-embedding-granite-embedding-278m-multilingual@q8_0を使用します。(Ollamaでモデルgranite-embedding:278mを使用すると、なぜか1件だけエラーが発生してembeddingが生成されませんでした。)
LM Studioのローカル・サーバーはポート8080で接続の待受けをするように構成しています。
Oracle APEX 24.2のワークスペース・ユーティリティに、新たにベクトル・プロバイダが追加されています。このベクトル・プロバイダを使用して、テキストからベクトル表現を生成します。
ベクトル・プロバイダを開き、LM Studioの
text-embedding-granite-embedding-278m-multilingual@q8_0を呼び出すプロバイダを作成します。
作成をクリックします。
プロバイダ・タイプとして生成AIサービスを選択します。プロバイダ・タイプには生成AIサービスの他にデータベースONNXモデルとカスタムPL/SQLがあります。
LM StudioのOpen AI互換APIを呼び出してベクトル表現を生成するため、AIプロバイダにはOpen AIを選択します。名前はLocal Granite 278m、静的IDはLOCAL_GRANITE_278Mとします。APEXはローカルのpodmanでコンテナとして動作させているため、LM Studioのembedding APIを呼び出すベースURLに以下を設定します。
http://host.containers.internal:8080/v1
LM Studioでは資格証明は不要ですが必須設定なので、資格証明として- 新規作成 -を選択し、APIキーにdummy(文字列はなんでも良い)と入力します。
詳細のAIモデルにtext-embedding-granite-embedding-278m-multilingual@q8_0を設定します。
以上の設定を行い、接続のテストをクリックします。接続に成功することを確認し、作成をクリックします。
残念ながら不具合があり(APEX 24.2.3では修正されていません)、ベースURLはhttp://またはhttps://で始まる必要があります、というエラーが発生します。そのため、ベクトル・プロバイダを作成できません。
ワークアラウンドとして、
生成AIサービスの代わりに
カスタムPL/SQLとして等価なベクトル・プロバイダを作成します。
以下のファンクションGENERATE_EMBEDDINGを作成します。
先ほどと同じ手順でベクトル・プロバイダの作成まで進みます。
プロバイダ・タイプにカスタムPL/SQLを選択します。名前はLocal Granite 278m、静的IDはLOCAL_GRANITE_278Mとし、ローカル埋込みのカスタム・ファンクション名にGENERATE_EMBEDDINGを指定します。
以上を設定し作成をクリックします。
ベクトル・プロバイダとしてLocal Granite 278mが作成できました。
これから表JLAW_LAW_SENTENCESの列"Sentence"からベクトル表現を生成し、列SENTENCE_VECTORに保存します。
その前に、管理サービスのインスタンス管理のセキュリティに設定されている最大Webサービス・リクエストの上限を確認しておきます。embeddingを生成するために、大量のAPIリクエストが発行される可能性があります。リクエスト数の制限にかからないように設定を変更しておきます。
この上限値はワークスペース単位でも設定できます。ワークスペース単位で制限している場合は、そちらも確認する必要があります。
ベクトル表現の更新には時間がかかるため、APEXのワークスペース・スキーマにsqlplusまたはSQLclといったコマンドライン・ツールで直接データベースに接続し、以下のスクリプトを実行します。APEXセッションを開始するためのアプリケーションIDなどは、対象のAPEXのワークスペースに存在する値に変更します。
% sql wksp_apexdev/******@localhost/freepdb1
SQLcl: 金 3月 14 18:32:07 2025のリリース24.4 Production
Copyright (c) 1982, 2025, Oracle. All rights reserved.
接続先:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.6.0.24.10
SQL> set serveroutput on
SQL> declare
2 l_vector vector;
3 begin
4 /*
5 * ベクトル・プロバイダがあるワークスペースにある
6 * アプリケーションであればなんでも良い。ユーザーも
7 * 存在しているユーザーであれば良い。
8 */
9 apex_session.create_session(
10 p_app_id => 100
11 ,p_page_id => 1
12 ,p_username => 'ADMIN'
13 );
14 for c in (
15 select sid, "Sentence" from jlaw_law_sentences
16 where sentence_vector is null
17 order by sid
18 -- fetch first 10 rows only
19 )
20 loop
21 begin
22 l_vector := apex_ai.get_vector_embeddings(
23 p_value => c."Sentence"
24 ,p_service_static_id => 'LOCAL_GRANITE_278M'
25 );
26 -- l_vector := generate_embedding(c."Sentence");
27 update jlaw_law_sentences set sentence_vector = l_vector where sid = c.sid;
28 exception
29 when others then
30 dbms_output.put_line('sid = ' || c.sid);
31 raise;
32 -- null;
33 end;
34 commit;
35 end loop;
36 apex_session.delete_session;
37 end;
38* /
PL/SQLプロシージャが正常に完了しました。
SQL>
使用しているembeddingモデルtext-embedding-granite-embedding-278m-multilingual@q8_0の最大コンテキスト長は512ですが、列"Sentence"にはそれを超える長さの条文が含まれます。そのため、生成されているembeddingは精度が高いとは言えません。今回の目的はAPEXの検索構成の確認なので、そのままにしています。(Ollamaでエラーが発生するのは、おそらくコンテキスト長を超える文字列を与えていることが理由と思われます。)
列SENTENCE_VECTORにnullがなければ、すべての行で列"Sentence"のベクトル表現が生成されています。
select count(*) from jlaw_law_sentences where sentence_vector is null;
SQL> select count(*) from jlaw_law_sentences where sentence_vector is null;
COUNT(*)
___________
0
SQL>
表に保存されているデータから一気にembeddingを生成する際は、ベクトル・プロバイダを指定してAPEX_AI.GET_VECTOR_EMBEDDINGSを呼び出す必要はあまりありません。OpenAIやCohereなどのサービスは1回のAPIリクエストで複数のembeddingを生成できます。また、OpenAIではBatch APIを呼び出すことにより、低コストでembeddingを生成できます。
ベクトル・プロバイダはこれから作成する検索構成で使用します。ベクトル検索では、検索フィールドに入力した文字列のベクトル表現を取り出す必要があります。APEXの検索構成では、この処理を行なう設定としてベクトル・プロバイダを使います。
以上で、APEXアプリケーションを作成する準備は完了しました。
空のAPEXアプリケーションを作成します。名前はe-Gov法令検索とします。
アプリケーションが作成されます。共有コンポーネントを開きます。
構成の検索を開きます。これは、検索構成のことです。
作成をクリックします。
最初に検索タイプが Oracleベクトル検索の検索構成を作成します。名前はe-Gov法令ベクトル検索とします。
次へ進みます。
ベクトル・プロバイダにLocal Granite 278m、表/ビューの名前にJLAW_LAW_SENTENCESを選択します。
次へ進みます。
主キー列はSID(Number)、ベクトル列はSENTENCE_VECTOR(Vector)、タイトル列はLawTitle(Varchar2)、説明列はSentence(Clob)とします。アイコン・ソースはイニシャルとします。
検索構成の作成をクリックします。
検索タイプがOracleベクトル検索の検索構成が作成されます。
設定の静的IDをLAW_VECTORとしておきます。ベクトル属性の検索タイプがデフォルトでExact、距離メトリックがCosineになっています。ベクトル索引を作成している場合は、検索タイプとしてApproximateを選択できます。
列のマッピングのカスタム列1にSectionTitle(Varchar2)、カスタム列2にSubsectionTitle(Varchar2)、カスタム列3にArticleTitle(Varchar2)を設定します。
アイコンと表示のデフォルト結果行テンプレートや結果のCSSクラスを設定することにより、検索結果の表示をカスタマイズできます。
同じ手順で、検索タイプがOracle Textの検索構成を作成します。名前はe-Gov法令テキスト検索とします。
次へ進みます。
ソースの
表/ビューの名前に
JLAW_LAW_SENTENCESを選択します。
次へ進みます。
列のマッピングは
ベクトル列の指定が
Oracle Text索引列の指定に変わります。
Oracle Text索引列は
Sentence(Clob)です。
検索構成の作成をクリックします。
検索タイプがOracle Textの検索構成が作成されます。静的IDにLAW_TEXTを設定します。
列のマッピングのカスタム列1、2、3をベクトル検索の検索構成と同じ設定にします。そして、アイコンと表示のアイコン・ソースは- アイコンなし -に変更し、ベクトル検索の検索結果とOracle Textの検索結果で、見分けがつくような表示にします。
以上で検索構成の作成は完了です。
検索ページを作成します。
ページの作成をクリックします。
検索ページを選択します。
作成するページの
名前は
e-Gov法令検索とします。
構成の検索の
E-Gov法令テキスト検索と
E-Gov法令ベクトル検索の双方を
チェックします。
以上で
ページの作成をクリックします。
検索ページが作成されます。
ページを少しだけカスタマイズします。今回は記事はベクトル検索がテーマなので、ソースの検索にある、E-Gov法令ベクトル検索をE-Gov法令テキスト検索の上に移動します。また、両方とも外観の最大結果数を5に限定します。
以上でAPEXアプリケーションは完成です。
アプリケーションを実行すると、記事の先頭にあるような検索を実行できます。
今回の記事で作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/e-gov-law-search.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完