2021年7月8日木曜日

全国医療機関の医療体制の状況をオープンデータをもとに地図上に表示する

 政府CIOポータルより新型コロナウイルス感染症対策関連:全国医療機関の医療体制の状況(G-MISデータ)が、オープンデータとして公開されています。このデータをもとに、Oracle APEXのマップ・リージョンに医療機関の位置と状況を表示させてみました。

オープンデータの仕様はこちらに解説されています。

https://corona.go.jp/dashboard/#opendata

指定した日付以降を取得するデータの対象にできること、都道府県名による絞り込みができること、また、全国地方公共団体コード(6桁)による絞り込みができます。

https://opendata.corona.go.jp/api/covid19DailySurvey/日付?prefName=都道府県名

https://opendata.corona.go.jp/api/covid19DailySurvey/日付?localGovCode=全国地方公共団体コード

それぞれの検索条件の指定は任意です。検索条件がない場合、全件が対象(24,903件 - 2021年7月7日時点)になります。返されるデータの形式はJSONです。

マップに医療体制の状況を表示するために、以下の順番で作業を進めます。

  1. 医療体制の状況を参照するRESTデータ・ソースを作成する。
  2. RESTデータ・ソースをソースとしたレポートのページを作成する。
  3. RESTデータ・ソースから取得したデータを保存する表を作成する。
  4. RESTデータ・ソースとローカル表を同期させる。
  5. ローカル表より、マップ・リージョンを含むページを作成する。


アプリケーションを作成する


今回の一連の作業を行うアプリケーションを、新規に作成します。アプリケーション作成ウィザードを起動します。アプリケーション・ビルダーを開いて、作成を実行します。


新規アプリケーションをクリックします。


アプリケーションの名前医療提供体制の状況とします。それ以外の追加設定は行わず、空のアプリケーションを作ります。アプリケーションの作成をクリックします。


アプリケーションが出来上がりました。



RESTデータ・ソースを作成する


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


データ・ソースのグループにRESTデータ・ソースが含まれます。これを開きます。


作成済みのRESTデータ・ソースが一覧されます。アプリケーションを作成した直後なので、RESTデータ・ソースは1件もリストされません。作成をクリックして、新規作成を開始します。


RESTデータ・ソースの作成最初から実施します。へ進みます。


オープンデータを提供しているエンドポイントを指定します。RESTデータ・ソース・タイプ簡易HTTPを選択します。名前covid19DailySurveyとします。この名前よりデフォルトの静的IDが導出されます。英数字で指定しておくと、後で静的IDの修正が不要になります。
URLエンドポイントとして、検索パラメータの指定を含めた、実際にデータが返されるURLを指定します。

今回は以下のURLを指定しました。

https://opendata.corona.go.jp/api/covid19DailySurvey/20210701?localGovCode=131016

列の情報は、上記のURLより返されたデータを解析して得られます。そのため、ある程度のデータが返される必要があります。

HTTPSホスト名の指定は不要です。へ進みます。


リモート・サーバーベースURLおよびサービスURLパスの確認画面が表示されます。通常は自動検出された情報を訂正する必要はありません。確認だけして、へ進みます。


認証は不要なので、認証が必要ですOFFにします。検出をクリックします。


取得したデータのプレビューが表示されます。


データ・プロファイルも確認してみます。FACILITYIDFACILITYCODENUMBERとして認識されていますが、全件を対象とすると数値以外もあります。ここで認識されたデータ型はRESTデータ・ソース作成後に修正できます。

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


RESTデータ・ソースが作成されました。これからRESTデータ・ソースに必要な修正を加えていきます。RESTソース名covid19DailySurveyをクリックして開きます。


最初にRESTデータ・ソースに3つの絞り込み条件を定義します。指定した日付以降を対象としるsince、都道府県名のprefName、全国地方公共団体コードのlocalGovCodeです。

URLパス接頭辞を20210701から:sinceへ変更します。


パラメータlocalGovCodeを開き、として設定されている131016を削除して無指定に変更します。詳細値が空の場合に省略ONに変更します。RESTデータ・ソースの呼び出し時にlocalGovCodeの指定がなければ、URLにlocalGovCode=といった指定自体を含めません。

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


localGovCodeの修正は完了です。続いて、パラメータの追加をクリックします。


パラメータタイプ問合せ文字列変数とし、名前をprefNameとします。都道府県名をデータ取得の条件とするパラメータです。詳細値が空の場合に省略ONにします。追加後、さらに追加をクリックします。


パラメータのタイプURLパターン変数とし、名前sinceとします。

パラメータの追加をクリックします。


パラメータが3つ作成され、すべて目的入力、デフォルト値なし必須いいえであることを確認します。URLパス接頭辞:sinceに変更し、変更の適用を行います。


データ・プロファイルの修正は後ほど実施することにします。まずは作成したRESTデータ・ソースソースとする、対話モード・レポートを作成してみます。


対話モード・レポートのページを作成する


ページ作成ウィザードを起動します。ページの作成をクリックします。


ページ・タイプとしてコンポーネントを選び、レポートをクリックします。


対話モード・レポートをクリックします。


ページ名医療提供状況詳細とし、へ進みます。


ナビゲーションのプリファレンスとして新規ナビゲーション・メニュー・エントリの作成を選択し、へ進みます。


データ・ソースとしてRESTデータ・ソースを選択し、RESTデータ・ソースとしてcovid19DailySurveyを選択します。作成をクリックします。


ページが作成されます。ページを実行し、レポートを表示させてみます。


サインインの画面が表示されます。ワークスペースにサインインしたユーザー名をパスワードにて、アプリケーションにサインインします。

レポートが表示されるまでに、数十秒程度の時間がかかるはずです。


次のページを表示させます。レポートの下に表示されているページめくりのボタンをクリックします。


次ページを開くのにも数十秒程度の時間がかかります。実際に発行されているRESTサービスの呼び出しを確認してみます。SQLワークショップのSQLコマンドを開き、以下のSELECT文を実行します。

select URL, HTTP_METHOD,STATUS_CODE, RESP_CONTENT_LENGTH, ELAPSED_SEC, REQUEST_DATE
from apex_webservice_log order by request_date desc

Oracle APEXのAPIを経由したRESTサービスの呼び出し履歴は、ビューAPEX_WEBSERVICE_LOGから確認できます。


直近のログを見ると、単にページ送りであっても毎回RESTサービスが呼び出されていることが確認できます。これら呼び出しでは、パラメータは与えられていないため、8.3MBにおよぶデータを毎回読み出しています

この状況は実用的ではなく、また、公共の資源の無駄遣いにもなります。

2つの対策を取ることができます。RESTサービスの呼び出し時にパラメータの指定を必須とすること、または、取得したデータをローカルの表に保存することです。


RESTデータ・ソースの呼び出しにパラメータを与える


対話モード・レポートのページを、ページ・デザイナにて開きます。

Content Bodyの上でコンテキスト・メニューを開き、リージョンの作成を実行します。対話モード・レポートのリージョンの上に配置します。名前検索条件とします。タイプ静的コンテンツです。


作成したリージョンに、RESTデータ・ソースへのパラメータとなるページ・アイテムを作成します。

ページ・アイテムの作成を実行します。識別名前P2_SINCEタイプ日付ピッカーとします。ラベルこの日以降とし、外観書式マスクYYYYMMDDを指定します。


ページ・アイテムP2_PREF_NAMEを作成します。タイプテキスト・フィールドです。ラベル都道府県とし、レイアウト新規行の開始OFFにします。P2_SINCEの右隣にページ・アイテムが配置されます。


ページ・アイテムP2_LOCAL_GOV_CODEを作成します。タイプテキスト・フィールドです。ラベル全国地方公共団体コードとし、レイアウト新規行の開始OFFにします。


ページ・アイテムに指定した値でRESTデータ・サービスの呼び出しが行われるよう、送信ボタンを作成します。

リージョン検索条件にてコンテキスト・メニューを表示させ、ボタンの作成を実行します。識別ボタン名B_SUBMITとし、ラベル送信とします。


都道府県名もしくは全国地方公共団体コードのどちらかの指定がないと、対話モード・レポートを表示しない(つまり、RESTデータ・ソースの呼び出しを行わない - 全件でのデータ取得を抑制する)よう、サーバー側の条件を設定します。

リージョンの医療提供状況詳細を選択し、サーバー側の条件タイプ言語SQLSQL式として以下を指定します。

:P2_PREF_NAME is not null or :P2_LOCAL_GOV_CODE is not null


ページ・アイテムの入力値がRESTサービスの呼び出しに使われるよう、リージョンのパラメータをそれぞれ設定します。

パラメータlocalGovCodeを選択し、タイプアイテムアイテムとしてP2_LOCAL_GOV_NAMEを選択します。


パラメータprefNameタイプアイテムアイテムにはP2_PREF_NAMEを指定します。


パラメータsinceタイプアイテムアイテムにはP2_SINCEを指定します。


以上で対話モード・レポートでのRESTデータ・ソースの呼び出しで、パラメータの指定を必須とする設定が完了しました。ページを実行し、結果を確認してみます。

検索条件がないと、対話モード・レポート自体が表示されません。


全国地方公共団体コードとして012106を指定し、送信をクリックします。北海道岩見沢市の医療機関のみが一覧されます。


地域を限定してデータを取得するようになりましたが、レポートが表示されるたびにRESTサービスの呼び出しが行われている状況は変わりません。

次にローカル表を使うことにより、RESTサービスの呼び出しを抑制します。

ローカル表と同期させる


RESTデータ・ソースcovid19DailySurveyを開き、データ・プロファイルの編集を行います。


全部で14列あるデータの定義を変更します。それぞれの列の左端にある鉛筆アイコンをクリックします。


名前ANSTYPEの列は、以下のように変更します。同期表はあらかじめ作成することもできますが、今回はデータ・プロファイルの設定をもとに自動生成させます。

名前ANS_TYPEに変更します。これが同期表の列名になります。主キーOFFフィルタ可能OFFにします。表示可能ONです。データ型Varchar2最大長16に変更します。

以上の変更を行なって、変更の適用をクリックします。


ANSTYPEも含めて、以下の指定にて列のデータ・プロファイルを変更します。主キーとなるのはFACILITY_IDFACILITY_TYPEフィルタ可能はすべてOFFです。


データ・プロファイルの設定後、同期化の管理を呼び出します。


同期先として新規表を選び、表名としてC19_MEDICAL_FACILITY_STATUSESを入力します。保存をクリックします。


REST同期化のページが開きます。同期化表が存在しません。とメッセージが表示されています。SQLを表示して内容を確認し、表の作成を実行します。


C19_MEDICAL_FACILITY_STATUSESを生成するDDLとして、以下が実行されます。

create table "C19_MEDICAL_FACILITY_STATUSES"(
"ANS_TYPE" VARCHAR2(16)
,"ZIP_CODE" VARCHAR2(12)
,"CITY_NAME" VARCHAR2(40)
,"LATITUDE" NUMBER
,"PREF_NAME" VARCHAR2(20)
,"LONGITUDE" NUMBER
,"FACILITY_ID" VARCHAR2(16)
,"SUBMIT_DATE" DATE
,"FACILITY_TEL" VARCHAR2(16)
,"FACILITY_ADDR" VARCHAR2(255)
,"FACILITY_CODE" VARCHAR2(16)
,"FACILITY_NAME" VARCHAR2(255)
,"FACILITY_TYPE" VARCHAR2(16)
,"LOCAL_GOV_CODE" VARCHAR2(6)
,"APEX$SYNC_STEP_STATIC_ID" VARCHAR2(255)
,"APEX$ROW_SYNC_TIMESTAMP" TIMESTAMP WITH TIME ZONE
,constraint "C19_MEDICAL_FACILITY_STATUSES_PK" primary key ("FACILITY_ID","FACILITY_TYPE"))
/

データ・プロファイルとしてFACILITY_IDFACILITY_TYPEに主キーを設定しています。そのため、同期タイプマージを選択することができます。同期タイプを変更して、保存して実行をクリックします。


ステップを設定していないため、パラメータsince、prefName、localGovCodeのすべてが無指定でRESTサービスの呼び出しが行われます。結果としてすべてのデータが取得され、表C19_MEDICAL_FACILITY_STATUSESへ保存されまます。


表示上の問題ですが、上記のページは同期化の処理が完了していても、ジョブのステータス実行中のままで更新されません。この表示は気にせず、作業を続けます。

通常は同期スケジュールを設定し、ローカル表との同期化処理を定期的に実行させるようにします。また、ステップの追加を行うとsince、prefNameおよびlocalGovCodeといったパラメータを指定することができます。


RESTデータ・ソースの一覧より、同期化済の表示を確認します。はいであれば同期化は完了しています。表C19_MEDICAL_FACILITY_STATUSESにRESTサービスを呼び出して取得したデータが保存されています。


表C19_MEDICAL_FACILITY_STATUSESの内容を最新に保つには、定期的にRESTデータ・ソースの同期化を実行する必要があります。定期的な同期化については、本記事では実装しません。

対話モード・レポートで同期化表を使用する


対話モード・レポートのリージョンを選択し、ソース同期化表の使用ONに変更します。変更後、保存をクリックします。


同期化表では列の名前が変更されているため(例えばANSTYPEはANS_TYPEへ変更)、列の同期化を実行します。


列の同期化を実行するとなぜか同期表の使用がOFFに戻ります。これは再度ONへ変更します。変更したら保存をクリックします。


ローカル表にたいして検索条件のページ・アイテムが有効になるよう、ローカル後処理タイプWHERE/ORDER BY句に変更し、以下の条件を設定します。

(:P2_SINCE is null or submit_date >= :P2_SINCE)
and
(:P2_PREF_NAME is null or pref_name = :P2_PREF_NAME)
and
(:P2_LOCAL_GOV_CODE is null or local_gov_code = :P2_LOCAL_GOV_CODE)


ローカル表であれば、対話モード・レポートの機能でフィルタできます。そのため、このような検索条件自体、不要になっています。検索条件のリージョンを非表示にしても良いでしょう。

ページを実行してみます。レポートの表示やページの移動など、ストレスなく実行できます。



地図上に医療機関を表示する


オープンデータには医療機関の位置を示す緯度経度が含まれています。この位置情報を使って、医療機関をマップ上に表示します。

ページ作成ウィザードを起動します。ページの作成を実行します


ページ・タイプとしてコンポーネントを選択し、マップをクリックします。


ページ名医療機関とし、へ進みます。


ナビゲーションのプリファレンスとして、新規ナビゲーション・メニュー・エントリの作成を選択し、へ進みます。


データ・ソースとしてローカル・データベースを選択し、ソース・タイプ表/ビューの名前として同期化表であるC19_MEDICAL_FACILITY_STATUSESを直接指定します。RESTデータ・ソースのcovid19DailySurveyを指定することも可能ですが、公共のサイトに不必要な負荷をかけることになります。できるだけ同期化表を使いましょう。(対話モード・レポートと同様に、タイプとしてRESTデータ・ソースを選択し、同期化表の使用をONにする方法もあります。)


レイヤーを定義します。マップ上にポイントとして医療機関を表示させます。ジオメトリ列タイプとして、2つの数値列を選択します。経度にはLONGITUDE (Number)緯度にはLATITUDE (Number)ツールチップ列にはFACILITY_NAME (Varchar2)を指定します。ファセット検索ページの作成ONにし、作成をクリックします。


ページが作成されたら、実行して確認します。マップ上に医療機関の位置が表示されていることが確認できます。これから表示を調整していきます。


最初にファセットを作成します。左ペインのレンダリング・ツリーにあるファセット上でコンテキスト・メニューを表示させ、ファセットの作成を実行します。

識別名前P4_FACILITY_TYPEタイプチェック・ボックス・グループとします。ラベル医療機関のタイプとします。LOVタイプとして個別値を選択します。


ページを実行します。医療機関のタイプとして入院外来救急を選択できるようになっています。


医療提供状況別にポイントを色分けして表示します。

レイヤーの医療機関を選択します。識別名前通常に変更します。行割当てANS_TYPEを選択し、このレイヤーの値通常にします。外観塗りつぶしの色緑(#00ff00)を指定します。 


上で作成したレイヤーを重複させます。名前制限行割当てこのレイヤーの値制限外観塗りつぶしの色黄色(#ffff00)を指定します。


同様にレイヤーを重複させます。名前停止行割当てこのレイヤーの値停止外観塗りつぶしの色は赤(#ff0000)を指定します。


レイヤーを重複させます。名前設置なし行割当てこのレイヤーの値設置なし外観塗りつぶしの色明るい灰色(#c0c0c0)を指定します。


最後です。レイヤーを重複させ、名前未回答行割当てこのレイヤーの値未回答外観塗りつぶしの色暗い灰色(#808080)を指定します。


 以上で医療提供状況を色分けして表示する設定ができました。ページを実行して確認してみます。


ポイントのツールチップに医療機関の名前でけでなく、住所などのその他の情報も表示されるように変更します。レイヤーのツールチップ拡張フォーマットONに変更し、HTML式として以下を指定します。

<b>&FACILITY_NAME.</b>
<br>郵便番号: &ZIP_CODE.
<br>住所: &FACILITY_ADDR.
<table><tr><th>医療区分</th><th>医療提供状況</th></tr>
<tr><td>&FACILITY_TYPE.</td><td>&ANS_TYPE.</td></tr>
</table>


5つのレイヤーそれぞれに同じ設定を行います。政府CIOポータルでは、ひとつの医療機関のポイントがひとつであるため、ツールチップに医療区分(外来、入院、救急)がまとまって表示されています。今回行なっている実装は医療区分でポイントは別になっているため(重なって表示される)、ツールチップの表示は若干異なります。


それぞれの医療機関のタイプ別に、地図上に表示するマーカーを変更します。マップソースタイプSQL問合せに変更し、SQL問合せとして以下のSELECT文を指定します。

select ANS_TYPE,
ZIP_CODE,
CITY_NAME,
LATITUDE,
PREF_NAME,
LONGITUDE,
FACILITY_ID,
SUBMIT_DATE,
FACILITY_TEL,
FACILITY_ADDR,
FACILITY_CODE,
FACILITY_NAME,
FACILITY_TYPE,
LOCAL_GOV_CODE,
case facility_type
when '入院' then
'fa fa-hospital-o'
when '救急' then
'fa fa-ambulance'
when '外来' then
'fa fa-medication'
else
'fa fa-map-marker'
end facility_icon,
APEX$SYNC_STEP_STATIC_ID,
APEX$ROW_SYNC_TIMESTAMP
from C19_MEDICAL_FACILITY_STATUSES

FACILITY_ICONを追加しています。入院fa-hospital-o救急fa-ambulance外来fa-medication、それ以外にはfa-map-markerというアイコンでポイントを表示させます。

ソースを変更すると列のマッピングが無効になるため、再設定が必要です。作成済みの5つのレイヤーをすべて選択します。すべてのレイヤーの列のマッピングジオメトリ列のデータ型経度/緯度経度列LONGITUDE緯度列LATITUDEを指定します。ポイント・オブジェクトスタイルアイコンを選択し、アイコン・ソースとしてアイコン・クラス列アイコン列FACILITY_ICONを選択します。


最後にマップ・リージョンのAttributesの設定変更を行います。コントロールオプションの、ブラウザの位置の取得円形ツール距離ツールにチェックを入れます。また、初期位置およびズームブラウザから位置を取得ONに変更します。


位置情報を取得するには、ブラウザが動作している機器上で許可する必要があります。

以上の設定を行なったのち、ページを表示してみます。


一番最初のアクセスでは、現在位置を中心としてマップが表示されます。

オプションで許可をした、現在位置へ移動する機能、距離を測る機能、地図上で領域を円で選択するツールなどが利用可能になっています。

ここまでの実装では、地図上に表示されるかされないかに関わらず、マップ・リージョンまたはレイヤーのソースとして選択された(SELECT文の結果として返される)ポイントはすべて、マップ・リージョンのコンポーネントに取り込まれます。そのため、一部の領域しか表示しない場合がパフォーマンス面で不利になります。

マップ・リージョンのサンプルには色々な動的アクションが含まれています。それらを活用することにより、マップ・リージョンをもっと使いやすくできます。サンプル・アプリケーションのインストールと確認をお勧めします。

以上で今回の記事は完了です。

RESTデータ・ソースの同期化の定期実行、および、マップ・リージョンの活用については別の機会にまとめてみようと思います。

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

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