2023年2月7日火曜日

APEX 22.2の検索コンポーネントを使ってコード検索アプリを作成する

 本ブログではGistにコード・スニペットを保存して、記事に貼り付けていることが多いのですが、コード・スニペットを対象とした検索ができなくて困っていました。

APEX 22.2では検索コンポーネントが新規に追加されています。これを使ってコード・スニペットを検索するアプリケーションを作ってみました。

https://apex.oracle.com/pls/apex/r/japancommunity/codesearch/home


作成したアプリケーションを公開するため、今回の作業はapex.oracle.comで実施しています。

検索コンポーネントについては、Oracle APEXのOffice Hourで開発者のCarsten Czarskiさんが解説しています。

Part 2: Marquee Features (APEX 22.2)

YouTubeの動画では、22分頃から解説が始まります。

https://www.youtube.com/watch?v=EEYLgNxx3Wo&t=1320s

今回のアプリケーションですが、クイックSQLの以下のモデルを使って表を作成します。

#prefix: cds
documents
    title vc4000 /nn 
    url vc400
    content clob 
    published date
    updated date

attachments
    post_id /fk documents
    embedded_url vc400
    embedded_content clob 
    raw_url vc400
    raw_content clob 
    embedded_updated date
    raw_updated date

ブログ記事の本文を保存する表CDS_DOCUMENTSに対して、複数のコード(添付ファイル)が表CDS_ATTACHMENTSとして紐づくという構造になっています。一般的によくある構造なので、応用はしやすいと思います。

以下より、アプリケーションを作成する手順を紹介します。

最初に上記のクイックSQLのモデルより、表CDS_DOCUMENTSとCDS_ATTACHMENTSを作成します。

SQLワークショップのユーティリティのクイックSQLを開き、左ペインにモデルを貼り付けます。その後SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次クリックします。


DDLが生成され、レビュー画面が開きます。今回使用する元データに合わせるため、表CDS_DOCUMENTSの主キーの定義を変更します。

表CDS_DOCUMENTSの列IDの型定義は以下に変更します。主キー制約の定義は変更しません。

varchar2(32) default on null rawtohex(sys_guid())

参照制約が定義されているCDS_ATTACHMENTSの列POST_IDの型はvarchar2(32)に変更します。

以上の変更を行い、スクリプトを実行します。


2つの表と参照制約に関係する索引が1つ作成されます。


ここからはアプリケーションの作成は行いません。

アプリケーション作成ウィザードを、アプリケーション・ビルダーから起動します。

アプリケーションの名前はコード検索とします。テストに使用するデータを投入するための画面を、あらかじめアプリケーションに作成します。本題の検索画面は、アプリケーションを作成したのちに作成します。

ページの追加をクリックします。


ページの追加の追加ページを開き、複数のレポートを選択します。


表の選択画面が開きます。表CDS_DOCUMENTS、CDS_ATTACHMENTSを探してチェックを入れます。

ページの追加をクリックします。


それぞれの表について、フォーム付きの対話モード・レポートが追加されます。編集をクリックし、管理ページに切り替えます。


詳細を開き、管理ページとして設定にチェックを入れます。


管理ページに変更すると、編集ボタンの横にあるアイコンがスパナに変わります。

AttachmentsとDocumentsの双方を管理ページに変更し、アプリケーションの作成を実行します。


以上でアプリケーションが作成されます。

アプリケーションを実行し管理画面を開くと、表CDS_DOCUMENTSとCDS_ATTACHMENTSの編集メニューが含まれていることが確認できます。テストに使うデータはこちらから登録できます。

apex.oracle.com上のアプリケーションではこの画面を使わずに、ブログ記事本文を表CDS_DOCUMENTSの列CONTENTに、Gistのスニペットを表CDS_ATTACHMENTSのRAW_CONTENTに投入しています。


表CDS_DOCUMENTSの列CONTENTおよびCDS_ATTACHMENTSの列RAW_CONTENTにOracle Textの全文検索索引を作成します。列CONTENTはレクサーとしてJAPANESE_LEXER、列RAW_CONTENTはコードなのでBASIC_LEXERを使用します。

あらかじめお断りしておきますが、最終的にOracle Text検索は使用しません。コード中のプロシージャ名やファンクション名の検索に向いていないためです。Oracle Textについては、一つの実装例としての紹介になります。

それぞれのレクサーのプレファレンスを、ja_lexerおよびbasic_lexerとして作成します。
begin
  ctx_ddl.create_preference('ja_lexer', 'JAPANESE_LEXER');
  ctx_ddl.create_preference('basic_lexer', 'BASIC_LEXER');
end;
/

表CDS_DOCUMENTSの列CONTENTに、Oracle Text索引CDS_DOCUMENTS_CTX1を作成します。
create index cds_documents_ctx1 on cds_documents(content) 
indextype is ctxsys.context parameters('filter ctxsys.null_filter lexer ja_lexer sync(on commit)');

同様に表CDS_ATTACHMENTSの列RAW_CONTENTに、索引CDS_ATTACHMENTS_CTX1を作成します。
create index cds_attachments_ctx1 on cds_attachments(raw_content)
indextype is ctxsys.context parameters('filter ctxsys.null_filter lexer basic_lexer sync(on commit)');

以上で検索画面を作成する準備ができました。

共有コンポーネントの構成の検索を開きます。(英語だとSearch Configurationsで、これ以外は検索構成と訳されています。)


作成済みの検索構成が一覧されます。作成をクリックします。


検索構成の名前は本文検索 - Oracle Textとします。検索タイプとしてOracle Textを選択します。

次へ進みます。


ソースの表/ビューの名前として、CDS_DOCUMENTSを選択します。

次へ進みます。


主キー列はID(Varchar2)、Oracle Text索引列はCONTEXT(Clob)、タイトル列はTITLE(Varchar2)とします。アイコン・ソースとしてアイコン・クラスを選択し、アイコンCSSクラスとしてfa-file-text-oを指定します。

検索構成の作成をクリックします。


検索構成本文検索 - Oracle Textが作成されます。

設定の検索問合せ接頭辞にcontent-text、静的IDにcontent-textと設定します。列のマッピングのカスタム列1にURL(Varchar2)を選択します。

以上で変更の適用をクリックします。


同様の手順で、表CDS_ATTACHMENTSの検索構成を作成します。

名前はコード検索 - Oracle Textとします。検索タイプにOracle Textを選択します。


親となる表CDS_DOCUMENTSの列を検索結果に含めるため、ソースのソース・タイプとしてSQL問合せを選択し、以下のSQLをSQL SELECT文を入力に記述します。
select a.id, d.title, d.url, a.raw_url, a.raw_content
from cds_documents d join cds_attachments a 
  on d.id = a.post_id

主キー列はID(Number)、Oracle Text索引列はRAW_CONTENT(Clob)、タイトル列はTITLE(Varchar2)とします。アイコン・ソースとしてアイコン・クラスを選択し、アイコンCSSクラスとしてfa-file-text-oを指定します。


検索構成コード検索 - Oracle Textが作成されます。

設定の検索問合せ接頭辞にcode-text、静的IDにcode-textと設定します。列のマッピングのカスタム列1にURL(Varchar2)、カスタム列2にRAW_URL(Varchar2)を選択します。

以上で変更の適用をクリックします。


以上で検索ページに使用する検索構成が作成できました。

検索ページを作成します。このページをホームとするため、作成済みのホーム・ページを削除します。

ページ・デザイナでホーム・ページを開き、ページの削除を実行します。


カスケード削除ははいを選択し、ページを完全に削除を実行します。


ページが削除されたら、代わりになる検索ページを作成します。ページの作成を実行します。

検索ページを選択し、次へ進みます。


ページ番号は1、名前はコード検索とします。ページ・モードは標準です。

構成の検索としてコード検索 - Oracle Text、本文検索 - Oracle Textの双方をチェックします。

以上でページの作成をクリックします。


検索ページが作成されます。

今回はすべて公開されているデータを元にしているため、作成した検索ページの保護をすべて解除します。

識別の別名をhomeに変更します。

セキュリティの認証はパブリック・ページ、ディープ・リンクは有効、ページ・アクセス保護は制限なしとします。セッション管理のセッションを再結合はパブリック・セッションに対して有効に変更します。

変更を保存します。


アプリケーションを実行し、検索ページの動作を確認します。

検索ワードとしてapex_data_exportを入力します。

一件もヒットしません。

検索ワードをapex data exportとすると、複数の検索結果が得られます。


Oracle Textでは単語は_(アンダースコア)で分割されています。そのため、apex_data_exportでは検索にヒットしません。プロシージャ名を検索ワードにしたいので、検索構成を変更します。

検索構成を変更するまえに、2つページの設定を変更します。

リージョン検索結果を選択し、プロパティ・エディタの属性を開きます。

デフォルトでは文字入力の都度、検索が実行されるようになっています。データベースへの負荷を減らすため、設定の入力時に検索をOFFに変更します。


続いて、検索結果として表示されるURLをクリックできるようにします。

設定のカスタム・レイアウトをONにし、結果行テンプレートに以下を書き込みます。

カスタム列1の置換文字列は&CUSTOM_01.、カスタム列2は&CUSTOM_02.です。これらのカスタム列が現れる部分をA要素に変更しています。

結果行テンプレートの記述方法は、結果行テンプレートのオンライン・ヘルプに記載されています。


以上の変更で、検索結果として表示されるURLがクリック可能になります。テンプレート・ディレクティブの使用もできるため、検索結果の見栄えの自由度は高いでしょう。


Oracle Textの検索はコード検索の要件に合わなかったため、検索構成を新規に作成します。

新たに作成する検索構成の名前は本文検索 - 標準とします。検索タイプは標準を選択します。これ以降の指定は、検索タイプがOracle Textのときと同じです。


作成された検索構成本文検索 - 標準の設定の検索問合せ接頭辞、静的IDはcontentとします。ソースの検索可能列としてCONTENT(Clob)を選択します。この列に検索キーワードによるLIKE検索が行われます。

列のマッピングのカスタム列1としてURL(Varchar2)を選択します。


同様に検索構成コード検索 - 標準を作成します。


作成された検索構成コード検索 - 標準の設定の検索問合せ接頭辞、静的IDはcodeとします。ソースの検索可能列としてRAW_CONTENT(Clob)を選択します。

列のマッピングのカスタム列1としてURL(Varchar2)を選択します。カスタム列2としてRAW_URL(Varchar2)を選択します。


以上で、置き換える検索構成が作成されました。

検索ページを開き、ソースの検索のコード検索 - Oracle Textを選択します。

識別の名前をコード検索、検索構成をコード検索 - 標準に変更します。


同様に本文検索 - Oracle Textの識別の名前を本文検索、検索構成を本文検索 - 標準に変更します。


以上でアプリケーションは完成です。

アプリケーションを実行して、apex_data_exportで検索してみます。

記事およびGistのスニペットの内容にapex_data_export(大文字小文字は無視されます)が含まれる記事が一覧されます。


検索構成に検索問合せ接頭辞が設定されています。本文検索 - 標準にはcontentが指定されているため、検索キーワードとしてcontent:apex_data_exportと入力するとブログ記事本文のみが検索対象になります。


この他にもいろいろな機能が、最初に紹介したYouTubeの動画で紹介されています。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/codesearch.zip

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

完