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_DOCUMENTSCDS_ATTACHMENTSを探してチェックを入れます。

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


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


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


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

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


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

アプリケーションを実行し管理画面を開くと、表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静的IDcontent-textと設定します。列のマッピングカスタム列1URL(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静的IDcode-textと設定します。列のマッピングカスタム列1URL(Varchar2)、カスタム列2RAW_URL(Varchar2)を選択します。

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


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

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

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


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


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

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


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

構成の検索としてコード検索 - 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のときと同じです。


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

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


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


作成された検索構成コード検索 - 標準設定検索問合せ接頭辞静的IDcodeとします。ソース検索可能列として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のアプリケーション作成の参考になれば幸いです。