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 TracingURLエンドポイントとして、先ほど作成したRESTサービスのURLを入力します。

へ進みます。


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


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


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

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


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

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


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


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


パラメータのタイプ問合せ文字列変数です。名前はuser_idstart_timeend_timedistancetime_tolerance_in_secchaining_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.として指定します。


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


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