2022年4月26日火曜日

Oracle Spatialのsdo_obj_tracing.get_all_durationsの結果をAPEXで扱う

 Oracle Spatialを使った接触追跡という記事を参照して、この結果をOracle APEXのマップ・リージョンを使って可視化しようとすると、sdo_obj_tracing.get_all_durationsが行を返してくれない、という現象がありました。(2022年5月9日追記 - sdo_obj_tracing.get_all_durationsの引数track_table_nameにスキーマ名を付けることにより、正常に動作します。そのため、RESTサービスよりは表関数で実装する方が効果的でしょう。)

Oracle APEXは少し特殊なSQLの実行方法なので(以前に説明記事を書いています)、おそらくそれが理由だと思われるのですが、Oracle Spatialの接触追跡を使える環境は限られているため、ワークアラウンドを実装してみました。

APEXから呼ぶと行が返されないのですが、RESTサービスとして呼ぶとsdo_obj_tracing.get_all_durationsは行を返します。なので、RESTサービスとして接触追跡を実装します。

Always FreeのAutonomous DatabaseでOracle Database 21cが使えるのは北米のリージョンだけなので、Ashburnでインスタンスを作成しました。APEXのワークスペースはAPEXDEV、Oracle Spatialの記事の作業はSPATIALUSERではなく、APEXのワークスペース・ユーザーとなるAPEXDEVで作業を行なっています。

以下、実装になります。

RESTサービスは、APEXのRESTfulサービスのUIを使って実装しました。

モジュールをcom.oracle.contacttracing、ベース・パスを/contacts/として作成しています。認証による保護は省略しています。

URIテンプレートはtraceとしています。ハンドラはGETだけを作成しています。

GETハンドラを作成します。ソース・タイプをPL/SQLとし、レスポンスはPL/SQLのコードで生成します。

ソースは以下になります。

APEXのアプリケーションからRESTサービスを検出する際に、パラメータを指定できないケースがあります。実行結果が返されないと、想定されるレスポンスを手作業で登録する必要が出てきます。それは避けたいため、パラメータの指定が無い場合に、必ず実行結果が返される値に置き換えています。

URLの問合せ文字列が、ソースで使用しているバインド変数に渡されるよう、パラメータを設定します。user_id、start_time、end_time、distance、time_tolerance_in_sec、chaining_tolerance_in_secをURLの問合せ文字列として受け付けます。


RESTサービスの作成は以上です。

続いて、このRESTサービスを使ったAPEXアプリケーションを作成します。

アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前はContact Tracingとします。


アプリケーションが作成されます。最初にRESTデータ・ソースを作成します。

共有コンポーネントを開きます。


RESTデータ・ソースを開きます。


作成済みのRESTデータ・ソースが一覧されます。作成をクリックします。


RESTデータ・ソースの作成は最初からのままで、次に進みます。


RESTデータ・ソース・タイプは簡易HTTPを選択します。RESTサービス自体はORDSを使って実装していますが、RESTサービスはORDSの機能を使わず、PL/SQLでコーディングしているためです。名前はContact Tracing、URLエンドポイントとして、先ほど作成したRESTサービスのURLを入力します。

次へ進みます。


作成される内容の確認です。リモート・サーバー、ベースURL、サービスURLパスの変更が必要な場合はほぼ無いので、変更せずに次へ進みます。


ページ区切り(ページング)は実装していないので、ページ区切りタイプはページ区切りなしのままで、次へ進みます。


認証は不要なので、認証が必要ですはOFFのままにしておきます。

以上の条件で、検出をクリックします。


RESTサービスのレスポンスが表示されます。APEXのアプリケーションで扱いやすいようにPL/SQLのコードを記述しているので、変更が必要な作業はありません。

RESTデータ・ソースの作成をクリックします。


RESTソースContact Tracingが作成されました。これから、問合せ文字列の設定を追加します。編集のためにContact Tracingを開きます。


RESTデータ・ソースの編集画面から、パラメータの追加を実行します。


パラメータのタイプは問合せ文字列変数です。名前はuser_id、start_time、end_time、distance、time_tolerance_in_sec、chaining_tolerance_in_secの6つです。値はPL/SQLのソースとして設定したデフォルト値と同じにしておきます。目的は入力、静的はOFF、必須をONにします。

追加後、さらに追加をクリックし、パラメータをすべて作成します。


パラメータを作成したら、RESTデータ・ソースの作成は完了です。


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


ホーム・ページに接触追跡の結果を表示するマップ・リージョンを作成します。

その前に、接触追跡の実行での引数になるページ・アイテムを作成します。

リージョンを作成し、識別の名前をパラメータとします。タイプは静的コンテンツです。作成したリージョンに、6つのページ・アイテム、P1_USER_ID、P1_START_TIME、P1_END_TIME、P1_DISTANCE、P1_TIME_TOLERANCE_IN_SEC、P1_CHAINING_TOLERANCE_IN_SECを作成します。


マップ・リージョンを作成します。識別のタイトルをContact Tracing、タイプをマップとします。


レイヤーを選択します。識別の名前を接触、レイヤー・タイプはポイントとします。ソースの位置として、RESTソースを選択し、RESTソースにContact Tracingを選択します。列のマッピングのジオメトリ列のデータ型として、経度/緯度を選択し、経度列にX、緯度列にYを設定します。


パラメータを選択し、値のタイプをアイテムに変更します。アイテムにRESTサービスのパラメータとなるページ・アイテムを選択します。


最後に送信ボタンを作成します。ボタン名をB_SUBMIT、ラベルを送信とします。


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


APEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/rest-contact-tracing.sql

ORDSのRESTサービスのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/ORDS_REST_APEXDEV_com.oracle.contacttracing_2022_04_26.sql

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

追記

RESTサービスが呼び出せることの確認だったので、APEXアプリの見栄えは気にしていなかったのですが、せめてCONTACT_IDで色分けしてみます。

レイヤーを選択して、ローカル後処理のタイプをSQL問合せに変更します。SQL問合せに以下を記述します。
select
    X,
    Y,
    to_char(END_TIME, 'YYYY-MM-DD HH24:MI') end_time,
    CONTACT_ID,
    IN_USER_ID,
    to_char(START_TIME, 'YYYY-MM-DD HH24:MI') start_time,
    OUT_USER_ID,
    NUM_CONTACT_TIMES,
    DURATION_IN_MINUTES,
    case
    when contact_id = 1 then
        'red'
    when contact_id = 2 then
        'green'
    when contact_id = 3 then
        'yellow'
    when contact_id = 4 then
        'blue'
    else
        'black'
    end col
from #APEX$SOURCE_DATA#

色を指定する列COLを追加したので、それを外観の塗りつぶしの色に&COL.として指定します。


結果として、以下のように色付けされます。


色だけでなく、例えばアイコンなども同様の手法で変更することができます。

完