2022年9月6日火曜日

Autonomous DatabaseでのSEM_MATCH関数の動作を確認する

 Autonomous Databaseでデータベース組み込みのJavaVMが使えるようになりました。今まではSEM_MATCH関数を使うことができなかったので、JavaVMを有効にして動作を確認してみます。

確認作業として、以前の記事「Oracle APEXよりGraphの機能を呼び出してみる」に記載している作業をやり直してみます。以下の一連のコマンドを実行します。

最初にネットワークNET1を作成します。

次にモデルM1を作成します。

作成したモデルM1を確認します。


データを1行挿入します。


SEM_MATCH関数を含んだ問合せを発行します。Autonomous DatabaseではJavaVMが使えないためエラーが発生します。

ORA-13199: JAVAVM is not installed

※) SEM_MATCH関数の引数network_ownerとしてsys_context('USERENV','current_schema')を指定すると以下のエラーが発生するため、APEXのワークスペース・スキーマ名を直接指定します。

ORA-20000: Unable to read model M1 info from "MDSYS".rdf_model$ ORA-00942: 表またはビューが存在しません。


Autonomous DatabaseのJavaVMを有効にします。マニュアルの以下の記載に従います。

BEGIN
   DBMS_CLOUD_ADMIN.ENABLE_FEATURE(
       feature_name => 'JAVAVM' );
END;
/
データベース・アクションにユーザーADMINで接続して、上記のSQLを実行します。JAVAVMを有効化した後、Autonomous Databaseの再起動を行います。


マニュアルのNotes for Oracle Java on Autonomous Databaseに、一旦JAVAVMを有効化すると無効にはできない、また、メンテナンス時にはJavaの機能が使えなくなる、との注意書きがあります。

During the maintenance window, during the Java patching phase there would be no response for Java session calls or you would see an ORA-29548 error. After the maintenance window completes, Java usage is restored.

JavaVMを使うとAutonomous Databaseの可用性は低くなるため、必要なときに限り(例えば今回のようにSEM_MATCH関数を使いたいなど)JAVAVMを有効化するのが良いでしょう。

JavaVMを有効化した後、再度SEM_MATCH関数を含んだ問合せを発行します。

今度は検索結果が返されます。SEM_MATCH関数が使えるようになりました。


SEM_APIS.SPARQL_TO_SQLも実行してみます。こちらも結果が返ってきます。


以前の記事で作成したAPEXアプリケーションRDF Graphも変更します。

ページ・デザイナでページ番号1の対話モード・レポートのページを開きます。

ページ・アイテムP1_SPARQLとして、SPARQLの問合せ文を入力するテキスト・フィールドを作成します。


対話モード・レポートのソースのタイプをSQL問合せを返すファンクション本体に変更し、ファンクション本体として以下を記述します。


SEM_MATCH関数の引数queryにバインド変数を割り当てることができなかったため(およびnvlやcoalesce関数でバインド変数がNULLのときに固定したSPARQL文を割り当てることができなかった)、SEM_APIS.SPARQL_TO_SQLを代わりに使用しています。

送信するページ・アイテムとしてP1_SPARQLを指定します。


ページ・アイテムP1_SPARQLに入力したSPARQL問合せを実行するボタンを作成します。

識別のボタン名はB_SUBMIT、ラベルを送信とします。レイアウトのリージョンとしてRDF Graph、位置としてNextを選択します。ブレッドカラムの右端にボタンが配置されます。動作のアクションは、デフォルトのページの送信から変更しません。


以上で完成です。対話モード・レポートのソースが評価される際に、SPARQLとして以下を与えています。

SELECT ?s ?p ?o WHERE { ?s ?p ?o }

そのため、レポート列として?s ?p ?o(主語、述語、目的語)に関連する列が認識されています。P1_SPARQLとして与えるSPARQLの問合せ文の検索結果を?s ?p ?oから変更すると、認識済みの列と一致しなくなります。そのため変更できるのは検索条件のみになります。


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

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

完

2022年9月5日月曜日

APEXアプリに埋め込む画像をオブジェクト・ストレージに配置する

 CKEditor5(リッチ・テキスト・エディタ)に表示する画像をオブジェクト・ストレージに配置し、事前認証リクエストを使って参照する実装について記事(CKEditor5による画像アップロードを実装する(4) - 画像をオブジェクト・ストレージに保存する)を書いています。

カード・リージョンやレポートに画像を表示する方がリッチ・テキスト・エディタに画像を埋め込むより用途としては多いはずなので、カードに表示する画像をオブジェクト・ストレージに配置するような実装を試してみました。


特にカード・リージョンで画像を表示する際に問題になりますが、データベースから画像をダウンロードさせると、アクティブなセッションをひとつ使います。イメージのサイズが大きいとダウンロードに時間がかかり、セッションの占有時間が伸びます。カード・リージョンでは複数のカードが一度に表示されます。また、同じカード・リージョンのページを開いているユーザーが複数いる場合、それだけでアクティブ・セッションの上限に達してしまい、他の操作ができなくなる可能性があります。画像のダウンロードをオブジェクト・ストレージから直接行うことにより、データベースのアクティブ・セッションの数を減らすことができます。

SQLワークショップのユーティリティのクイックSQLを使って、使用する表を作成します。

以下のモデルから、表IMG_ITEMS、IMG_IMAGESを作成します。

# prefix: img
# pk: guid
# ondelete: set null
items
    name vc80 /nn

images
    item_id /fk items
    location vc400 /nn
    file_name vc80
    mime_type vc200
    last_updated date /nn
SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次実施します。表の作成までを実施し、アプリケーションの作成は行いません。
 

アプリケーション作成ウィザードを起動します。

アプリケーションの名前は画像ビューワーとします。ホーム・ページの編集を開いて削除し、代わりにファセット検索のページを追加します。


ページ名も画像ビューワーとします。表示形式はレポートを選択します。フォームの画面をウィザードで作成するためにレポートを選んでいます。フォームを含めるにチェックを入れます。アプリケーションの作成後にレポートからカードに変更します。ソースとなる表としてIMG_ITEMSを選択します。

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


以上を設定し、アプリケーションの作成を実行します。

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


オブジェクト・ストレージを扱うための設定を行います。記事CKEditor5による画像アップロードを実装する(4) - 画像をオブジェクト・ストレージに保存するで行なっている準備作業(APEXワークスペース・スキーマへの権限付与、クリデンシャルMY_OCI_CREDの作成、バケットimagesの作成等)は実施済みとします。

 アプリケーション定義の置換として、置換文字列G_REGION、G_NAMESPACE、G_BUCKET、G_CREDENTIALに置換値を設定します。


記事CKEditor5による画像アップロードを実装する(4) - 画像をオブジェクト・ストレージに保存するの事前承認リクエストの発行を参照し、アプリケーション・アイテムG_PREAUTH_URLを作成します。


アプリケーションの計算を作成します。計算として設定するコードは以下です。



レポートのページ(ページ番号1)を開き、リージョンImg Itemsを選択します。

識別のタイプをクラシック・レポートからカードに変更します。ソースのタイプをSQL問合せに変更し、SQL問合せを以下のSELECT文に置き換えます。



リージョンのタイプをカードに変更すると、ボタンCREATEが表示されなくなります。ボタンCREATEを選択し位置をRegion Bodyに変更します。


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

タイトルの列としてNAMEを選択します。メディアのソースとしてURL列、URL列としてLOCATIONを選択します。位置、外観、サイズ指定はデフォルトのまま変更しません。


カードの編集画面を開くため、カード・リージョンImg Itemsにアクションを作成します。

作成したアクションの識別のタイプとしてカード全体を選択します。リンクのタイプとしてこのアプリケーションのページにリダイレクト、ターゲットはページ2とします。


ターゲットをクリックして、リンク・ビルダー・ターゲットを開いて設定します。

ターゲットのページは2を選択します。アイテムの設定の名前としてP2_ID、値として&ID.を設定します。

以上でOKをクリックします。


ページ・デザイナにてページ番号2のフォームのページを開きます。イメージ・ファイルのアップロードを実装します。

Region Bodyにページ・アイテムP2_IMAGEを作成します。

識別の名前をP2_IMAGE、タイプとしてファイル参照...を選択します。ラベルはImageとします。設定の表示形式としてBlock Dropzoneを選択します。

記憶域タイプとしてTable APEX_APPLICATION_TEMP_FILESを選択し、ファイルをパージするタイミングとしてEnd of Requestを選びます。アップロードされたファイルは表APEX_APPLICATION_TEMP_FILESの1行として保存されます。そのファイルは次に作成するプロセスにてオブジェクト・ストレージにアップロードするので、リクエストが終了したら不要になります。そのため、リクエスト終了時にパージする(End of Request)ように設定します。


オブジェクト・ストレージにアップロードするプロセスを作成します。

最初に以下のパッケージIMG_UTILを作成します。


プロセスを作成し、プロセス・フォームImg Itemの下に配置します。識別の名前をオブジェクト・ストレージに保存とします。タイプはAPIの呼出しを選びます。設定にてパッケージIMG_UTILのプロシージャUPLOAD_IMAGEを呼び出すように指定します。


サーバー側の条件のタイプとしてリクエストは値に含まれる、値にCREATE SAVEを指定します。


パラメータはすべてアイテムを割り当てます。それぞれ以下の設定になります。

p_id = P2_ID
p_item_value = P2_IMAGE
p_region = G_REGION
p_namespace = G_NAMESPACE
p_bucket = G_BUCKET
p_credential = G_CREDENTIAL

以上でアプリケーションは完成です。実行すると先頭のGIF動画のような動作をします。

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

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

完

2022年9月2日金曜日

CKEditor5のmention機能を実装してみる

追記: APEX 23.1よりリッチ・テキスト・エディタはCKEditor5からTinyMCEへ置き換えられます。CKEditor5のカスタマイズ方法はTinyMCEには適用できません。

---- 

 Louis Moreauxさんが彼のブログにCKEditor5 mention featureという記事を載せていました。面白い内容だったので、自分でも実装してみました。


日本語環境だとmentionの機能を使った直後のキーボード入力がIMEに渡らないようです。私が使っているMacの問題かもしれませんが、少々残念です。

以下より、上記のサンプル・アプリケーションを作ったときの作業を記述します。今回はテスト・データの生成にOracle APEX 22.1の新機能であるデータ・ジェネレータを使いました。

クイックSQLを使って、ユーザーの一覧を保存する表CKE_USERSを作成します。

SQLワークショップのユーティリティのクイックSQLを開きます。クイックSQLのモデルとして以下を記述します。
# prefix: cke
users
    first_name vc80 /nn
    last_name  vc80 /nn
    email_address vc40
    shortname  vc8 /nn
SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次クリックします。表の作成までを実施し、アプリケーションの作成は行いません。


表CKE_USERSが作成されます。


作成した表CKE_USERSにテスト・データを投入します。

 SQLワークショップのユーティリティのデータ・ジェネレータを開きます。

作成済みのブループリントが一覧されます。生成するテスト・データの定義は、ブループリントというJSON形式のファイルとして保存されます。

ブループリントの作成をクリックします。


ブループリントの作成方法を選択します。今回は先ほど作成した表CKE_USERSを元にブループリントを作成します。

既存の表の使用を選択します。


ブループリント名はCKEditor5 Mention Testとします。表の一覧よりCKE_USERSにチェックを入れます。

以上の設定を行い、ブループリントの作成をクリックします。


ブループリントが作成され、ブループリント・デザイナが開きます。


TablesにあるCKE_USERSを選択し、設定を確認します。

行数が50行になっています。このブループリントを元に生成されるテスト・データは50行です。表の名前として設定されているCKE_USERSに50行のテスト・データが挿入されます。


列IDを選択します。

データ・ソースとして組込み、組込みとしてnumber.guid:NUMBERが設定されています。sys_guid()の結果が列IDのテスト・データとして生成されます。しかし、列IDは自動生成になっており、値を投入すると一意性を担保できなくなります。

列IDをテスト・データ生成の対象から外すため、列の削除を実行します。


列FIRST_NAMEを選択します。データ・ソースは組込み、組込みとしてperson.first_name:VARCHAR2が選択されています。Oracle APEXが事前定義しているperson.first_nameのデータが、テスト・データとして使用されます。現在のところ英語のデータのみで、詳細の言語もen以外は選択できません。最大長は表CKE_USERSの列FIRST_NAMEのサイズを考慮していないようです。表定義に合わせて最大長を80に変更します。


列LAST_NAMEを選択します。こちらも最大長を80に変更します。


列EMAL_ADDRESSを選択します。データ・ソースは組み込み、組み込みとしてperson.email:VARCHAR2が選択されています。列名から推測して、テスト・データが選択されています。必須はOFFにして、パーセント・ブランクを10とします。テスト・データとして50行生成するように設定しているので、そのうちの10%である5行は列EMAIL_ADDRESSがNULLになります。詳細の最大長は40とします。


列SHORTNAMEを選択します。データ・ソースとして式を選択し、式として以下を記述します。

upper(substr({FIRST_NAME},1,1) || substr({LAST_NAME},1,7))

列FIRST_NAMEの先頭1文字と列LAST_NAMEの先頭7文字を連結した、最大8文字の値を列SHORTNAMEとして生成します。


以上でブループリントが作成できました。

データのプレビューをクリックして、生成されるテスト・データを確認します。

列FIRST_NAME、LAST_NAME、EMAIL_ADDRESS、それと式によって定義している列SHORTNAMEも想定したテスト・データになっています。

プレビューを確認した後、データの作成に進みます。


アクションとしてデータベースへの挿入を選択します。生成されたテスト・データは表CKE_USERSへ直接書き込まれます。挿入メソッドは挿入、行スケーリングは1xとします。

アクションとしてファイル・エクスポートを選択すると、JSON、CSVまたはSQLのinsert文としてテスト・データをファイルに出力できます。生成したテスト・データを別のプラットフォームにロードする際に役立つでしょう。

データを挿入を実行します。


テスト・データが挿入されるとダイアログにメッセージが表示されますが、ダイアログは閉じません。続けてデータを挿入を実行すると、さらにテスト・データが挿入されます。今回の例では50行が追加され、100行になります。

テスト・データの作成が終わったら、取消をクリックしてダイアログを閉じます。


SQLワークショップのオブジェクト・ブラウザなどを使用して、表CKE_USERSに投入されたテスト・データを確認します。


表CKE_USERSとテスト・データの準備ができたので、CKEditor5のmentionの機能を使うAPEXアプリケーションを作成します。

アプリケーション作成ウィザードを起動します。

アプリケーションの名前はCKEditor5 mention featureとします。それ以外は変更せず、アプリケーションの作成を実行します。

アプリケーションはすべてホーム・ページに実装します。


アプリケーションが作成されたら、ホーム・ページをページ・デザイナで開きます。


ページ・アイテムP1_TEXTを作成します。このページ・アイテムのタイプをリッチ・テキスト・エディタ(実体はCKEditor5)とし、mentionを使えるようにします。

識別の名前をP1_TEXT、タイプとしてリッチ・テキスト・エディタを選択します。ラベルはTextとします。ソースのタイプはNULL、使用はセッション・ステートの値がNULLの場合のみ、セッション・ステートの保持にセッションごと(ディスク)を選択します。

ページ・アイテムP1_TEXTの値はセッション・ステートにのみ保存し、表やAPEXコレクションは用意しません。


送信ボタンを作成します。

識別のボタン名はB_SUBMIT、ラベルはSubmitとします。動作のアクションとしてページの送信を選択します。

このボタンをクリックすると、ページ・アイテムP1_TEXTの値がセッション・ステートに保存されます。


ページ・アイテムを作成し、mentionとして検索される数の上限を設定します。

識別の名前をP1_LIMIT、タイプとして非表示を選択します。ソースのタイプとして静的値を選択し、静的値に5を指定します。一度に検索されるmentionの上限を5に設定しています。使用はセッション・ステートの値がNULLの場合のみ、セッション・ステートの保持にリクエストごと(メモリーのみ)を選択します。


CKEditor5が発行する検索要求を受け付けて、ユーザーの一覧を返すAjaxコールバックを作成します。

Ajaxコールバックにプロセスを作成します。

識別の名前はGET_USERS、タイプとしてコードを実行を選択します。ソースのPL/SQLコードとして、以下を記述します。




CKEditor5のプラグインmentionを有効にします。

ページ・アイテムP1_TEXTの詳細のJavaScript初期化コードとして、以下を記述します。




初期化コードで呼び出しているファンクションgetUserItems、userItemRendererを、ページ・プロパティのJavaScriptのファンクションおよびグローバル変数の宣言に記述します。



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

アプリケーションを実行すると、記事の先頭にあるGIF動画のような動作をします。

開発者ツール・バーよりセッション・ステートを表示させ、ページ・アイテムP1_TEXTに保存されているHTML文書を確認します。


入力した文字列は以下のようになります。

<div class="ck-content"><p><span class="mention" data-mention="@PMOREL">Parker Morel</span> さんへ、</p><p>mention機能については、 <span class="mention" data-mention="@WPICKENP">Winter Pickenpaugh</span> さんへ、</p></div>

mentionの部分に限ると、以下です。data-mention属性としてAjaxコールバックGET_USERSがidとして返した値、span要素のテキストとしてtextが設定されています。

<span class="mention" data-mention="@PMOREL">Parker Morel</span>

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

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

完