検索

クリアフィルター
記事
Shintaro Kaminaka · 2020年9月11日

IRIS for Health 上でFHIR リポジトリ+OAuth2 認可サーバ/リソースサーバ構成を構築する パート2

開発者の皆さん、こんにちは。 今回の記事では前回の記事に引き続き、IRIS for Health上で、FHIRリポジトリ+OAuth2認可サーバ/リソースサーバを構成する方法をご案内します。 (注意:2020.4以降のバージョンではこの記事に記載されているスコープ指定では正しくリソースが取得できません。詳細はこちらの記事をご覧ください。) パート1では、事前準備と、OAuth2認可サーバを構成し、アクセストークンを取得するとこまでをご紹介しました。このパート2では、FHIRリポジトリの構築方法と、OAuth2クライアント/リソースサーバの構成方法をご紹介していきます。 今日構成する、FHIRリポジトリおよび、OAuth2クライアント/リソースサーバの構成は、前回パート1で構成したOAuth2認可サーバのIRISインスタンスと分けることもできますし、同じインスタンスに同居させることもできます。この記事の中では前回と同じインスタンス上に構成していきます。 FHIRリポジトリの構築とOAuth Client Nameの指定 FHIRリポジトリの構築方法は、過去の記事「Azure上でIRIS for Healthをデプロイし、FHIR リポジトリを構築する方法」で紹介しています。 管理ポータルにアクセスし、ネームスペース/データベースを作成、さらにHealthメニューからFHIRリポジトリを構築する手順はこの記事を参考にして進めてください。この記事の中でもネームスペース/データベース=FHIRSERVER , FHIR endpointを/csp/healthshare/fhirserver/fhir/r4として構成しています。 構築後の以下の画面で、endpoint URL /csp/healthshare/fhirserver/fhir/r4 をクリックして構成画面を開きます。 構成画面で OAuth Client Name を欄に、これから作成するOAuth2クライアントの構成名を入力しておきます。先にOAuth2クライアントを構成している場合はその名前に合わせてください。 ここでは、「FHIRResource」という文字列にしておきます。変更するには上記画面で「Edit」ボタンを押して変更し、「Update」ボタンで保存します。 OAuth2クライアントの構成 次は、OAuth2クライアント構成を作成していきましょう。 管理ポータルのシステム管理→セキュリティ→OAuth2.0 と進み、前回パート1とは異なり、「サーバ」ではなく、「クライアント」を選択します。 次の画面では「サーバの説明を作成」をクリックして、OAuth2認可サーバへ接続するための構成を作成します。 サーバデスクリプション ページで発行者エンドポイントには、パート1で構成した認可サーバのエンドポイントを入力します。 以下はパート1で構成したOAuth2認可サーバの構成画面です。 SSL/TLS構成には、パート1の事前準備で作成した、SSL/TLS構成「SSL4CLIENT]を入力します。 項目を入力したら「発見して保存」を実行して、OAuth2認可サーバから情報を取得します! アクセスに成功すると以下のように取得できた情報が表示されます。パート1事前準備で用意したホスト名を指定したSSL証明書が正しく作成・認識されていない場合、この過程でエラーが発生することがありますので、ご注意ください。 注意:この連載のパート1でDLしたdocker-containerファイルを使っている場合でも、IRISコンテナ→Apacheコンテナへホスト名を指定したアクセスがうまくいかない場合があります。この場合、以下のようにextra_hostsとして、docker-compose.ymlファイルに自分のマシンのホスト名とIPアドレスを入力すると解決できることがあります。 extra_hosts: - <yourhostname>:<your ip address> 「保存」を押して構成を保存すると、以下のページに戻りますので、続いて「クライアント構成」を選択してFHIRリポジトリ用の構成を作成していきます。 OAuth2クライアントにクライアント構成を追加する ややこしいタイトルですが、次は今作成したOAuth2クライアント設定(どのOAuth2認証サーバに接続するかという情報をもつ)に、クライアント構成(OAuth2クライアントとしてOAuth2認可サーバに接続したい、具体的なFHIRリポジトリやCSPアプリケーションなどの情報)を追加します。 次の画面では「クライアントの構成を作成」をクリックして以下の画面を表示し、必要な項目を設定していきます。 最初に、クライアントの種別=リソース・サーバ を選択すると、下記入力画面と同じになります。 アプリケーション名 FHIRResource : FHIRリポジトリの構成で「OAuth Client Name」に入力した値を入力します。 クライアント名 OAuth2認可サーバに登録されるクライアント名です。アプリケーション名と同じでもかまいませんが、ここでは違う名前にしました。 説明 この構成の説明を入力します。 クライアントの種別 「リソース・サーバ」を選択します。 SSL/TLS構成 パート1事前準備で用意したSSL/TLS構成を指定します。 入力が完了したら、「動的登録と保存」ボタンをクリックして保存とサーバへの登録を行います。(ちょっとわかりにくいですが)ボタンの表示が「動的登録と保存」から「更新メタデータを取得して保存」に変わったら登録が成功しています。 OAuth2認可サーバ側の構成情報を見て、本当に登録されているか確認してみましょう。 管理ポータル→システム管理→セキュリティ管理→OAuth2.0→サーバ の画面で「クライアントデスクリプション」をクリックすると以下のように登録されていることがわかります。 名前がクライアント名で指定した名前になっていることが確認できます。 パート1ではPostmanからアクセステストする際は、このクライアントデスクリプション画面をさらに進んで表示される、クライアント認証情報(クライアントIDとくらい案tの秘密鍵)を手動でコピーしましたが、今回は動的登録の過程でこれらの情報はクライアント側に受け渡されています。 PostmanからOAuth2アクセストークンを使って、FHIRリポジトリへアクセスする それではいよいよ、Postmanからアクセスしてみましょう! まずアクセストークンを取得します。基本はパート1の最後で取得した方法と同じですが、アクセストークンの発行先を表すaudienceパラメータを追加する必要があります。 aud=https://<hostname>/csp/healthshare/fhirserver/fhir/r4 Postmanで具体的に追加するには、以下のようにAuthorization Codeのendpoint URLにパラメータとして追加します。(Postmanの画面の都合上パラメータの全体が見えませんが、上記の aud=https://<hostname>/csp/healthshare/fhirserver/fhir/r4 をすべて記載してください) 注意:Postmanに入力するClient IDやClient Secretは先ほどのリソースサーバの動的登録で発行されたものに変更する必要はありません。パート1で追加した postman用に発行されたクライアントIDと秘密鍵を使用します。 アクセストークンが取得できたら、その内容をコピーしておいてください。 PostmanではこのままAuthorizationのTYPEをOAuth2にしておくと、アクセストークンを送信する機能がありますが、IRIS for HealthのFHIRリポジトリでは、OAuth2のアクセストークンだけではなく、Basic認証のユーザ・パスワード情報も送信する必要があります。 そのため、Postmanからアクセスする場合は、(ちょっと手間ですが)AuthorizationのTYPEはBasic Authにして、ユーザ名パスワードを入力し、アクセストークンはFHIRリポジトリへのRESTリクエストのParameterとして送信する必要があります。 具体的には、まず以下の画面のようにユーザ名・パスワードを入力します。このユーザ情報は、アクセストークンのsub内に含まれるユーザ情報と一致しているかの確認が行われるため、必ずアクセストークン取得時に入力したユーザ情報と同じユーザである必要があります。 次に、Paramsタブで、 access_token にパラメータに先ほどのアクセストークン値を入力します。 FHIRリポジトリを構築したばかりであれば、リポジトリには何のデータもはいってはいませんが、Patientデータをリクエストしてみましょう! Request URL には https://<hostname>/csp/healthshare/fhirserver/fhir/r4/Patient を入力し、HTTPのメソッドはGETを選択します(上の図のようになります) Sendボタンを押してリクエストを投げてみましょう!以下のようにFHIRのBundleが取得できれば、アクセストークンを使用したFHIRリポジトリへのアクセスは成功です! FHIRリポジトリへのデータの登録や検索の方法については、IRIS for Healthのドキュメントやコミュニティの記事をご参照ください。 IRIS for Health 2020.1 日本語ドキュメント:リソースリポジトリ IRIS for Health 2020.3  英語ドキュメント:Resource Repository (この記事を執筆した段階では、2020.3はPreview Editionです。) いかがでしたか?FHIRリポジトリへのアクセスが成功したでしょうか? この連載で紹介した構成内容は最も単純な構成ですが、実際のFHIRプロジェクトではユーザの認めたスコープによってどの範囲のデータまで返すように実装するか?といった検討と実装が必要になってきます。 開発者コミュニティでは引き続きFHIRに関する情報を発信していきたいと思います。 「発見して保存」を押した後、下記エラーが表示されます。 自己署名証明書を使用しているせいかと思いましたが、何か原因がございますでしょうか? ※ブラウザで管理ポータルに繋ぐ際、自己署名証明書の警告は表示されます。 お試しいただきありがとうございます。 IRIS for Health のコンテナから、ホストに対してホスト名でアクセスできていない可能性があります。以下のコマンド試してみてください。 #docker exec -it irishealth bashirisowner@iris:~$ ping <yourhostname>ping: <yourhostname>: Name or service not known このメッセージが出る場合、記事内にある  extra_hosts:  の追加を試してみてください。(この注意を書く位置がよくなったです。。。お手数かけて申し訳ありません。) エラーが出た時点でストップしてしまい、少し下の注釈を見落としておりました。申し訳ございません。 記載頂いたpingは通る状態だったのですが、extra_hostsの設定は行っていなかったため設定したところ無事動作しました。 ただ以下のようにlocalhostではNGで、実際のIPアドレスを指定しないとエラーが解消しませんでしたので念のため共有させて頂ければと思います。 NG ``` iris: image: store/intersystems/irishealth-community:2020.3.0.200.0 init: true container_name: irishealth ports: - "52773:52773" - "1972:1972" environment: - ISC_DATA_DIRECTORY=/ISC/dur - TZ=JST-9 volumes: - .:/ISC extra_hosts: - my-ubuntu:172.0.0.1 ``` OK ``` iris: image: store/intersystems/irishealth-community:2020.3.0.200.0 init: true container_name: irishealth ports: - "52773:52773" - "1972:1972" environment: - ISC_DATA_DIRECTORY=/ISC/dur - TZ=JST-9 volumes: - .:/ISC extra_hosts: - my-ubuntu:192.168.0.123 ``` ご確認と情報提供ありがとうございました。 記事の注意書きの位置も修正しておきました。 記事の修正誠にありがとうございます。 その後手順通り試したところ、FHIRのBundle取得まで正常に完了することが出来ました。
記事
Hiroshi Sato · 2020年12月16日

インターシステムズデータプラットフォーム製品のライセンスポリシーについて

この文書では、インターシステムズの製品の中で、InterSystems CachéおよびIRIS data platformに関するライセンスポリシーを説明します。 インターシステムズのライセンスポリシーは、ソリューション・パートナー契約の際の契約書一式あるいはエンドユーザーに直接販売する際の契約書一式に含まれる製品に関する条件(この文書は製品別に存在します)という文書で規定されています。 なおこの文書は一般には公開していません。 ここでは、CachéおよびIRIS data platformのライセンスポリシーについてこの文書に書かれていることを要約および補足して説明します。 まずCachéシステムおよびIRIS data platformはこの文書で規定されているライセンスポリシーにでき得る限り忠実にそうようにライセンスチェック機構を実装しています。 しかしながら様々な技術的な制約によりライセンスポリシーとこれら製品のライセンスシステムを完全に一致させることはできません。 そしてもしシステム上のライセンスチェック機構の動作とライセンスポリシー上に不一致が発生した場合には、いかなる場合でもライセンスポリシーが優先されます。 つまりライセンスシステム上許容されている動作であっても、ライセンスポリシーに合致していない場合には、ライセンスポリシーに合うような運用を行わなければなりません。 次にライセンスの形態ですが、Cachéは、ユーザー単位の同時ユーザーライセンスとなっています。 IRIS data platformは、同時ユーザーライセンスに加えて、CPUコア数単位に課金するライセンスタイプも提供しています。 同時ユーザーライセンスの場合、同時ユーザー1名が課金の単位となり、その課金の単位をLU(License Unit)と呼びます。 システムの稼働に必要なライセンス容量を決定する際に、システムのピーク時に同時アクセスする最大ユーザー数を見積もることで必要なLU数が求められます。 さらにこの同時という概念も少し説明が必要です。 ここで言う同時とは、サーバーとユーザーが使用するクライアントデバイス間のソフトウェア的な接続(TCPセッションなど)が確立されているかどうかは関係なく、その仮想的な接続を通してサーバー上のインターシステムズデータプラットフォームの機能を実行できる準備がクライアントデバイス側にできている状態を意味しています。 例えば、接続プールやHTTPのように毎回接続を確立して終了後切断するような技術を使い、クライアント側とサーバー側のコネクションが切れたとしても、クライアント側のアプリケーションが何等かの状態で動作している限り(画面表示され、次のアクションを待っているなど)は、その同時接続が維持されていると考えます。 (これを技術的に完全に検知するのは不可能です。) そして1LU当たり一人のユーザーの1つのデバイス当たり最大12個の接続あるいはプロセスを(合算して)同時に持つことができます。 同一人物が同時に複数のデバイスを使う場合にはデバイス毎にLUを消費します。 また人と直接結びつかずに単独でサーバーと接続するような1デバイス(医療検査機器など)も1ユーザーとみなします。 さらに人と直接結びつかないバッチプロセス(日時、週時、月時処理など)もLUの1つの形態とみなし最大12同時プロセスまで1LUとしてカウントできます。 なお、同一ユーザーの同一デバイスからの同時アクセスが25を超えると接続数分のLUがカウントされるというライセンスシステムの動作は、ライセンスポリシーで規定されたものではなく、システムが同じ所から多数の同時アクセスがあったことを検知した結果、シングルユーザーではなくマルチユーザーアクセスしていると判断してライセンスカウントの方法を変えたということを意味しています。 実案件でもし本当に一人のユーザーからの同時接続が12を超える可能性がある場合にLUをどうカウントするかあるいはその他ライセンス数の数え方の不明な点については、インターシステムズ営業部門までお問い合わせください。IRIS data platformのCPUコアライセンスは、CPUコアがライセンスユニット(LU)の単位となります。 物理サーバー上でIRIS data platformを稼働する場合は、IRISインスタンスまたはIRISクラスタを構成する全てのIRISインスタンスが稼働する物理サーバー上のCPUコア数の総計をカウントします。 仮想サーバー上でIRIS data platformを稼働する場合は、IRISインスタンスまたはIRISクラスタを構成する全てのIRISインスタンスが稼働する仮想サーバー上のCPUコア数の総計をカウントします。 なおインテル社のCPUに採用されているハイパースレッディングのようなSMT(Simultaneous Multithreading Technology)は物理サーバー上ではCPUのコア数としてはカウントしません。 しかし一方で仮想環境やAWSなどのクラウド環境では仮想CPU (製品やベンダー、クラウドサービスによって呼び方が異なるが一般的にはvCPUと表現される)がコア数の単位になります。
記事
Toshihiko Minamoto · 2022年3月2日

2021.2 SQL 機能スポットライト - 高度なテーブル統計

これは、IRIS でリレーショナルデータをクエリするアナリストとアプリケーションに、さらに優れた適応性とパフォーマンスによるエクスペリエンスを提供する IRIS SQL のイノベーションをトピックとした短い連載の 3 つ目の記事です。 2021.2 では連載の最後の記事になるかもしれませんが、この分野ではさらにいくつかの機能強化が行われています。 この記事では、このリリースで収集し始めた**ヒストグラム**という追加のテーブル統計について、もう少し詳しく説明します。 ### ヒストグラムとは? ヒストグラムは数値フィールド(またはより広範には、厳密な順序を持つデータ)のデータ分布の近似表現です。 このようなフィールドの最小値、最大値、および平均値がわかれば役立ちますが、データが 3 つのポイント間でどのように分布しているかはほとんどわかりません。 ここで役立つのがヒストグラムです。値の範囲をバケットに分割し、バケットごとに出現するフィールド値の数をカウントします。 これは非常に柔軟な定義であるため、バケットがフィールド値に関して同じ「幅」になるように、またはカバーされるサンプル値の数に関して同じ「大きさ」になるように、バケットのサイズを選択することができます。 後者の場合、各バケットには同じパーセンテージの値が含まれるため、バケットはパーセンタイルを表します。 以下のグラフは、日数で表現された同じバケット幅を使用して、[Aviation Demo データセット](https://github.com/intersystems/Samples-Aviation)の EventData フィールドのヒストグラムをプロットしています。 ### ヒストグラムが必要な理由 カリフォルニア州で 2004 年より前のすべてのイベントについて、このデータセットのクエリを実行しているとします。 SELECT * FROM Aviation.Event WHERE EventDate < '2004-05-01' AND LocationCountry = 'California' 「[ランタイムプランの選択](https://jp.community.intersystems.com/node/510746)」という前の記事では、テーブル統計で LocationCounty のようなフィールドの選択性と潜在的な外れ値をキャプチャする方法についてすでに説明しています。 しかし、そのような個別のフィールド値の統計は、EventDate での `<` 条件ではあまり実用的ではありません。 この条件の選択制を計算するには、2004 年 5 月 1 日までのすべての潜在的な EventDate 値の選択制を集計する必要があり、クエリのプランニング時に行えるような手っ取り早い見積もりではなく、それだけで非常に厳しいクエリとなる可能性があります。 ここで使用できるのがヒストグラムです。 EventDate 値の分布のヒストグラムデータを見てみましょう。今回は、データを同じサイズの 16 個のバケットに分割し、各バケットには 6.667% のデータが保持されています。 このようにすると、クエリコストの見積もりに使用できるパーセンタイルと選択制の数値に簡単に変換できます。 このテーブルを読み取るために、4 行目を見てみましょう。値の 20%(各 6.667% の 3 つのバケット)がこのバケットの下限である 2003 年 6 月 22 日より前にあり、さらに 6.667% の値が 2003 年 9 月 19 日まで保持されています。  <colgroup><col style="width:48pt" width="64"><col style="width:61pt" width="81"><col style="width:64pt" width="85"></colgroup> Bucket Percentile Value 0% 21/12/2001 1 7% 02/07/2002 2 13% 19/01/2003 3 20% 22/06/2003 4 27% 19/09/2003 5 33% 30/12/2003 6 40% 01/10/2004 7 47% 01/10/2005 8 53% 20/08/2006 9 60% 14/01/2007 10 67% 02/04/2008 11 73% 14/05/2008 12 80% 29/11/2008 13 87% 01/06/2010 14 93% 30/10/2011 15 100% 26/09/2012 上記のクエリ例で使用されているカットオフ日(2004 年 5 月 1 日)は、5 番目のバケットにあり、その日付より前には 33% から 40% の値があります。 バケットが小さくなるにつれ、その_中_の分布はほぼ均一であると見なすことができ、下限と上限の間を単に補完することができます。つまり、この場合、選択性は約 37% となり、これをクエリコストの見積もりに使用することができます。  ヒストグラムの使用を可視化するには、もう一つ、累積分布グラフとしてプロットする方法があります。 X 軸で 2004 年 5 月 1 日の線(値)がどのように描かれるかを確認すれば、Y 軸で 約 37% と解釈できます。     上記の例では、わかりやすくするために上限のみの範囲条件を使用していますが、このアプローチは、下限または間隔条件(`BETWEEN` 句を使用するなど)を使用しても当然動作します。  2021.2 より、文字列を含むすべての照合フィールドのテーブル統計の一環としてヒストグラムを収集しており、それを使用して RTPC の一部として範囲選択性を推定することができるようになっています。 実世界での多くのクエリには日付(およびその他の)フィールドでの範囲条件が伴うため、この IRIS SQL の機能強化によって、多くのお客様のクエリプランに役立つと信じています。いつものように、皆さんの体験をお聞かせください。
記事
Mihoko Iijima · 2023年5月26日

IRISジャーナル(z圧縮済み)をCachéにリストアする方法

これは InterSystems FAQ サイトの記事です。 IRISではジャーナルファイルが自動的に圧縮される仕組みが導入されています。 ジャーナルファイルの圧縮機能について詳しくは、別の記事「ジャーナル圧縮機能について」をご参照ください。 例えば、CachéからIRISへ移行された後に、念のためIRISで更新されたデータを手動でCachéにも反映させたいことばある場合に、IRISのジャーナルファイルをCachéにリストアすることができます。 手順は以下の通りです。 (手順1) IRISのジャーナルファイル(YYYYMMDD.nnnz) ファイルを解凍する(手順2,3) 解凍した ジャーナルファイルを Cachéに転送してリストアする リストアの方法として、以下の2パタンをご紹介 (A) 指定グローバルとデータベースについて、指定ジャーナルから、全エントリをリストア(B) 指定グローバルとデータベースについて、指定ジャーナルから、特定のアドレスまでリストアする (A) 指定グローバルとデータベースについて、指定ジャーナルから、全エントリをリストア (手順1) IRISサーバ上で以下のコマンドにより、ジャーナルを解凍する IRIS 2022.1 以降、現在実行中のジャーナル以外は、拡張子 z で圧縮されています。 以下のコマンドで解凍し、指定のフォルダにコピーします。 これをCachéにリストアしたいジャーナルファイルすべてに対して繰り返し実行してください。 例) set j1="/usr/irissys/mgr/journal/20230413.002z" set j2="/temp/20230413.002" write ##class(%SYS.Journal.File).Decompress(j1,j2) set j1="/usr/irissys/mgr/journal/20230413.003z" set j2="/temp/20230413.003" write ##class(%SYS.Journal.File).Decompress(j1,j2) 以下の実行例では、リストア対象データを作成しています。 USER>set ^abc="Dummyデータ" USER>set ^test1="USERデータベースで登録( I R I S )" USER>set $namespace="test1" TEST1>set ^Dummy=11000 TEST1>set ^DummyXX=2000 USERネームスペースはUSERデータベースにグローバルがセットされ、USERデータベースディレクトリは「/usr/irissys/mgr/user/」です。 TEST1ネームスペースはTEST1データベースにグローバルがセットされ、TEST1データベースディレクトリは「/usr/irissys/mgr/test1/」です。 (手順2) 手順1で解凍した、リストアしたいジャーナルを、すべて Cachéサーバに転送します。 (手順3) Cachéサーバ上で、上記コピーしてきたジャーナルを、連続してリストアします。 IRISからコピーして /temp に置いた 20230413.002 と 20230413.003 ファイルを以下のルールでリストアするように指定します。 [IRIS]/usr/irissys/mgr/user/  → [Cache]/usr/cachesys/mgr/user/ : ^abc と ^test1をリストア対象に指定する [IRIS]/usr/irissys/mgr/test1/  → [Cache]/usr/cachesys/mgr/test1/ : ^Dummy と ^DummyXXをリストア対象に指定する 実行コードは以下の通りです。 注意:Windows以外のOSにリストアする場合、データベースディレクトリの末尾にパスのマーク(/)を必ず入れて下さい。 //ジャーナルリストアに利用するクラスのインスタンスを生成 set jrn=##class(Journal.Restore).%New() //リストア開始ファイルの指定 set jrn.FirstFile="20230413.002" //リストア終了ファイルの指定 set jrn.LastFile ="20230413.003" //ジャーナルファイルの配置場所 do jrn.UseJournalLocation("/home/isjedu/irisjrn/") //カレントインスタンスのジャーナルログファイルを使うかどうか(-1は使わない) set jrn.JournalLog=-1 //ジャーナルリストア終了時、コミットされてないトランザクションをロールバックするかどうか set jrn.RollBack=0 //1つ目のデータベース set src(1)="/usr/irissys/mgr/user/" set to(1)="/usr/cachesys/mgr/user/" //第1引数:IRISのデータベースのデータベースディレクトリ //第2引数:リストア対象グローバル変数名(前方一致可) //IRISのUSERデータベースにある ^abcと、^iijimaをリストア do jrn.SelectUpdates(src(1),"abc") //^abc do jrn.SelectUpdates(src(1),"test1") //^test1 //ジャーナルリストア対象データベースディレクトリのリダイレクト指定 //第1引数:ジャーナルに記録されているIRISのデータベースディレクトリ //第2引数:リストア対象のCacheのデータベースディレクトリ set status=jrn.RedirectDatabase(src(1),to(1)) //もしエラーがあったらエラー情報を出力して終了 if $$$ISERR(status) { write $system.Status.GetErrorText(status) quit } //2つ目のデータベース set src(2)="/usr/irissys/mgr/test1/" set to(2) ="/usr/cachesys/mgr/test1/" do jrn.SelectUpdates(src(2),"Dummy*") ;; ^Dummy ^DummyXX set status=jrn.RedirectDatabase(src(2),to(2)) if $$$ISERR(status) { write $system.Status.GetErrorText(status) quit } //n個目のデータベース /* set src(n)="..(IRISのDBフォルダ名).." set to(n) ="..(CacheのDBフォルダ名).." do jrn.SelectUpdates(src(n),"xxx*") // ^xxx do jrn.SelectUpdates(src(n),"yyy") // ^yyy set status=jrn.RedirectDatabase(src(n),to(n)) if $$$ISERR(status) { write $system.Status.GetErrorText(status) quit } */ //リストア実行 set status=jrn.Run() if $$$ISERR(status) { write $system.Status.GetErrorText(status) quit } (B) 指定グローバルとデータベースについて、指定ジャーナルから、特定のアドレスまでリストア (手順1)(手順2)は、(A)と同様です。 (手順3) Cachéサーバ上で、上記コピーしてきたジャーナルを、連続してリストアします。 指定アドレス以降はリストアしない、というフィルタルーチンを、Caché サーバの %SYS に作成します。ルーチンの引数名はそのままにしておいてください。 作成詳細は、別記事「誤って削除したグローバルを復旧させる方法」の実施例以下をご覧ください。 %SYSネームスペースにルーチン名:ZJRNFILT で作成します。 例) ZJRNFILT(pid,dir,glo,type,restmode,addr,time) set restmode=1 // グローバル変数名に TEST1 が含まれいる // かつ ジャーナルレコードが9060180以降は restmode=0 に設定(=リストアしない) if (glo [ "TEST1") & (addr>=9060180) { set restmode=0 } quit (A)の手順のRun()メソッド実行の直前にフィルタルーチンの名称を設定する1文を加えるだけです。 //実行 set jrn.Filter="^ZJRNFILT" ;; <--- フィルタルーチン指定 set status=jrn.Run() 実行すると、ジャーナルをリストア完了後、以下のように2回聞かれます。 Do you want to rename your journal filter? Do you want to delete your journal filter? どちらも N と入力して、リターンしてください。
記事
Toshihiko Minamoto · 2022年2月24日

2021.2 SQL 機能スポットライト - ランタイムプランの選択

InterSystems IRIS Data Platform の 2021.2 リリースには、ミッションクリティカルなアプリケーションを高速で柔軟性に優れ、セキュアに開発するための刺激的な新機能が多数含まれています。 Embedded Python は間違いなく脚光を浴びています(正当な理由で!)が、SQL の分野でも、テーブルデータに関する詳細な統計情報を収集し、それを最適なクエリプランに提供する、より適応性の高いエンジンに向けて大きな一歩を踏み出しました。 この短い連載記事では、2021.2 で新しく追加された 3 つの要素について詳しく説明し、ランタイムプランの選択(RTPC)を手始めに、この目標に向かって進みます。 これらについて適切な順序で話していくのは困難です(この記事を書く上で、私がどれだけ順序を入れ替えたか想像できないほどです!) というのも、これらが相互に非常にうまく機能するためです。 そのため、ご自由に順序を変えてお読みください。 IRIS クエリ処理について IRIS SQL エンジンにステートメントを送信すると、エンジンはリテラル(クエリパラメーター)を置き換えてそのステートメントを正規化された形式に解析し、テーブル構造、インデックス、およびフィールド値に関する統計を見て、正規化されたクエリにとって最も効率的な実行ストラテジーをはじき出します。 これにより、おそらく異なるクエリパラメーター値を使用してクエリをもう一度実行したい場合に、エンジンは同じプランと生成されたコードを再利用することができます。 たとえば、以下のクエリを例にします。 SELECT * FROM Customer WHERE CountryCode = 'US' AND ChannelCode = 'DIRECT' このクエリは以下のような形式に正規化されます。 SELECT * FROM Customer WHERE CountryCode = ? AND ChannelCode = ? そのため、国とチャンネルの様々な組み合わせに対する後続の呼び出しは、即座にキャッシュされた同じクエリクラスを取得するため、計算量の多いプランニング作業を省略することができます。 6 つのチャンネルを通じて世界中にランニングシューズを販売すると仮定しましょう。言い換えると、データは CountryCode とChannelCode の可能な値全体で均等に分散されます。 これらの両方のフィールドに通常のインデックスがある場合、この正規化されたクエリで最も効率的なプランは、対応するインデックスを使用してマスターマップから一致する行にアクセスすることで最も選択的な条件(CountryCode)から始め、その後にマスターマップのすべての行に対し、別の条件(ChannelCode)をチェックします。  ### 外れ値 では、スポーツ用品メーカーではなく、ベルギーチョコレートの型を販売する専門ベンダーだとしましょう(どこから出てきた例でしょうかね )。 この場合、顧客の大半(たとえば 60%)がベルギーにいるとします。つまり、「BE」が CountryCode フィールドの_外れ値_であり、テーブルの多数の行を表します。 すると突然、CountryCode でのインデックスに他の使用方法が現れました。ランタイムで取得する CountryCode のクエリパラメーターが「BE」で_あるとした場合_、そのインデックスを最初に使用すると、マスターマップの大半を読み取ることになるため、ChannelCode でのインデックスから始める方がよくなります。 しかし、CountryCode のクエリパラメーター値が別の値で_あるとした場合_、他のすべての国が残りの 40% のベルギー以外の顧客を分割するため、CountryCode でのインデックスの方がはるかに高い価値が出てきます。 これは、ランタイム時に異なるプランを選択する場合の例です。または、言い換えると、**ランタイムプランの選択**(RTPC)と言えます。 RTPC は、従来のリテラル置換とキャッシュ済みのクエリルックアップロジックに小さなフックを追加して、CounryCode 列の「BE」値などの外れ値を見つけるメカニズムです。 IRIS SQL クエリ処理のさらに詳細な概要に興味のある方は、[こちらの VS2020 動画](https://learning.intersystems.com/course/view.php?id=1598)をご覧ください。 IRIS SQL は過去に、非常に大雑把なオプトインバージョンをサポートしていましたが、2021.2 で、大幅に軽量化され、より広範な述語条件に対応できる、まったく新しい RTPC インフラストラクチャを導入しました。 このランタイムチェックのオーバーヘッドは確かに最小限であるため、ユーザーが何も行わなくてもこのメリットを得られるように、これをデフォルトでオンにしました(いつものように、[アップグレード後にクエリプランを解凍](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCRN_upgrade_intro#GCRN_upgrade_intro_frozen)する必要はありません)。 これまで頻繁に、実世界のデータセットでは外れ値がどれほど一般的であるか(また、厳格に一様な分布がどれほど稀であるか)を見てきましし、パートナーのベンチマークでのテストによって、以下のグラフからわかるように、パフォーマンスと I/O で目を見開くほどの改善が得られることがわかりました。 また、2020.1 のベンチマーク結果も含めているため、リリースのたびにパフォーマンスを改善できるように継続的に取り組んでいること(と結果)を見ていただけるでしょう。 改善のマイレージは、データセットの外れ値の量とインデックスの可用性によって異なりますが、この変更の可能性には非常に興奮しており、皆さんの体験をお聞かせいただければ幸いです。
ディスカッション
Seiji Hirose · 2021年2月22日

IRISで困ること(是非、ご教授下さい)

今思えば、製品名に「M」が付いている時代は説明が楽でした。私が記憶している製品は、DTM(Data Tree Mumps:MS-DOS上で巨大なシステムを構築できていましたね)、DSM(Dec Standard Mumps)、MSM(マイクロネティック Standard Mumps あってますか?)、ISM(Intersystems Standard Mumps)、U-MUMPS(?)その他もあったかも知れませんが、M(Mumps)の実装環境です、という説明で何とかなっていました。すると、「へぇ~、MUMPSってまだあったんだね」という答えを頂くこともありました。これらの製品が統合されて「OpenM」となりましたが、まだ「M」の文字が入っており、MUMPSもSQL対応できるようになりました、などと説明していました。 ところが、製品名がCacheになり、趣が大きく変わり、製品の説明が難しくなりました。「データベースです。」→「RDBなの?」→「RDBとしても動作しますがKey-Value的で多次元データ管理もできます」→「OLAP用なの?」→「OLAP処理もできますが、基本はトランザクション処理用です」→「で、結局、何なの」という禅問答のような状況にはまって行きました。 そして、IRISです。Cache+α+β+θ...で機能満載ですね。端的な表現で「IRISはこういうものです」というフレーズをお持ちでしたら是非ご教授頂けないでしょうか。今後、個人的に、色々なところでIRISについて説明する機会が増えると考えていますが、つかみの部分が難しいと感じていますので...なお、データプラット・フォームです、は除外して頂けると有り難いです。返って長い説明がはじまってしまいそうなので。 宜しくお願い致します。 データプラットフォームと同じかもしれませんが、個人的にはデータベースと言語が一体となったシステムだと思います。(MUMPSやCachéも同じですが。。。) データベースと言語が一体となっているので、言語からデータベースの内容を簡単かつ安全、高速に参照、更新できるところが利点だと思います。また、以前はデータベース=RDBとなっていたので、拒絶反応を示されることが多かったのですが、最近ではドキュメントDBやグラフDBなどリレーショナルでないものもいろいろと出てきているので、少しご理解いただけるようになってきているのでは。と思います。 Minamoto様、コメント頂き有難う御座いました。 個人的には、「何とかツール」的なキラーフレーズがあると良いなぁ、と思っています。多少、厳密性を欠くことがあっても、一言でイメージが伝わるようなキャッチコピーがあると、今よりももっと受け入れられるような気がします。 例えば、無線LAN通信を「wi-fi」と言ってのけるように。ちなみに、wi-fi って、昔のステレオのHi-Fiをまねして、wi-fi になったそうですね。Bluetoothも、かつてのヨーロッパの王様の愛称だったとか... 上記のようなネーミングやキャッチコピーは貴社のポリシーには合致しないかも知れませんが、マーケティング的なキャッチコピーがあると良いなぁ、と思っています。 Hiroseさん先週のバーチャルサミット聴講していただいたと思いますが、ウルシステムズの漆原社長の講演は聞かれましたか?そこでエッジの効いたデータベースと紹介いただいています。見てない場合は是非ご覧になってください。 Sato様。 ウルシステムズの漆原様の講演は拝聴いたしました。 Satoさんのコメントにありますが「エッジの効いたデータベース」のイメージが掴みづらいと個人的に感じています。また、漆原様の講演の中で、「通常の処理であればRDBMSで十分だと思われる」といった旨のお話もあったように記憶しています。(間違っていたらご指摘ください。) 個人的には、IRISで所謂RDBMS的な処理は十分にこなせるのではないかと感じています。漆原様のお話にありましたが、RDBMSよりもIRISの方がデータ更新系の処理が数倍高速である、というのは私も実感しています。(最近、MariaDB(MySQL)でInsertテストを実施して実感しました。) 「エッジの効いたデータベース」が、RDBMSでは構築できない仕組みを構築できるデータベース、だとすると、IRISはRDBMSを補完するデータベースとして認識されてしまう可能性も有るように感じました。 何かもっとしっくり来る表現の仕方があるように思われるのですが、残念ながら、私の頭では思い付かない状況です。 hiroseさん その通りです。大は小を兼ねますからね IRISなら軽いものから重たいものまで何でもこなせます。用途に合わせてデータベースを分けないとなると、同じデータを物理的に別々に管理しなければならなくなりますよね。ITの課題の1つがデータのサイロ化です。 データがいろいろなところに散在していると、それを取りまとめるための手間が増えてしまいます。1つのデータベースが色々な用途に対応できるとその手間が少なくできるのではないかと思います。 そんな方向性をIRISは目指しています。キーワードとしてはマルチモデルとマルチワークロードです。 Sato様。 すでに2016年当時に上記のお考えをお持ちだったのですね。下記の記事を拝読致しました。 https://blogs.itmedia.co.jp/satohiroshi/2016/09/post_3859.html 色々なご意見を伺う中で、私のIRISに対するイメージは下記のようなものになってきました。 Multi Purpose Utility System (or, Environment )→上手く日本語になれば良いのですが。 このようなイメージはある程度当たっているでしょうか? 今後ともどうぞ宜しくお願い致します。 Hiroseさん返答遅れて申し訳ないです。Multi Purpose Utility System これは何だかMUMPSを思い出させるネーミングなので、申し訳ないですが却下させてください。でもイメージは間違っていないと思います。キャッチーなネーミングは、コンシューマを意識する場合は不可欠なのですが、IRISはどこまでいっても消費財ではなく生産財なので、すべての人に理解してもらうのはやはり難しいところです
記事
Toshihiko Minamoto · 2022年3月1日

2021.2 SQL 機能スポットライト - スマートサンプリング & テーブル統計の自動化

これは、適応性とパフォーマンスに優れた SQL エクスペリエンスを提供する 2021.2 SQL 強化機能に関する連載第 2 回目の記事です。 この記事では、前の記事で説明したランタイムプランの選択機能の主要な入力であるテーブル統計の収集におけるイノベーションに焦点を当てます。 皆さんには次のことを何度もお伝えしてきました: 『Tune tableを実行しましょう!』 [`TUNE TABLE` SQL コマンド](https://docs.intersystems.com/iris20211/csp/docbookj/DocBook.UI.Page.cls?KEY=RSQL_tunetable)または[`$SYSTEM.SQL.Stats.Table` ObjectScript API](https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?&LIBRARY=%25SYS&CLASSNAME=%25SYSTEM.SQL.Stats.Table#GatherTableStats) を通じてテーブルをチューニングすることは、IRIS SQL が適切なクエリプランをはじき出すのに役立つテーブルデータの統計情報を収集することです。 これらの統計情報には、テーブル内のおおよその行数など、オプティマイザーが JOIN の順序(通常、最も小さいテーブルから始めるのが最も効率的です)などを決定する上で役立つ重要な情報が含まれています。 クエリのパフォーマンスについて InterSystems サポートに寄せられる多くの問い合わせは、`TUNE TABLE` を実行してもう一度試すだけで解消されます。このコマンドを実行することで、既存のプランが無効になり、次の呼び出しによって新しい統計が得られるためです。 サポートへの問い合わせから、こういったユーザーがテーブルの統計情報を収集していなかった理由が 2 つわかりました。テーブル統計について知らなかった、または本番システムでチューニングを実行した際のオーバーヘッドの余裕がなかったという理由です。 2021.2 では、この 2 つの理由に対処しました。 ### ブロックレベルのサンプリング 2 つ目の理由から始めましょう。統計を収集するコストです。 テーブル統計を収集するには多大な I/O が必要となるため、_テーブル全体をスキャンしているのであれば_、オーバーヘッドも高まります。 API ではすでに、行の一部のみサンプリングすることをサポートしていましたが、この操作にはかなりのコストがかかるというご意見をいただいていました。 2021.2 では、マスターマップグローバルをループすることでランダムな行を選択するのではなく、その下の物理ストレージにすぐにアクセスしてそのグローバルにカーネルが実際のデータベースブロックのランダムなサンプルを取得するように変更しました。 サンプリングされたこれらのブロックから、それらが保存する SQL テーブル行を推論し、通常のフィールド単位の統計情報構築ロジックに対応します。 これを大規模なビールフェスティバルへの参加に例えると、すべての通路を歩き、いくつかの醸造所のブースを選んでそれぞれのボトルをカートに入れるのではなく、単に主催者に依頼してランダムなボトルが入った木箱を渡してもらうので歩かなくても済む、というものです。 (実際のビール試飲会では、歩き回ったほうが適切ですが![wink](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/wink_smile.png "wink"))。 酔いを醒ますために、以下に、ブロックベースのアプローチ(青い十字)に対する今までの行ベースのアプローチ(赤い十字)をプロットした単純なグラフを示しています。 これは、一部のお客様が `TUNE TABLE` を実行することを警戒している巨大なテーブルについては大きなメリットがあることを表しています。   ブロックサンプリングの制限はあまりありませんが、最も重要なのは、デフォルトのストレージマッピングでないテーブル(例: `%Storage.SQL` を使用してグローバル構造をカスタムマッピングしているテーブル)では使用できないことです。 このような場合には、過去に機能していた方法である、行ベースのサンプリングに戻ります。 ### 自動チューニング オーバーヘッドに関する認識の問題が片付いたところで、お客様が `TUNE TABLE` を実行していなかったもう 1 つの理由について考えましょう。その存在を知らなかったという理由です。 それについて文書化することもできました(また、ドキュメントを改善する余地が常にあることは認識しています)が、この非常に効率的なブロックサンプリングは、私たちが長年求めてきたことを実行する機会であると捉えました。すべてを自動化するということです。 2021.2 からは、統計がまったく提供されていないテーブルに対してクエリを準備する場合、最初に上記のブロックサンプリングメカニズムを使用してそれらの統計を収集し、クエリプランニングに統計を使用し、以降のクエリで使用できるように、テーブルメタデータに保存します。 仰々しく聞こえるかもしれませんが、上記のグラフは、GB サイズのテーブルでは、この統計収集の作業がわずか数秒で開始していることがわかります。 不適切なクエリプランを使用してそのようなテーブルをクエリしている場合(適切な統計がないため)は、事前に簡易サンプリングを実行するよりもはるかにコストがかかる可能性があります。 もちろん、これは、ブロックサンプリングを使用できるテーブルのみに行い、行ベースのサンプリングのみをサポートする特殊なテーブルの場合は、(残念ながら)統計なしで対処するしかありません。 他の新機能と同様に、皆さんの最初の体験に関する感想とフィードバックをお送りください。 この分野では、テーブルの使用状況に基づいて統計を最新の状態に維持するなど、自動化に関するアイデアは他にもありますが、そういった機能をラボ外部の使用体験に基づくものにしたいと考えています。
記事
Toshihiko Minamoto · 2022年11月2日

時間の支配者になるには ー誕生

> **良識のある人にはルールなんていらない。** > > _ドクター_ 日付と時間のマスターになるのは簡単なことではありません。いつも問題になる上、どのようなプログラミング言語でも混乱することがあります。そこでこのタスクが可能な限り単純になるように、分かりやすく説明していくつかのヒントをご紹介しましょう。 さぁ、[ターディス](https://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%BC%E3%83%87%E3%82%A3%E3%82%B9)に乗り込みましょう。あなたを**時間の支配者**にして差し上げます。 ![ターディス](/sites/default/files/inline/images/tardis-doctor.gif) ## 基本から始めよう 普段、他の言語を使用しているのであれば、InterSystems Object Script(以降「IOS」と呼びますが、Apple モバイルと勘違いしないように)の日付は少し独特です。 ターミナルで [$HOROLOG](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_VHOROLOG) を実行して現在の日付と時刻を取得する場合、2 つの部分に分割されているのがわかります。 WRITE $HOROLOG > 66149,67164 最初の値は日にちです。正確には 1840 年 12 月 31 日以来の日数であり、つまり値 1 は 1841 年 1 月 1 日となります。2 つ目の値は今日の 00:00 時以来の秒数です。 この例では、66149 は 09/02/2022(欧州フォーマットの dd/mm/yyyy なので 2 月 9 日)、67164 は 18:39:24 に対応しています。 このフォーマットを日付と時刻の**内部フォーマット**と呼ぶことにします。 混乱してきましたか? (日付と時刻の)宇宙の大きな秘密を解明し始めることにしましょう。   ## 内部フォーマットをわかりやすいフォーマットに変換するには? それについては、[$ZDATETIME](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_fzdatetime) コマンドを使用します。 基本的なコマンドは以下のようになります。 SET RightNow = $HOROLOG WRITE RightNow > 66149,67164 WRITE $ZDATETIME(RightNow) > 02/09/2022 18:39:24 デフォルトでは、アメリカ式フォーマット(mm/dd/yyyy)を使用します。 別のフォーマットで日付を表す場合は、欧州フォーマット(dd/mm/yyyy)など2 つ目のパラメーターを使用し、この場合は値 4 を指定します(詳細については、ドキュメントの [$ZDATETIME.dformat](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_fzdatetime#RCOS_fzdatetime_dformat) をご覧ください)。 SET RightNow = $HOROLOG WRITE RightNow > 66149,67164 WRITE $ZDATETIME(RightNow,4) > 09/02/2022 18:39:24 このオプションは、ローカル変数で定義したものを区切り文字と年フォーマットを使用します。 また、別の時間フォーマットを使用したい場合、たとえば 24 時間制ではなく 12 時間制(午前/午後)を使用したい場合は、3 つ目のパラメータを値 3 とし、秒数を表示しない場合は、値 4 を使用します(ドキュメントの [ $ZDATETIME.tformat](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_fzdatetime#RCOS_fzdatetime_tformat) を参照)。 SET RightNow = $HOROLOG WRITE RightNow > 66149,67164 WRITE $ZDATETIME(RightNow,4,3) > 09/02/2022 06:39:24PM WRITE $ZDATETIME(RightNow,4,4) > 09/02/2022 06:39PM わかってきましたか? ではもっと詳しく見てみましょう。 ### ODBC フォーマット このフォーマットはローカル構成に依存しておらず、常に yyyy-mm-dd として表示されます。この値は 3 です。 CSV、HL7 などのファイルでエクスポートされるデータを作成する際は、これを使用することをお勧めします。 SET RightNow = $HOROLOG WRITE RightNow > 66149,67164 WRITE $ZDATETIME(RightNow,3) > 2022-02-09 18:39:24 ### 曜日、曜日名、年間通産日 | 値 | 説明 | | -- | ------------------------------------------------------------------------- | | 10 | 曜日は 0 から 6 の値で、日曜日は 0、土曜日は 6 です。 | | 11 | 曜日の略名で、ユーザーが定義するローカル構成に基づいて返します。IRIS のデフォルトインストールは enuw(英語、米国、Unicode)です。 | | 12 | ロング形式の曜日名。 11 と同じです。 | | 14 | 年間通産日。つまり 1 月 1 日からの日数です。 | 日付と時刻を個別に扱う場合は、それぞれ $ZDATE コマンドと $ZTIME コマンドを使用します。 フォーマットのパラメーターは、[$ZDATETIME.dformat](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_fzdatetime#RCOS_fzdatetime_dformat)と[$ZDATETIME.tformat](https://docs.intersystems.com/healthconnectlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=RCOS_fzdatetime#RCOS_fzdatetime_tformat)で定義されているパラメーターと同じです。 SET RightNow = $HOROLOG WRITE RightNow > 66149,67164 WRITE $ZDATE(RightNow,10) > 3 WRITE $ZDATE(RightNow,11) > Wed WRITE $ZDATE(RightNow,12) > Wednesday ## 日付を内部フォーマットに変換するには? では、逆のステップを見てみましょう。日付のあるテキストを IOS フォーマットに変換する方法です。 このタスクでは、[$ZDATETIMEH](https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzdatetimeh) コマンドを使用します。 今度は、日付と時刻に使用されているフォーマット($ZDATETIMEH を使用している場合)、または日付($ZDATEH)または時刻($ZTIMEH)に使用されているフォーマットを個別に示す必要があります。 フォーマットは同じです。つまり、ODBC フォーマット(yyyy-mm-dd)の日付を持つ文字列がある場合は、値 3 を使用します。 SET MyDatetime = "2022-02-09 18:39:24" SET Interna1 = $ZDATETIMEH(MyDatetime, 3, 1) // ODBC フォーマット SET MyDatetime = "09/02/2022 18:39:24" SET Interna2 = $ZDATETIMEH(MyDatetime, 4, 1) // 欧州フォーマット SET MyDatetime = "02/09/2022 06:39:24PM" SET Interna3 = $ZDATETIMEH(MyDatetime, 1, 3) // 米国フォーマット、12 時間制 AM/PM WRITE Interna1,!,Interna2,!,Interna3 > 66149,67164 66149,67164 66149,67164 論理的に、文字列が特定のフォーマットを使用しており、誤ったパラメーターを指定した場合は、2 月 9 日ではなく 9 月 2 日として理解するなど、どのようなことでも起こりえます。 フォーマットを混在させないようにしましょう。後で問題になります。 SET MyDatetime = "09/02/2022" /// 米国フォーマット SET InternalDate = $ZDATEH(MyDatetime, 1) /// 欧州フォーマット SET OtherDate = $ZDATETIME(InternalDate, 4) WRITE InternalDate,!,OtherDate > 66354 02/09/2022 もちろん、欧州式の日付を設定し、米国式に変換しようとすると ... バレンタインデーはどうなってしまうのでしょうか? SET MyDatetime = "14/02/2022" SET InternalDate = $ZDATEH(MyDatetime, 1) // 米国フォーマット。 14 月は存在しません!!! ^ <ILLEGAL VALUE> ハートブレイクなバレンタインデーと同じように... コードブレイクしてしまいました。 では、学習した内容を使って、何かやってみましょう。 READ !,"Please indicate your date of birth (dd/mm/yyyy): ",dateOfBirth SET internalFormat = $ZDATEH(dateOfBirth, 4) SET dayOfWeek= $ZDATE(internalFormat, 10) SET nameOfDay = $ZDATE(internalFormat, 12) WRITE !,"The day of the week of your birth is: ",nameOfDay IF dayOfWeek = 5 WRITE "you always liked to party!!!" // 金曜日生まれ 後で、これを他のやり方で行う方法と、エラーの処理方法を見ることにしましょう。 ###   ### 次の章: タイムトラベルの方法   ## トリビア なぜ 1841年1月1日の値が値1 となるのでしょうか? それが選択された理由は、オブジェクトスクリプトを拡張した [MUMPS プログラミング言語](https://ja.wikipedia.org/wiki/MUMPS)が設計されたときに、南北戦争の退役軍人として当時生存していた最年長 121 歳のアメリカ人が生まれる前のうるう年でない年であったためです。   >オブジェクトスクリプトを拡張した MUMPS プログラミング言語が設計されたときに これは逆ですね。MUMPSプログラミング言語を拡張したオブジェクトスクリプト
記事
Toshihiko Minamoto · 2023年3月23日

IRIS IntegratedML を使った腎臓病予測 Web アプリ

腎臓病は、医学会でよく知られるいくつかのパラメーターから発見することが可能です。 この測定により、医学界とコンピューター化されたシステム(特に AI)を支援すべく、科学者である Akshay Singh は、腎臓病の検出/予測における ML アルゴリズムをトレーニングするための非常に便利なデータセットを公開しました。 このデータセットは、ML の最大級のデータリポジトリとして最もよく知られている Kaggle に公開されています。https://www.kaggle.com/datasets/akshayksingh/kidney-disease-dataset ## データセットについて 腎臓病データセットには、以下のメタデータ情報が含まれています(出典: https://www.kaggle.com/datasets/akshayksingh/kidney-disease-dataset) * 赤血球、足浮腫、血糖値などの 25 種類の特徴量を含む 400 行のデータセット。 * 患者が慢性腎臓病を患っているかどうかを分類することが目的 * 分類は、'classification' と名付けられた属性が 'ckd'(慢性腎臓病)であるか 'notckd' であるかに基づいて行われます。 * データセットの作成者は、テキストと数値のマッピングやその他の変更点を含むデータセットのクリーニングを実施しました。 クリーニングの後、データセット作成者は EDA(探索的データ解析)を行い、データセットをトレーニングとテストに分割し、それらにモデルを適用しました。 分類結果は、最初はあまり満足のいくものではないことがわかっています。 そこで、Nan 値のある行をドロップする代わりに、ラムダ関数を使用して、それらの行を各カラムのモードに置き換えて、 もう一度データセットをトレーニングセットとテストセットに分割し、モデルに適用しました。 今度は、結果が改善され、ランダムフォレストと意思決定ツリーが、1.0 と 0 の誤分類の精度で最も良く実行することがわかりました。 分類のパフォーマンスは、混合行列、分類レポート、および制度の出力によって測定されています。 ### データセットの情報(出典: https://archive.ics.uci.edu/ml/datasets/chronic\_kidney\_disease ) データセットの収集には以下の表現を使用しています。 age - 年齢 bp - 血圧 sg - 比重 al - アルブミン値 su - 糖分 rbc - 赤血球 pc - 膿細胞 pcc - 膿細胞の塊 ba - 細菌 bgr - ランダム血糖値 bu - 血液尿素 sc - 血清クレアチニン sod - ナトリウム pot - カリウム hemo - ヘモグロビン pcv - ヘマトクリット値 wc - 白血球数 rc - 赤血球数 htn - 高血圧 dm - 糖尿病 cad - 冠動脈疾患 appet - 食欲 pe - 足浮腫 ane - 貧血症 class - クラス ### 属性の情報(出典: https://archive.ics.uci.edu/ml/datasets/chronic\_kidney\_disease) 24 + class = 25(数値 11 個、名義尺度 14 個)を使用します。 1. 年齢(数値) 年数 2. 血圧(数値) bp(mm/Hg) 3. 比重(名義尺度) sg - (1.005,1.010,1.015,1.020,1.025) 4. アルブミン値(名義尺度) al - (0,1,2,3,4,5) 5. 糖分(名義尺度) su - (0,1,2,3,4,5) 6. 赤血球(名義尺度) rbc - (normal,abnormal) 7. 膿細胞(名義尺度) pc - (normal,abnormal) 8. 膿細胞集塊(名義尺度) pcc - (present,notpresent) 9. 最近(名義尺度) ba - (present,notpresent) 10. ランダム血糖値(数値) bgr(mgs/dl) 11. 血液尿素(数値) bu(mgs/dl) 12. 血清クレアチニン(数値) sc(mgs/dl) 13. ナトリウム(数値) sod(mEq/L) 14. カリウム(数値) pot(mEq/L) 15. ヘモグロビン(数値) hemo(gms) 16. ヘマトクリット値(数値) 17. 白血球数(数値) wc(cells/cumm) 18. 赤血球数(数値) rc(100万/cmm) 19. 高血圧(名義尺度) htn - (yes,no) 20. 糖尿病(名義尺度) dm - (yes,no) 21. 冠動脈疾患(名義尺度) cad - (yes,no) 22. 食欲(名義尺度) appet - (good,poor) 23. 足浮腫(名義尺度) pe - (yes,no) 24. 貧血症(名義尺度) ane - (yes,no) 25. 区分(名義尺度) class - (ckd,notckd) ## Kaggle から腎臓データを取得する Kaggle の腎臓データは、Health-Dataset アプリケーション(https://openexchange.intersystems.com/package/Health-Dataset)を使って IRIS テーブルに読み込めます。 これを行うには、module.xml プロジェクトから依存関係(Health Dataset 用の ModuleReference)を設定します。 Health Dataset アプリケーションリファレンスを使用した Module.xml <?xmlversion="1.0" encoding="UTF-8"?> <Export generator="Cache" version="25">  <Documentname="predict-diseases.ZPM"> <Module>       <Name>predict-diseases</Name>       <Version>1.0.0</Version>       <Packaging>module</Packaging>       <SourcesRoot>src/iris</SourcesRoot>       <Resource Name="dc.predict.disease.PKG"/>       <Dependencies>         <ModuleReference>           <Name>swagger-ui</Name>           <Version>1.*.*</Version>         </ModuleReference>         <ModuleReference>           <Name>dataset-health</Name>           <Version>*</Version>         </ModuleReference>       </Dependencies>        <CSPApplication         Url="/predict-diseases"         DispatchClass="dc.predict.disease.PredictDiseaseRESTApp"         MatchRoles=":{$dbrole}"         PasswordAuthEnabled="1"         UnauthenticatedEnabled="1"         Recurse="1"         UseCookies="2"         CookiePath="/predict-diseases"        />        <CSPApplication         CookiePath="/disease-predictor/"         DefaultTimeout="900"         SourcePath="/src/csp"         DeployPath="${cspdir}/csp/${namespace}/"         MatchRoles=":{$dbrole}"         PasswordAuthEnabled="0"         Recurse="1"         ServeFiles="1"         ServeFilesTimeout="3600"         UnauthenticatedEnabled="1"         Url="/disease-predictor"         UseSessionCookie="2"       />     </Module>       </Document> </Export> ## 腎臓病を予測するための Web フロントエンドとバックエンドのアプリケーション Open Exchange アプリのリンク(https://openexchange.intersystems.com/package/Disease-Predictor)に移動し、以下の手順に従います。 1. リポジトリを任意のローカルディレクトリに Clone/git pull します。 $ git clone https://github.com/yurimarx/predict-diseases.git 2. このディレクトリで Docker ターミナルを開き、以下を実行します。 $ docker-compose build 3. IRIS コンテナを実行します。 $ docker-compose up -d 4. AI モデルをトレーニングするため管理ポータルのクエリ実行(http://localhost:52773/csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER)に移動します。 5. トレーニングに使用するビューを作成します。 CREATE VIEW KidneyDiseaseTrain AS SELECT age, al, ane, appet, ba, bgr, bp, bu, cad, classification, dm, hemo, htn, pc, pcc, pcv, pe, pot, rbc, rc, sc, sg, sod, su, wc FROM dc_data_health.KidneyDisease 6. ビューを使用して AI モデルを作成します。 CREATE MODEL KidneyDiseaseModel PREDICTING (classification) FROM KidneyDiseaseTrain 7. モデルをトレーニングします。 TRAIN MODEL KidneyDiseaseModel 8. [http://localhost:52773/disease-predictor/index.html](http://localhost:52773/disease-predictor/index.html) に移動し、Disease Predictor フロントエンドを使用して、以下のように疾患を予測します。 ## 背後の処理 ### 腎臓病を予測するためのバックエンドのクラスメソッド InterSystems IRIS では、前に作成されたモデルを使って、SELECT の実行により予測することができます。 腎臓病を予測するためのバックエンドのクラスメソッド /// 腎臓病の予測 ClassMethod PredictKidneyDisease() As %Status {     Try {       Set data = {}.%FromJSON(%request.Content)       Set %response.Status = 200       Set %response.Headers("Access-Control-Allow-Origin")="*"             Set qry = "SELECT PREDICT(KidneyDiseaseModel) As PredictedKidneyDisease, "                   _"age, al, ane, appet, ba, bgr, bp, bu, cad, dm, "                   _"hemo, htn, pc, pcc, pcv, pe, pot, rbc, rc, sc, sg, sod, su, wc "                   _"FROM (SELECT "_data.age_" AS age, "                   _data.al_" As al, "                   _"'"_data.ane_"'"_" AS ane, "                   _"'"_data.appet_"'"_" AS appet, "                   _"'"_data.ba_"'"_" As ba, "                   _data.bgr_" As bgr, "                   _data.bp_" AS bp, "                   _data.bu_" AS bu, "                   _"'"_data.cad_"'"_" As cad, "                   _"'"_data.dm_"'"_" As dm, "                   _data.hemo_" AS hemo, "                   _"'"_data.htn_"'"_" AS htn, "                   _"'"_data.pc_"'"_" As pc, "                  _"'"_data.pcc_"'"_" As pcc, "                   _data.pcv_" AS pcv, "                   _"'"_data.pe_"'"_" AS pe, "                   _data.pot_" As pot, "                   _"'"_data.rbc_"'"_" As rbc, "                   _data.rc_" AS rc, "                   _data.sc_" AS sc, "                   _data.sg_" As sg, "                   _data.sod_" As sod, "                   _data.su_" AS su, "                   _data.wc_" AS wc)"       Set tStatement = ##class(%SQL.Statement).%New()       Set qStatus = tStatement.%Prepare(qry)       If qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}       Set rset = tStatement.%Execute()       Do rset.%Next()         Set Response = {}       Set Response.classification = rset.PredictedKidneyDisease       Set Response.age = rset.age       Set Response.al = rset.al       Set Response.ane = rset.ane       Set Response.appet = rset.appet       Set Response.ba = rset.ba       Set Response.bgr = rset.bgr       Set Response.bp = rset.bp       Set Response.bu = rset.bu       Set Response.cad = rset.cad       Set Response.dm = rset.dm       Set Response.hemo = rset.hemo       Set Response.htn = rset.htn       Set Response.pc = rset.pc       Set Response.pcc = rset.pcc       Set Response.pcv = rset.pcv       Set Response.pe = rset.pe       Set Response.pot = rset.pot       Set Response.rbc = rset.rbc       Set Response.rc = rset.rc       Set Response.sc = rset.sc       Set Response.sg = rset.sg       Set Response.sod = rset.sod       Set Response.su = rset.su       Set Response.wc = rset.wc         Write Response.%ToJSON()             Return 1           } Catch err {       write !, "Error name: ", ?20, err.Name,           !, "Error code: ", ?20, err.Code,           !, "Error location: ", ?20, err.Location,           !, "Additional data: ", ?20, err.Data, !       Return     } } これで、どの Web アプリケーションもこの予測を使用して、結果を表示できるようになりました。 predict-diseases アプリケーションのソースコードは、frontend フォルダをご覧ください。
記事
Toshihiko Minamoto · 2023年5月2日

スタジオとGitHubとの連携環境の構築

開発者のみなさん、こんにちは。 vscode上で動作するObjectScriptエクステンションがリリースされ、vscodeを開発環境として使用できるようになり、GitHubリポジトリと連携できるようになりました。その一方で、使い慣れたIRISやCacheのスタジオからGitHubを扱いたいという要望は根強くあり、GitHubと連携するツールがOpen Exchange上にいくつか公開されています。 そこで、Open exchangeに収録されているツールの中で新しい「git for shared development environment」を使い、環境を作成してみましたので、その手順をお伝えします。 ご利用される際のご参考になれば幸いです。 Git for windows のインストール Git for windows のサイト よりキットをダウンロードし、そのexeファイル (git-2.xx.xx xx-bit.exe) を起動します。ライセンスの確認画面が表示されますので、「Install」ボタンをクリックします。 SSHキーペアの作成 コマンドプロンプトを起動し、ssh-keygen コマンドを実行します。 C:\Users\username> ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (C:\Users\username/.ssh/id_rsa): <-- Enter Enter passphrase (empty for no passphrase): <-- Enter Enter same passphrase again: <-- Enter Your identification has been saved in C:\Users\username/.ssh/id_rsa. Your public key has been saved in C:\Users\username/.ssh/id_rsa.pub. : C:\Users\username> 注意:このツールではSSHキーペアを使ってGitHubにアクセスすることを前提にしています。httpだとうまく動作しないことがありますので、ご注意ください。 GitHub への公開鍵の登録 WebブラウザにてGitHubのSSH公開鍵登録画面(https://github.com/settings/keys)にアクセス(GitHubアカウントへのログインが必要です)し、「New SSH key」をクリックします。Add new画面にて、Titleに公開鍵の名称(何でも構いません)を入力し、Keyに先ほど作成したid_rsa.pubファイルの中身を貼り付け、「Add SSH key」ボタンをクリックします。 InterSystems Package Manager (IPM:旧ZPM)のインストール 以下のURLよりIPMのキット(zpm-0.x.x.xml)をダウンロードします。https://pm.community.intersystems.com/packages/zpm/latest/installer ダウンロードしたzpm-0.x.x.xmlを%SYSネームスペースにロードします。 USER> zn "%SYS" %SYS> do $SYSTEM.OBJ.Import(ファイル名,"c") IPMをインストールいただくことで、簡単にOpen Exchangeに収録されている対応ツールやパッケージをダウンロード、インストールできます。特に依存関係のあるパッケージもインストールされますので簡単です。 Git for Shared Development Environment のインストール Git for Shared Development Environmentは以下のOpenExchangeに掲載されており、スタジオからgitを使用してGitHubとの連携を行うツールです。https://openexchange.intersystems.com/package/Git-for-Shared-Development-Environments ターミナルを起動し、開発環境のネームスペースに移動、IPMを使用してインストールします。 USER> zn "DEV" DEV> zpm "install git-source-control" 設定メソッドを実行し、gitのパスやローカルリポジトリのフォルダ、SSH秘密鍵、Git操作ユーザを設定します。 DEV>d ##class(SourceControl.Git.API).Configure() Configured SourceControl.Git.Extension as source control class for namespace DEV Configured default mappings for classes, routines, and include files. You can customize these in the global: ^SYS("SourceControl","Git","settings","mappings") Path to git executable: "C:\Program Files\Git\bin\git.exe" => <-- Enterのみ Local git repo root folder: c:\temp\DEV\ => <-- ローカルリポジトリのフォルダを入力 Path to private key file (for ssh remotes): c:\Users\user\.ssh\id_rsa <-- 先ほど作成したSSH秘密鍵のファイル名 Event handler class for git pull: SourceControl.Git.PullEventHandler.Default => <-- Enterのみ Character to replace % symbol when importing %-classes into the file systems: <-- Enterのみ Attribution: Git username for user 'username': username => <-- Git操作を行うユーザ名 Attribution: Email address for user 'username': username@pc.company.com => <-- Git操作を行うユーザのメールアドレス Settings saved. DEV> ローカルリポジトリの初期化 Git for windowsバージョン2.35.2以降ではセキュリティが強化されており、ローカルリポジトリフォルダの所有者がローカルシステムアカウントでない場合、エラーが発生するようになりました。そのため、一旦フォルダを削除します。 C:\Users\username> rmdir C:\Temp\DEV スタジオを起動し、開発環境のネームスペースに接続します。「Git」メニューの「Initialize」をクリック、ローカルリポジトリを初期化します。 「Git」メニューが表示されないときは、管理ポータルを起動し、「システム管理」「構成」「追加設定」「ソースコントロール」をクリックしますと、以下のような画面が表示されます。 ここで画面左のネームスペースで開発環境のネームスペースを選択し、ソースコントロールクラス名にて「SourceControl.Git.Extension」クラスをクリック、画面上の「保存」ボタンをクリックします。その後、スタジオを再起動することで「Git」メニューが表示されるようになります。 リモートリポジトリの設定とソースコードの取り込み コマンドプロンプトより、リモートリポジトリ(github.com/username/xxx.git)を登録します C:\Users\username> cd C:\Temp\DEV C:\Temp\DEV> git remote add origin git@github.com:username/xxx.git リモートリポジトリからソースコードをpullし、テンポラリフォルダにソースコードを取り込みます。 C:\Temp\DEV> git pull origin master remote: Enumerating objects: 79, done. remote: Counting objects: 100% (79/79), done. remote: Compressing objects: 100% (51/51), done. remote: Total 79 (delta 14), reused 77 (delta 14), pack-reused 0 Unpacking objects: 100% (79/79), 42.87 KiB | 142.00 KiB/s, done. From github.com:miniclub/xxx * branch master -> FETCH_HEAD * [new branch] master -> origin/master ブランチがmasterでない場合、以下のようにブランチ名を指定し、git checkoutで現在のブランチを変更してください。 C:\Temp\DEV> git pull origin dev : C:\Temp\DEV> git chekout dev マッピング情報の変更 取り込んだリモートリポジトリのフォルダ構成に合わせてマッピング情報を変更します。 スタジオを起動し、開発環境のネームスペースに接続、「Git」「Settings」メニューをクリックします。設定画面が表示されますので、「Mappings」欄に移動します。 表の左からソースコードの拡張子、名前、関連パスとなっており、赤枠で囲まれた関連パスをリポジトリのフォルダ構成に応じて変更します。 例えば、vscodeで作成したリポジトリではクラスやルーチンは全てsrcフォルダ配下に入りますので、それらの値は全て「src/」となります。 ソースコードのインポート 「Git」「Import (force)」メニューで、ローカルリポジトリフォルダのソースコードをIRISに読み込みます。 以上で、GitHubに登録されたリポジトリのソースコードをIRISに取り込むことができました。クラスやルーチンを修正した後、各ファイルを表示した状態で「Git」「Commit changes to file」メニューをクリックすることで変更をコミットし、「Git」「Push to remote branch」でリモートリポジトリに反映させることが。 最後までお読みいただきありがとうございます。 一度お試しいただいて、ご意見やご質問等ございましたら、コメント欄に書き込みいただければと思います。
記事
Mihoko Iijima · 2023年6月2日

任意のWebアプリから呼び出せるワークフロー用 REST API の使い方

開発者の皆さん、こんにちは! この記事では、ワークフローコンポーネントを使ってみよう!~使用手順解説~ でご紹介したユーザ操作画面(ユーザポータル)を任意のWebアプリに変更する際に便利な REST API の使用方法をご紹介します。 ワークフロー用 REST APIですが、開発者コミュニティのサンプル公開ページ:Open Exchange に公開されているAPIでどなたでも自由にご利用いただけます。 Open Exchangeの検索ボックスに「Workflow rest」と入力すると出てきます。EnsembleWorkflow が対象のサンプルです。 ちなみに、2023年6月2日時点で724のアプリケーションが公開されているようです👀 以下の内容もぜひご確認ください。 ワークフローコンポーネントでどんなことができるのか?の概要説明については、ウェビナー(オンデマンド再生)をご参照ください。 コンテナで動くサンプルもご用意しています。流れを先に確認されたい場合は、システム連携の自動的な流れの中にユーザからの指示を介入できる「ワークフローコンポーネント」のサンプル の手順に沿って動作をご確認ください。 EnsembleWorkflow のページに移動したらボタンをクリックするとサンプルがあるGitリポジトリに移動します。 InterSystems Package Manager(IPM)でもインストールできますが、この記事ではGitリポジトリから入手する方法で記載しています。 リポジトリに移動すると、isc/wf/REST.clsクラスが確認できます。このクラスをお手元のIRISにインストールし、RESTのエンドポイント(=ウェブアプリケーションパスの設定)を作成したら利用できます。 以降の説明では、お手元のIRISにこのクラスをインポートした後の手順をご紹介します。 クラス定義のインポート方法については、1つ前の記事「ワークフローコンポーネントを使ってみよう!~使用手順解説~」の 4) サンプルのインポート をご参照ください。 この後の説明は、「システム連携の自動的な流れの中にユーザからの指示を介入できる「ワークフローコンポーネント」のサンプル」 の手順に沿って作成したワークフロータスクを処理できる環境があることを前提としています。 サンプルをインポートすると「isc.wf.REST」の名称でクラスがインポートされます。このクラス名を使用してRESTのエンドポイントを作成します。 IRISの管理ポータルを開きます(ウェブサーバ名、ポート番号は環境に合わせてご変更ください)👉 http://localhost:52773/csp/sys/UtilHome.csp 管理ポータル > [システム管理] > [セキュリティ] > [アプリケーション] > [ウェブ・アプリケーション] に移動します。 ボタンをクリックし、新しいウェブ・アプリケーションを作成します。 以下の項目を設定します。 「名前」にエンドポイントのパスを指定します。例では、/wfsample としています。(/ を先頭につけ忘れないようにしてください) 「ネームスペース」にクラス定義をインポートしたネームスペースを指定します。例では、USER を選択しています。 「REST」の「ディスパッチ・クラス」にインポートしたクラス名を指定します。例では、isc.wf.REST を指定しています。 セキュリティの設定の「許可された認証方法」を「パスワード」のみに変更します。 ワークフローユーザ名でログインが必要となりますので、パスワードのみにします。 設定が完了したら、画面上にある保存ボタンをクリックします。 保存後表示される「アプリケーション・ロール」タブを選択し、このパスを通過できたときに付与されるロールを設定します。 適切なロールを事前に作成し追加するほうが適切ですが、以下の例では事前定義ロールの%Allを指定する例でご紹介します。 「利用可能」から %Allを選択 ▶アイコンを利用して%Allを「選択済み」に移動 「付与する」ボタンクリック これで準備完了です。早速RESTでアクセスしてみます。 ワークフロータスクが0件の場合は、サンプルデータを更新しタスクを作成してください。 手順については「システム連携の自動的な流れの中にユーザからの指示を介入できる「ワークフローコンポーネント」のサンプル」の「5.メモ」をご参照ください。 (例では、RESTクライアントにPostmanを使用しています。) タスク一覧を取得:GET http://ウェブサーバ/エンドポイント/tasks で取得できます。(ワークフローユーザを利用してBasic認証でアクセスします。パスワードは設定されたパスワードをご利用ください。) 例)http://localhost:52773/wfsample/tasks タスク一覧のJSONオブジェクトの中に、idプロパティがあります。このidの値を利用して、1件のタスク詳細をGETできます。 1件のタスク詳細取得:GET http://ウェブサーバ/エンドポイント/task/id で取得できます。(ワークフローユーザを利用してBasic認証でアクセスします。パスワードは設定されたパスワードをご利用ください。) 例)http://localhost:52773/wfsample/task/8||ManagerA 1件のタスクを処理する:POST http://ウェブサーバ/エンドポイント/task/id をPOST要求で実行します。(ワークフローユーザを利用してBasic認証でアクセスします。パスワードは設定されたパスワードをご利用ください。) 例)http://localhost:52773/wfsample/task/8||ManagerA 特定した1件のタスクを処理します。今回の例では、承認か却下のボタンを押すことができるので、承認のボタンを押すアクションを実施します。 POST時に送付するJSONは以下の通りです。 { "action": "承認", "formFields": { "RejectedReason": "" } } action にボタン名を指定します。 formFields.RejectedReasonには「却下理由」を指定します。「承認」の時は空を設定し渡します。​​​​ この時のトレースは以下の通りです。 「承認」の情報が渡されています。 では次に、却下を試します。 別のタスクIDを利用して、却下理由(RejectedReason)も含めてPOSTします。 トレースを確認します。 ​​​​​「却下」の情報が渡されていることと「却下理由」も渡されていることを確認できます。 REST APIでワークフロー用データにアクセスできれば、IRIS付属のユーザポータルではなくお好みのWebアプリケーションをユーザポータルとして利用することもできます。 システム連携の流れの中にユーザからの指示を含めたい処理がある!!という場合には、ぜひこのワークフローコンポーネントをご利用ください😀
記事
Shintaro Kaminaka · 2020年8月12日

RESTForms - 永続クラスにREST APIをアドオンする パート2: クエリ

最初の記事では、RESTForms(永続クラス用のREST API)について説明をしました。 基本的な機能についてはすでに説明しましたが、ここではクエリ機能を中心とする高度な機能について説明します。 * 基本クエリ * クエリ引数 * カスタムクエリ ### クエリ クエリを使用すると、任意の条件に基づいてデータの一部を取得できます。 RESTFormsには、2種類のクエリがあります。 * 基本クエリは一度定義すればすべてのRESTFormsクラスに対して機能します。異なっているのはフィールドリストのみです。 * カスタムクエリはそれが指定され、使用できるクラスに対してのみ機能しますが、開発者はクエリの本文に完全にアクセスできます。 ### 基本クエリ 一度定義すると、すべてのクラスか一部のクラスですぐに使用できます。 基本クエリはシステムによって定義されているものもありますが、開発者が追加することもできます。これらのクエリはすべて、SELECTのフィールドリストのみを定義します。 その他すべて(絞り込み、ページネーションなど)はRESTFormsによって行われます。 form/objects/:class/:query を呼び出すと、単純なクエリを実行できます。 2番目の :query パラメーターはクエリ名(クエリの SELECT と FROM の間の内容)を定義します。 デフォルトのクエリタイプは次のとおりです。 |クエリ|説明| |------------|-------------------------| |all|すべての情報| |info|displayName と id| |infoclass|displayName、id、class| |count|行数| 例えば、Form.Test.Personオブジェクトに関する基本的な情報を取得するには、infoclassクエリを実行できます。 form/objects/Form.Test.Person/infoclass {"children": [ {"_id":"1", "displayName":"Alice", "_class":"Form.Test.Person"}, {"_id":"2", "displayName":"Charlie", "_class":"Form.Test.Person"}, {"_id":"3", "displayName":"William", "_class":"Form.Test.Person"} ]} RESTFormsは次の場所で myq という名前のクエリを探します(最初にヒットするまで)。 1. フォームクラス内のqueryMYQクラスメソッド 2. クエリクラス内のMYQパラメーター 3. クエリクラス内のqueryMYQクラスメソッド 4. Form.REST.Objectsクラス内のMYQパラメーター 5. Form.REST.Objectsクラス内のqueryMYQクラスメソッド 独自のクエリクラスを定義できます(上記リストの項目2、3用)。このクエリクラスは、すべてのクラスで使用可能なクエリの定義を保持する特別なクラスです。 そのクラスで myq という名前の独自クエリを定義する手順は以下のとおりです。 1. (1回だけ)YourClassName クラスを定義します。 2. そのクラスで MYQ パラメーターか queryMYQ クラスメソッドを定義します。 パラメーターはメソッドよりも優先されます。 3. メソッドまたはパラメーターは、SQLクエリのSELECTとFROMの間の部分を返す必要があります。 4. (1回だけ)ターミナルで以下を実行します。 Do ##class(For.Settings).setSetting("queryclass", YourClassName) メソッドの署名は以下のとおりです。 ClassMethod queryMYQ(class As %String) As %String クラス固有のクエリを定義することもできます。 myq という名前の独自クラスクエリを定義する手順は以下のとおりです。 1. フォームクラスで queryMYQ クラスメソッドを定義します。 2. メソッドの署名は以下のとおりです。ClassMethod queryMYQ() As %String 3. メソッドは、SQLクエリのSELECTとFROMの間の部分を返す必要があります。 URL 引数 フィルターやその他のパラメーターをURLで指定できます。 すべての引数は省略可能です。 | 引数 | サンプル値 | 説明 | | ------------ | ------------------- | ----------------------------------------- | | size | 2 | ページサイズ | | page | 1 | ページ番号 | | filter | 値+contains+W | WHERE句 | | orderby | 値+desc | ORDER BY句 | | collation | UPPER | COLLATION句 | | nocount | 1 | レコード数を削除(クエリを高速化します)| これらの引数に関するいくつかの情報を次に示します。 ### ORDER BY句 結果の順序を変更します。 値は、カラム名またはカラム名+desc です。 カラム名は、SQLテーブルのカラム名またはカラム番号です。 ### WHERE句 絞り込み条件の書式は、カラム名+条件+値です。 カラム名+条件+値+カラム名2+条件2+値2のように、複数の条件を指定できます。 矢印構文とシリアルオブジェクトもサポートされています: Column_ColumnField+条件+値 Valueに空白が含まれている場合、サーバーに送信する前にタブに置き換えます。 | URL | SQL | | ---------------------- | -------------- | | neq | != | | eq | = | | gte | >= | | gt | > | | lte | <= | | lt | < | | startswith | %STARTSWITH | | contains | [ | | doesnotcontain | '[ | | in | IN | | like | LIKE | リクエストの例: form/objects/Form.Test.Simple/info?size=2&page=1&orderby=text form/objects/Form.Test.Simple/all?orderby=text+desc form/objects/Form.Test.Simple/all?filter=text+eq+Hello form/objects/Form.Test.Person/infoclass?filter=company_name+contains+a form/objects/Form.Test.Simple/all?filter=text+in+A9044~B5920 SQLアクセスには、ユーザーに適切なSQL権限(フォームテーブルに対するSELECT)を付与する必要があることに注意してください。 ### COLLATION句 書式は、collation=UPPER または collation=EXACT です。 指定した照合順序をWHERE句で強制します。 省略した場合、デフォルトの照合順序が使用されます。 ### ページネーション ページネーションは、デフォルトで1ページあたり25レコードになります。 ページサイズと現在のページを変更するには、size 引数と page 引数を(1を基準として)指定します。 ### カスタムクエリ form/objects/:class/custom/:query を呼び出すと、カスタムクエリを実行できます。 カスタムクエリを使用すると、開発者はクエリの内容全体を決めることができます。 size および page 以外のURLパラメーターは指定できません。 メソッドは他のすべてのURLパラメーターを解析する必要があります(またはForm.JSON.SQLからデフォルトのパーサーを呼び出す必要があります)。 myq という名前のカスタムクエリを定義する手順は以下のとおりです。 1. フォームクラスで customqueryMYQ クラスメソッドを定義します。 2. メソッドの署名は以下のとおりです。ClassMethod customqueryMYQ() As %String 3. メソッドは有効なSQLクエリを返す必要があります。 ### デモ [現在デモ環境はお試しいただくことができません。] こちらでRESTFormsをオンラインで試すことができます(ユーザー名:Demo、パスワード:Demo)。 また、RESTFormsUIアプリケーション(RESTFormsデータエディタ)もあります。こちらをご確認ください(ユーザー名:Demo、パスワード:Demo)。 クラスリストのスクリーンショットを以下に掲載しています。 ### まとめ RESTFormsは、幅広くカスタマイズ可能なクエリ機能を提供します。 ### 次の内容 次の記事では、いくつかの高度な機能について説明します。 * メタデータの解釈 * セキュリティと権限 * オブジェクト名 ### リンク * [RESTForms GitHubリポジトリ](https://github.com/intersystems-ru/RESTForms/) RESTForms UI GitHubリポジトリ
記事
Mihoko Iijima · 2022年10月23日

JP Core などのカスタムプロファイルを IRIS の FHIR リポジトリで検証する方法

FHIR開発者の皆さん、こんにちは! IRIS の FHIR リポジトリは、HL7 FHIR 標準プロファイルに対する検証をサポートしていますが、カスタムプロファイルに対する検証は、まだサポートできていません(将来のリリースバージョンで対応予定です)。 カスタムプロファイルの Search Parameter の追加はサポートしています!詳しくは、「動画:FHIR プロファイル」をご参照ください。 この記事では、IRIS の FHIR リポジトリに対して、カスタムプロファイルの検証を行う方法についてご紹介します。 方法としては、HL7 FHIR が提供している FHIR Validator で提供しているJARファイル(validator_cli.jar)を利用します。 利用のためには、FHIR リソースの検証のタイミングで、JARファイルの検証を実行するようにFHIRサーバサイドの動作をカスタマイズする必要があります。 ということで、大まかな準備は以下の通りです。 1) Java用外部サーバ(External Language Servers)の開始 IRISから FHIR Validator で提供しているJARファイル(validator_cli.jar)を利用するため、Java用外部サーバを開始します。 2) 検証ロジックを加工する FHIRリポジトリのデフォルトの動作を変更するため、FHIRサーバーサイドのカスタマイズクラス群を用意します(サンプルをご提供しています)。​​ イメージは以下の通りです。 今回は、FHIRリソースの検証を外部のJARファイルで行うため、FHIRサーバーサイドの加工(絵の青い破線の部分)を行いますが、この他にも、 「このリソースに〇〇というデータがあるときは登録させたくない」 「このリソースに△△のデータが含まれているときは応答として返したくない」 や、 患者さんのお名前を匿名化したい! のような実装を行う場合も、同様に、カスタマイズクラス群を作成します。 この記事では、外部の検証機能を使用するようにカスタマイズする流れをご紹介しますが、その他のカスタマイズ内容詳細については、以下記事をご参照ください。 FHIRリポジトリをカスタマイズしよう!パート1​ 「このリソースに〇〇というデータがあるときは登録させたくない」や「このリソースに△△のデータが含まれているときは応答として返したくない」のカスタマイズ例を紹介しています。 FHIRリポジトリをカスタマイズしよう!パート2(カスタムOperation編) 患者さんのお名前を匿名化するカスタムオペレーションの作成例を紹介しています。 デモをご覧いただく場合は、こちらのビデオをご覧ください。 それでは、具体的な手順をご紹介します。サンプルはこちら👉 https://github.com/Intersystems-jp/FHIRValidation-Test 事前準備:最初に、FHIR ValidatorのJARを利用して検証のテストを行います。 [1] JARのダウンロード validator_cli.jar を https://github.com/hapifhir/org.hl7.fhir.core/releases/latest/download/validator_cli.jar からダウンロードします。 サンプル一式をgit cloneまたはダウンロードいただいた場合は、lib にJARを配置してください。 もちろん、任意ディレクトリに配置することもできますが、JARの呼び出しをまとめたJavaサンプルコードのコンパイルなどを簡単に行っていただくため、compile.bat/compile.sh をご用意しています。 この bat/sh の中でJARの場所を指定してるので、サンプルをそのままご利用いただく場合は、lib 以下に配置してください。 [2] JDKのバージョンの確認 JDKのバージョンについては、https://confluence.hl7.org/pages/viewpage.action?pageId=35718580#UsingtheFHIRValidator-JDKVersionをご確認ください。 例では、OpenJDK11をインストールして利用しています。IRISがサポートするJDKについては、こちらをご参照ください。(8と11をサポートしています) [3]-1 JARの呼び出しをまとめたJavaファイルの準備(Windows) 1. 事前準備 環境変数 JAVA_HOMEにJavaインストールディレクトリを設定します。 2. JavaValidatorFacade.java をコンパイルする .\compile.bat 3. Jarファイルを作る .\updateJar.bat [3]-2 JARの呼び出しをまとめたJavaファイルの準備(Linux) 1. JavaValidatorFacade.java をコンパイルする ./compile.sh 2. Jarファイルを作る ./updateJar.sh [4]検証のテスト 検証初回実行時、標準プロファイルのパッケージがない場合、https://confluence.hl7.org/display/FHIR/FHIR+Package+Cache からスキーマをダウンロードするため初回のみ時間がかかります。 Windows の場合、以下ディレクトリに保存されます(通常のユーザの場合)。 C:\Users<username>.fhir Linuxの場合、以下ディレクトリに保存されます。 ~/.fhir サンプルファイル(test_Patient.json)を利用してテストを行います。 実行例).\run.bat または ./run.sh <プロファイルのJSONがあるディレクトリ> <テストするリソースのJSON> 《メモ》run.bat/run.sh の第1引数はカスタムプロファイル用ファイルを配置する予定のディレクトリを指定します(空でも実行できます)。例では、fhirprofileを指定しています。 以下、Windowsでの実行例です(WindowsとLinuxとで出力内容に違いはありません。)。 1つのワーニングが出ていますが、Success と返ります。 (ワーニングの理由:meta.profileに指定しているURLが実在しないため) PS C:\WorkSpace\FHIRValidation-Test> .\run.bat C:\WorkSpace\FHIRValidation-Test\fhirprofile\ C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json C:\WorkSpace\FHIRValidation-Test>"C:\Program Files\jdk-11\bin\java" -cp lib\validator_cli.jar;lib\JavaValidatorFacade.jar ISJSample.JavaValidatorFacade C:\WorkSpace\FHIRValidation-Test\fhirprofile\ C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json Load hl7.terminology.r4#4.0.0 - 4164 resources (00:04.784) Load C:\WorkSpace\FHIRValidation-Test\fhirprofile - 0 resources (00:00.005) Validate C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json Validate Patient against http://hl7.org/fhir/StructureDefinition/Patient..........20..........40..........60..........80.........| 00:00.485 Success: 0 errors, 1 warnings, 1 notes { "resourceType" : "OperationOutcome", "text" : { "status" : "extensions", "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><table class=\"grid\"><tr><td><b>Severity</b></td><td><b>Location</b></td><td><b>Code</b></td><td><b>Details</b></td><td><b>Diagnostics</b></td><td><b>Source</b></td></tr><tr><td>INFORMATION</td><td/><td>Structural Issue</td><td>Canonical URL 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' does not resolve</td><td/><td>No display for Extension</td></tr><tr><td>WARNING</td><td/><td>Structural Issue</td><td>Profile reference 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' has not been checked because it is unknown, and the validator is set to not fetch unknown profiles</td><td/><td>No display for Extension</td></tr></table></div>" }, "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-file", "valueString" : "C:\\WorkSpace\\FHIRValidation-Test\\sample\\test_Patient.json" }], "issue" : [{ "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line", "valueInteger" : 6 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col", "valueInteger" : 8 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source", "valueCode" : "InstanceValidator" }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id", "valueCode" : "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE" }], "severity" : "information", "code" : "structure", "details" : { "text" : "Canonical URL 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' does not resolve" }, "expression" : ["Patient.meta.profile[0]"] }, { "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line", "valueInteger" : 1 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col", "valueInteger" : 2 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source", "valueCode" : "InstanceValidator" }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id", "valueCode" : "VALIDATION_VAL_PROFILE_UNKNOWN_NOT_POLICY" }], "severity" : "warning", "code" : "structure", "details" : { "text" : "Profile reference 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' has not been checked because it is unknown, and the validator is set to not fetch unknown profiles" }, "expression" : ["Patient.meta.profile[0]"] }] } 続いて、test_Patient.json 15行目の gender に不正な値(例では"Man")を設定し、検証エラーが発生するか確認します。 今度は FAILUREと表示されます。(先ほどと同じワーニングに対するメッセージは省いています。) PS C:\WorkSpace\FHIRValidation-Test> .\run.bat C:\WorkSpace\FHIRValidation-Test\fhirprofile\ C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json C:\WorkSpace\FHIRValidation-Test>"C:\Program Files\jdk-11\bin\java" -cp lib\validator_cli.jar;lib\JavaValidatorFacade.jar ISJSample.JavaValidatorFacade C:\WorkSpace\FHIRValidation-Test\fhirprofile\ C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json Load C:\WorkSpace\FHIRValidation-Test\fhirprofile2 - 0 resources (00:00.004) Validate C:\WorkSpace\FHIRValidation-Test\sample\test_Patient.json Validate Patient against http://hl7.org/fhir/StructureDefinition/Patient..........20..........40..........60..........80.........| 00:00.428 *FAILURE*: 1 errors, 1 warnings, 1 notes { "resourceType" : "OperationOutcome", "text" : { "status" : "extensions", "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><table class=\"grid\"><tr><td><b>Severity</b></td><td><b>Location</b></td><td><b>Code</b></td><td><b>Details</b></td><td><b>Diagnostics</b></td><td><b>Source</b></td></tr><tr><td>ERROR</td><td/><td>Invalid Code</td><td>The value provided ('man') is not in the value set 'AdministrativeGender' (http://hl7.org/fhir/ValueSet/administrative-gender|4.0.1), and a code is required from this value set) (error message = Unknown Code http://hl7.org/fhir/administrative-gender#man in http://hl7.org/fhir/administrative-gender)</td><td/><td>No display for Extension</td></tr><tr><td>INFORMATION</td><td/><td>Structural Issue</td><td>Canonical URL 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' does not resolve</td><td/><td>No display for Extension</td></tr><tr><td>WARNING</td><td/><td>Structural Issue</td><td>Profile reference 'http://intersystems.com/fhir/ISJSample/StructureDefinition/JP_Patient' has not been checked because it is unknown, and the validator is set to not fetch unknown profiles</td><td/><td>No display for Extension</td></tr></table></div>" }, "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-file", "valueString" : "C:\\WorkSpace\\FHIRValidation-Test\\sample\\test_Patient.json" }], "issue" : [{ "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line", "valueInteger" : 15 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col", "valueInteger" : 21 }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source", "valueCode" : "TerminologyEngine" }, { "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id", "valueCode" : "Terminology_TX_NoValid_16" }], "severity" : "error", "code" : "code-invalid", "details" : { "text" : "The value provided ('man') is not in the value set 'AdministrativeGender' (http://hl7.org/fhir/ValueSet/administrative-gender|4.0.1), and a code is required from this value set) (error message = Unknown Code http://hl7.org/fhir/administrative-gender#man in http://hl7.org/fhir/administrative-gender)" }, "expression" : ["Patient.gender"] }, ここまでで、 FHIR Validator から提供されているJARを利用した検証のテストは完了です。 ここからは、IRIS の FHIRサーバーサイドのカスタマイズを行っていきます。 <カスタマイズ概要> 1) Java用外部サーバ(External Language Servers)の開始 2) 検証ロジックを加工する まずは、1) Java用外部サーバ(External Language Servers)の開始 を行うための手順をご紹介します。 [5] ISJSample.JavaValidatorFacade クラスを実行するためJava用外部サーバを起動 実行環境に合わせて設定を追加します。 管理ポータル > システム管理 > 構成 > 接続性 > External Lanaugae Server > %Java Server 設定項目 値 クラスパス validator_cli.jarとJavaValidatorFacade.jarのパス Java Home Directory Javaのインストールディレクトリ (図例はWindowsでの例です) 設定が終わったら start のリンクをクリックします。以下のようなログが表示されます。 Start External Language Server %Java Server: お待ちください...結果が以下に表示されます: 2022-10-07 19:48:59 Starting Java Gateway Server '%Java Server' 2022-10-07 19:48:59 Executing O.S. command: C:\Program Files\jdk-11\bin\java.exe -Xrs -Djava.system.class.loader=com.intersystems.gateway.ClassLoader -classpath C:\WorkSpace\FHIRValidation-Test\lib\validator_cli.jar;C:\WorkSpace\FHIRValidation-Test\lib\JavaValidatorFacade.jar;C:\InterSystems\IRISHealth\dev\java\lib\1.8\intersystems-jdbc-3.3.1.jar com.intersystems.gateway.JavaGateway 53272 "" "JP7430MIIJIMA:IRISHEALTH:%Java Server" 127.0.0.1 "" 2022-10-07 19:49:10 Execution returned: '' 2022-10-07 19:49:10 Gateway Server start-up confirmation skipped 2022-10-07 19:49:10 Starting background process to monitor the Gateway Server 2022-10-07 19:49:10 Job command successful, started monitor process '26376' ここからは、2) 検証ロジックを加工する を行うための手順をご紹介します。 [6]FHIRリポジトリのカスタマイズ用クラスの準備 以下説明は、IRIS for Health 2022.1を利用した例で記載しています。 詳細はドキュメント:FHIRサーバのカスタマイズ もご参照ください。 !!FHIRリポジトリを作成する前に、ネームスペースにカスタマイズ用クラス群を準備する必要があります!! サンプルでは、以下の説明に登場するクラス群をISJSample以下に用意しています。インポート方法は 「5.インポート」をご参照ください。 1. クラス一覧 それぞれのクラスの関係は以下のイメージです。 2.作成したクラスにパラメータを設定 最初から作成される場合は、以下のクラスパラメータを設定してください。サンプルをそのままご利用いただく場合は修正不要です。 1で作成したクラスにパラメータを設定します。 ISJSample.FHIRValidationInteractions クラス ResourceValidatorClassに検証実行用カスタムクラス名(ISJSample.FHIRResourceValidator)を指定 BatchHandlerClassにBundleのtype=batchまたはtransactionを処理するカスタムクラス名(ISJSample.FHIRBundleProcessor)を指定 ISJSample.FHIRValidationInteractionsStrategy クラス StrategyKeyにInteractionsStrategyの一意の識別子を指定 InteractionsClassにInteractionsのカスタムクラス名(ISJSample.FHIRValidationInteractions)を指定 ISJSample.FHIRBundleProcessor クラス BundleValidatorClassにBundle検証用カスタムクラス名(ISJSample.FHIRBundleValidator)を指定 ISJSample.FHIRValidationRepoManager クラス StrategyClassに InteractionStrategyのカスタムクラス名(ISJSample.FHIRValidationInteractionsStrategy)を指定 StrategyKeyにInteratcionsStrategyで指定したStrategyKeyの値を指定 《補足》 この他、ISJSample.FHIRValidationInteractionsクラスとISJSample.FHIRResourceValidatorクラスでメソッドをオーバーライドしています。 ISJSample.FHIRValidationInteractionsクラスでは、Bundleに含まれるリソースに対して検証が2回呼び出されないように StartTransactionBundle()メソッドとEndTransactionBundle()メソッドのオーバーライドしています。 %inTransactionFlag変数の設定を追加 Method StartTransactionBundle(pBundleTransactionId As %Integer) { do ##super(pBundleTransactionId) set %inTransactionFlag=$$$YES } Method EndTransactionBundle() { kill %inTransactionFlag do ##super() } ISJSample.FHIRResourceValidatorクラスでは、ValidateResource()をオーバーライドしています。 %inTransactionFlgが$$$YES ではないとき、検証を実行するように変更 Method ValidateResource(pResourceObject As %DynamicObject) { //do ##super(pResourceObject) if $get(%inTransactionFlag,$$$NO)'=$$$YES { do ##class(ISJSample.FHIRValidation).validate(pResourceObject) } } ISJSample.FHIRBundleValidator クラスでは、スーパークラスのValidateBundle()をオーバーライドし、ISJSample.FHIRValidationクラスのvalidate()を呼び出しています。 ClassMethod ValidateBundle(pResourceObject As %Library.DynamicObject, pFHIRVersion As %String) { //do ##super(pResourceObject,pFHIRVersion) do ##class(ISJSample.FHIRValidation).validate(pResourceObject) } 3. カスタム検証用クラス(ISJSample.FHIRResourceValidator)の修正 最初から作成される場合は、以下のクラスパラメータを設定してください。サンプルをそのままご利用いただく場合は修正不要です。 スーパークラスのValidateResource()をオーバーライドし、ISJSample.FHIRValidationクラスのvalidate()を呼びしています。 4.カスタム検証用クラスが使用するパラメータ値の設定 管理ポータル > Health > 作成したネームスペース > Configuration Registry に移動し、以下のKeyとValueを設定します。 項目名(Key) 設定例(Value) 意味 /FHIR/Validation/SkipIfNoProfile 1 設定値 1:検証をスキップする(リソースのmeta.profileの値が空や設定されていない場合に、検証をスキップする設定です。) 設定値 0:検証をスキップしない /FHIR/Validation/JavaGatewayServer 127.0.0.1 Java用外部サーバのIPアドレスまたはサーバ名 /FHIR/Validation/JavaGatewayPort 53272 Java用外部サーバが使用するポート番号 /FHIR/Validation/ProfileLocation C:\WorkSpace\FHIRValidation-Test\fhirprofile カスタムプロファイルのディレクトリを指定(フルパス) /FHIR/Validation/TerminologyServer (設定なし) TerminologyサーバのURLを指定 5.サンプルクラスのインポート VSCodeをお使いの方は、対象ネームスペースに接続後、ISJSampleディレクトリ を右クリックし[Import and Compile]をクリックします(または、クラス定義を Ctrl + S で保存することでインポートできます)。 スタジオをお使いの方は、対象ネームスペースに接続し、ISJSampleディレクトリ 以下 *.clsを複数選択し、スタジオのエリアにドラッグ&ドロップすることでインポートできます。 管理ポータルからインポートする場合は、管理ポータル > システムエクスプローラー > クラス > 対象ネームスペース選択 > [インポート]ボタンクリック で表示されるインポート画面でISJSampleディレクトリ を選択し、インポートを実行します。 詳細は図例をご参照ください。 [7]FHIRリポジトリの作成 InteratcionsStrategyクラスのカスタムクラスがコンパイル済であることを確認し、以下GUIで作成します。 管理ポータル > Health > 作成したネームスペース > FHIR Configuration > Server Configuration > Add Endpoint !!Interactions sterategy classに作成したクラス名: ISJSample.FHIRValidationInteractionsStrategyを指定してからリポジトリを作成して下さい!! リポジトリ作成後、デバッグモードから認証なし設定します(Debuggingの「Allow Unauthenticated Access」にチェック) [8]テスト実行 Postmanで以下実行します。 通常のPOSTでテストしてもいいのですが、何度も同じリソースを使って検証のテストを行うような場合には、リソースの検証だけを行う $validate オペレーションの利用が便利です。 例では、URL末尾に /$validate をつけています。この指定があるだけとリソースの検証のみを行うことができます(/$validate をなくして実行すると通常のPOST要求の流れで検証が行われます)。 設定項目 値 URL <エンドポイント>/Patient/$validate Method POST Header Content-Type に application/json+fhir;charset=utf-8 Body PatientリソースのJSON 結果は以下の通りです。 { "resourceType": "OperationOutcome", "issue": [ { "severity": "information", "code": "informational", "diagnostics": "All OK", "details": { "text": "All OK" } } ] } Bundleの場合は以下の通りです。 設定項目 値 URL <エンドポイント>/Bundle/$validate Method POST Header Content-Type に application/json+fhir;charset=utf-8 Body Bundle用JSON ここまでで、手続きは完了です。 次は、いよいよ、カスタムプロファイルの検証を実行してみます! [9]JPCoreのプロファイルを適用する方法 1.JPCoreのアーティファクトを用意する 公開されているJPCoreのプロファイル FHIR JP Core 実装ガイドパッケージをダウンロードされるか、公式Git を clone して、SUSHIを利用してImplementation Guide(IG)などのJSONのファイル群(アーティファクト)を作成する方法があります。 参照元:HL7FHIR JP Core実装ガイド<Draft Ver.1>の公開について(ご案内) 以下例は、2022年10月24日にダウンロードしたFHIR JP Core 実装ガイド V1.1.0 のパッケージを利用して記述しています。 ※2022年11月5日にダウンロードした v1.1.1のパッケージでも以下の例が動作することを確認しています。 2. 1.で用意したアーティファクトをプロファイル配置用ディレクトリにコピーして検証を実行する テストする場合は、run.bat または run.sh の第1引数にアーティファクトがあるディレクトリを指定します。 例では、 FHIR JP Core 実装ガイド にある V1.1のtgz版をダウンロードして展開したディレクトリにあるJSONファイルを fhirprofile以下にコピーした状態で実行しています。 以下、Windowsでの実行例です(WindowsとLinuxとで出力内容に違いはありません。)。 PS C:\WorkSpace\FHIRValidation-Test> .\run.bat C:\WorkSpace\FHIRValidation-Test\fhirprofile C:\WorkSpace\FHIRValidation-Test\sample\test_Patient-JPCore.json C:\WorkSpace\FHIRValidation-Test>"C:\Program Files\jdk-11\bin\java" -cp lib\validator_cli.jar;lib\JavaValidatorFacade.jar ISJSample.JavaValidatorFacade C:\WorkSpace\FHIRValidation-Test\fhirprofile C:\WorkSpace\FHIRValidation-Test\sample\test_Patient-JPCore.json Load hl7.terminology.r4#4.0.0 - 4164 resources (00:04.947) Load C:\WorkSpace\FHIRValidation-Test\fhirprofile - 241 resources (00:00.465) Unable to generate snapshot for http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest: Attempt to use a snapshot on profile 'http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequestBase' as Base for generating a snapshot for the profile http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest before it is generated Unable to generate snapshot for http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest_Injection: Attempt to use a snapshot on profile 'http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequestBase' as Base for generating a snapshot for the profile http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest_Injection before it is generated Unable to generate snapshot for http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest: Profile JP_MedicationRequest (http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest), element null. Error generating snapshot: Error sorting Differential: The element MedicationRequest.dosageInstruction is out of order (and maybe others after it) Unable to generate snapshot for http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest_Injection: Profile JP_MedicationRequest_Injection (http://jpfhir.jp/fhir/core/StructureDefinition/JP_MedicationRequest_Injection), element null. Error generating snapshot: Error sorting Differential: The element MedicationRequest.dosageInstruction is out of order (and maybe others after it) Validate C:\WorkSpace\FHIRValidation-Test\sample\test_Patient-JPCore.json Validate Patient against http://hl7.org/fhir/StructureDefinition/Patient..........20..........40..........60..........80.........| Validate Patient against http://jpfhir.jp/fhir/core/StructureDefinition/JP_Patient..........20..........40..........60..........80..........100| 00:00.641 Success: 0 errors, 0 warnings, 1 notes { "resourceType" : "OperationOutcome", "text" : { "status" : "extensions", "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p>All OK</p><table class=\"grid\"><tr><td><b>Severity</b></td><td><b>Location</b></td><td><b>Code</b></td><td><b>Details</b></td><td><b>Diagnostics</b></td></tr><tr><td>INFORMATION</td><td/><td>Informational Note</td><td>All OK</td><td/></tr></table></div>" }, "extension" : [{ "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-file", "valueString" : "C:\\WorkSpace\\FHIRValidation-Test\\sample\\test_Patient-JPCore.json" }], "issue" : [{ "severity" : "information", "code" : "informational", "details" : { "text" : "All OK" } }] } 実行に指定しているtest_Patient-JPCore.jsonには、JPCoreが定義しているextension.Race(患者の人種)の情報が含まれます。 例) "birthDate": "1970-01-01", "extension":[ { "url": "http://jpfhir.jp/fhir/core/Extension/StructureDefinition/JP_Patient_Race", "valueCodeableConcept": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v3-Race", "code": "2039-6", "display": "Japanese" } ] } } ], 3. IRISから実行する。 実行前にカスタムプロファイルのアーティファクトがあるディレクトリが正確に設定されているか確認します。 IRISの管理ポータル > Health > ネームスペース選択 > Configuration Registry > /FHIR/Validation/ProfileLocation Valueを確認 《メモ》Configuration Registry の Key には、ISJSample.FHIRValidationクラスに定義されているパラメータ名を設定しています。 Value の取得は以下ユーティリティクラスのメソッドを実行することで取得できます。 ##class(HS.Registry.Config).GetKeyValue(..#ProfileLocationKEY) 設定値が管理ポータルで変更できるので、プロファイルを参照する場所を変える場合は、/FHIR/Validation/ProfileLocation を変更するだけでOKです。 以下、Postmanからのテスト例です。 設定項目 値 URL <エンドポイント>/Patient/$validate Method POST Header Content-Type に application/json+fhir;charset=utf-8 Body JPCore対応用PatientリソースのJSON 検証がOKであることを確認したら、JPCoreのプロファイルを正しく認識しているかどうかテストするため、患者の人種(Race)の情報に誤ったデータタイプの情報を設定し検証します。 RaceのデータタイプはExtension(CodeableConcept)が指定されているため、valueCodeableConceptにCodeableConceptタイプの情報を持つ必要がありますが、以下の例では、valueStringにstringの情報を設定しています。 "extension":[ { "url": "http://jpfhir.jp/fhir/core/Extension/StructureDefinition/JP_Patient_Race", "valueString":"日本人" } ], 以下、Postmanからのテスト例です。 設定項目 値 URL <エンドポイント>/Patient/$validate Method POST Header Content-Type に application/json+fhir;charset=utf-8 Body JPCore対応用PatientリソースのJSON:検証失敗用 例と同様に、JPCore V1.1のtgz版プロファイルを利用している場合のPatientリソース内タイプの確認については、https://jpfhir.jp/fhir/core/V1B/StructureDefinition-jp-patient.html をご参照ください。 RESTクライアントからの実行結果は以下の通りです。(CodeableConceptのタイプではなくstringの情報が来ていることでエラーが発生しています) { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "structure", "diagnostics": "5001", "details": { "text": "This element does not match any known slice defined in the profile http://jpfhir.jp/fhir/core/Extension/StructureDefinition/JP_Patient_Race and slicing is CLOSED: Patient.extension[0].value.ofType(string): Does not match slice 'valueCodeableConcept' (discriminator: ($this is CodeableConcept))" }, "expression": [ "Patient.extension[0].value.ofType(string)" ] }, { "severity": "error", "code": "structure", "diagnostics": "5001", "details": { "text": "The Extension 'http://jpfhir.jp/fhir/core/Extension/StructureDefinition/JP_Patient_Race' definition allows for the types [CodeableConcept] but found type string" }, "expression": [ "Patient.extension[0]" ] } ] } 以上です! 最後までお読みいただきありがとうございました 今回の記事は、JP Coreのカスタムプロファイルの適用でご紹介しましたが、カスタムプロファイルの作成からコンパイルまでの手続きなどについては、以下の記事でご紹介しています。 FHIRプロファイル作成ツールであるSUSHIの握り方使い方を紹介している記事 👉 SUSHIを使ってFHIRプロファイルを作成しようパート1 Extensionの追加と、Extensionで追加した項目に対するSearchParameterの定義を行い、IRISのFHIRリポジトリに適用し、新しいSearchParameterが利用できるまでの流れをご紹介している記事 👉 SUSHIを使ってFHIRプロファイルを作成しようパート2 ぜひご覧ください!
記事
Toshihiko Minamoto · 2020年10月8日

Ansible を使った Caché アプリケーションのプロビジョニング(パート 1)

Ansible は Caché とアプリケーションコンポーネントをいかに迅速にデータプラットフォームのベンチマークにデプロイするかという課題を解決するのに役立ちました。 同じツールと方法をテストラボ、トレーニングシステム、開発環境、またはその他の環境の立ち上げも使うことができます。 顧客サイトにアプリケーションをデプロイする場合、デプロイの大部分を自動化し、アプリケーションのベストプラクティス標準に合わせてシステム、Caché、アプリケーションを確実に構成することができます。 ## 概要 テクノロジーアーキテクトである私たちのグループの仕事の一つに、さまざまなベンダーのハードウェアやオペレーティングシステムでの InterSystems データプラットフォームのベンチマークがあります。 多くの場合、インフラストラクチャはリリース前のものであり、返却や他者への引き渡しが必要になるまでの時間が決まっているため、ベンチマークを迅速かつ正確に設定し、実際のベンチマーク作業にできるだけ多くの時間をかけることが不可欠です。 私たちは長年にわたってシェルスクリプトレットとチートシートやチェックリストからのカットアンドペーストを使用し、多くのベンチマークインストール作業を自動化していましたが、多くのサーバーがあり、異なるオペレーティングシステムを使用する場合は特に非常に激しくエラーが発生する傾向がありました。SLES 11、Red Hat 6、Red Hat 7、AIX などでのサービスのインストールや使用には、微妙で厄介な違いがある場合があるからです。 私はシステムの自動構成と管理に使用できるいくつかのソフトウェアオプションを検討した後、データプラットフォームアプリケーションとベンチマークコンポーネントをプロビジョニングする作業のために Ansible を選択しました。 なお、Ansible がデプロイと構成に**最適な**ソリューションであると決めつけているわけではありませんのでご了承ください。 私は Ansible を選択する前に、Puppet や Chef などの他のツールの機能や操作を確認しました。 あなたの組織がすでに他のツールを使用しており、あなたがそれを使用できるのなら、私が Ansible で使用する方法やコマンドなどは他のソフトウェアに読み替えることができるはずです。この投稿が、使用しているツールに関係なく役立つことを願っています。 これは、InterSystems データプラットフォームのアプリケーションをデプロイする際に Ansible を使用する方法を説明する連載の最初の投稿です。 この投稿では、Caché をインストールして基盤を構築する方法について説明します。次の投稿では、ソリューションを拡張し、%installer クラスの使用を含むアプリケーションのインストールについて掲載します。 この記事では以下について説明します。 * Ansible の概要とインストール。 * 簡単な管理とスケーリングのための Ansible のレイアウト。 * 1つ以上のサーバーでの Caché のインストール。 ## Ansible とは? Ansible では複雑なタスクを自動化しながら1つ以上のサーバーを構成でき、新しいサーバーを非常に簡単に追加できます。 タスクは冪等性が保たれるように設計されています(同じサーバーで同じスクリプトを何度でも実行でき、結果のサーバー構成は同じになります)。 Ansible をプロビジョニングタスク用に選択した主な理由は、システム要件が最小(Linux サーバーに Python 2.7 がインストールされていること)であり、自己完結型のソリューションであることです。Ansible のコードは管理サーバーにのみインストールされ、プッシュアーキテクチャを使用して OpenSSH 経由でターゲットサーバー上のコマンドとスクリプトを実行します。 プロビジョニングされるサーバーにはエージェントは必要ありません。 対照的に、Chef と Puppet はプルクライアントアーキテクチャであり、クライアントサーバー(Web、データベースなど)にソフトウェアが読み込まれ、クライアントは継続的に更新をマスターにポーリングします。 Ansible のプッシュアーキテクチャは、スケジュールに応じてサーバーを段階的に実装するのにも適しています。 Ansible はオープンソースであり、コミュニティによってメンテナンスされています。 Ansible, Inc は 2015 年 から Red Hat が所有しています。 Ansible, Inc は付加価値の高いライフサイクル製品(Ansible Tower)と共に有償のサポートとトレーニングを提供していますが、この投稿で使用されているものはすべてオープンソースのコマンドラインバージョンです。 活発なコミュニティ(Ansible Galaxy)があり、Web サーバー、ftp、Kerbros のインストールなどの多数のタスク用にダウンロードできる既成のソリューションが豊富に存在し、拡充され続けています。 完全なベンチマークのデプロイプロジェクトの例に、RHEL、SLES、または Solaris に(他のプラットフォームと共に)Apache 2.x をインストールして構成するためにダウンロードしてカスタマイズした Apache モジュールを含めています。 Ansible のダウンロードとインストールの手順は、Ansible の Web サイトと github にあります。 質問がある場合や貢献したい場合は、活発なコミュニティがあります。 https://www.ansible.com/get-started http://docs.ansible.com ## Ansible のインストール この投稿の例は、Red Hat 7.0 および 7.2 が稼働中の VM でテストされています。また、Centos 7 を搭載した私のノートパソコンで VirtualBox と Vagrant を使用し、Ansible コントローラーサーバーの初期テストも行いました。 Caché をコントローラーにインストールする必要はないため、Caché でサポートされているよりも多くのプラットフォームからオペレーティングシステムを選択できます。 話を簡単にするため、私は Red Hat で利用可能な Ansible の最新 rpm バージョン(Ansible 1.9.4)を使用しました。それ以降のバージョンは github から入手できます。 この例では、cache-2015.2.2.805.0-lnxrhx64 をインストールしていますが、HealthShare または Ensemble ディストリビューションにも同じ一般的な手順を適用できます。 後述するように、特定のファイル名、ディレクトリパスなどの変数を使用してインストールオプションをパラメーター化します。 この最初の投稿ではタスクを基本的な Caché のインストールに限定しています。そのため、ほとんどのタスクはプラットフォームに依存しません。 Ansible プレイブックが開始する最初のタスクの 1 つは、ターゲットマシンのマニフェスト(オペレーティングシステム、インターフェースカード、メモリ情報、CPU 数、ディスクレイアウトなど)を取得することです。このターゲットオペレーティングシステムの情報は、ターゲットで実行される実際のコマンドから Ansible スクリプトのコマンドを抽象化するためにコマンドが実行される際に使用されます(Red Hat の service httpd on や SLES の /etc/init.d/apache2 など)。 ここでは皆さんがプラットフォームの説明に従い、説明を読んで管理マシンに Ansible をインストールしたと想定します。 Ansible では Linux システムをコントローラーとして使用する必要がありますが、ターゲットシステムは Linux または Windows にすることができます。 Windows ターゲットの詳細については、Ansible のドキュメントを参照してください。 ### コントローラーシステムのインストール例:RHEL/CentOS 7 64ビット上の Ansible Red Hat または CentOSでは、Ansible を含む epel-release(Enterprise Linux 用の追加パッケージ)RPM を先にインストールする必要があります。 epel プロジェクトは多くの有用なオープンソースパッケージ(ネットワーク、システム管理、監視など)をまとめて提供しており、主要な Linux ディストリビューション向けに設計されています。 [root@localhost tmp]# wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm : : [root@localhost tmp]# rpm -ivh epel-release-7-5.noarch.rpm : : [root@localhost tmp]# yum --enablerepo=epel info ansible Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Installed Packages Name : ansible Arch : noarch Version : 1.9.4 Release : 1.el7 Size : 7.0 M Repo : installed From repo : epel Summary : SSH-based configuration management, deployment, and task execution system URL : http://ansible.com License : GPLv3+ Description : : Ansible is a radically simple model-driven configuration management, : multi-node deployment, and remote task execution system. Ansible works : over SSH and does not require any software or daemons to be installed : on remote nodes. Extension modules can be written in any language and   : are transferred to managed machines automatically. [root@localhost tmp]# [root@localhost tmp]# sudo yum install ansible : : [root@localhost tmp]# ansible --version ansible 1.9.4     configured module search path = None **成功しました。 始めましょう!** ## Ansible について インベントリ、プレイブック、モジュール、ロールなどのさまざまな Ansible コンポーネントの使用方法を Ansible のドキュメントでよく確認する必要があります。 管理を単純化し、大規模で複雑なスクリプトファイルを回避するため、事前定義されたディレクトリ構造と検索パスが使用されています。 この投稿では Ansible の推奨事項を使用し、より大きなインストールの例を作ることを検討する際のモデルとして使用できるファイル構造を使用する予定です。 使用されている Ansible モジュールはコメントが付いた分かりやすいもので、github から入手できます。 ファイルをダウンロードして内容を読み、ワークフローの感触をつかんでください。 この例のベースディレクトリには、次のファイルがあります。 * ansible.cfg:Ansible のデフォルト値を変更します。 * inventory:作業環境を定義し、記述します (サーバー名/IPなど)。 * >任意の名前<.yml ファイル:これらのファイルは、特定のサーバーのロールに対して実行されるタスクセットを記述します。 ### 用語集 今後の説明をより分かりやすくするため、いくつかの Ansible 用語について簡単に説明します。 モジュールは、システムで実行する自動化アクションを作成するビルディングブロックです。 各モジュールは特定のタスク用に構築されており、パラメーターを使用してそのタスクを変更できます。 例えば、ファイルのコピー、ユーザーの作成、コマンドの実行、サービスの開始などがあります。 現在、デフォルトの Ansible インストールには 400 種類以上のモジュールが含まれており、さらにはコミュニティからも多くのモジュールが提供されていますが、独自に作成することもできます。 モジュールは自動化ワークフローを実行する手段として、プレイとプレイブックを作成するために組み合わされます。 プレイは複数のタスクを持つことができ、プレイブックは複数のプレイを持つことができます。 ロールを使うと、複数のプレイブックを組み合わせることができます。 ロールは、ターゲットサーバーの使用状況に応じてサーバーのコンポーネント構成をグループ化するものと考えることができます。 この投稿のロールの例では、サーバーを構築するための構成レイヤーを構築します。 私のベンチマーク環境では、次のロールを使用してサーバーを構築しています。 * hs\_server\_common: OS の構成、Apache のインストール、Caché のインストール。 *  webserver: Webファイル(csp、html、js など)のコピー、アプリケーション用のApacheの構成。 * generator: ファイルのコピー、Webストレスジェネレーターのデータベース / ネームスペース / グローバルマッピングなどの作成と構成。 * dbserver:ファイルのコピー、DBサーバーシステムの設定 / アプリケーションデータベース / ネームスペース / グローバルマッピングなどの構成。 これらのロールを組み合わせて、さまざまなサーバータイプを構築できます。 * hs\_server\_common + webserver + generator = Web ストレスジェネレーターサーバー。 * hs\_server\_common + webserver = アプリケーション Web サーバー。 * hs\_server\_common + dbsevrer = データベースサーバー。 ロールを構成するものや各ロールに含まれる構成は、デプロイされるアプリケーションによって大きく異なります。 この投稿の例では、オペレーティングシステムの事前構成を前提とする最小限のタスクセットを使用しますが、Ansible や Galaxy で利用可能なモジュールを使用すると、はるかに複雑なフル機能のシステム構成が可能になります。 ## Caché のインストールに関するメモ {.MsoNormal} 私はいくつかの興味く便利な機能を紹介するため例を記載しましたが、その中でも以下は特に注目すべきものです。 注: これらの例は、InterSystems データプラットフォーム(Caché、HealthShare、Ensemble)をインストールするためのガイドとして使用できます。 HealthShare をインストールする例を書きましたが、HealthShare と Caché には同じ機能があります。 **./testserver/roles/hs\_server\_common/tasks/main.yml** これは、一般的な OS の構成、Apache のインストール、Caché のインストールの各タスクに使えるメインラインスクリプトです。 この投稿ではCaché をインストールおよび構成するため、Red Hat のインクルードファイルのみに短縮しています。 Ansible が起動した後、オペレーティングシステムの情報がスクリプトで決定を行うために使用できる _ansible\_os\_family_ などの _ansible_* _変数に保持されていることがわかります。 **./testserver/roles/hs\_server\_common/tasks/configure-healthshare2015.yml** これは、Caché をインストールするためのメインスクリプトです。 スクリプトを見ると、次のようなターゲット上のタスクの論理ワークフローがわかります。 * オペレーティングシステムのユーザーとグループを作成する。 * コントローラーのマニフェストフォルダーからインストールファイルをコピーする。 * インストールファイルを解凍する。 * サイレントインストールを使用して Caché をインストールする(以下の注意書きを参照)。 * Caché キーファイルをコピーする。 * デフォルト Caché インスタンスを設定する。 * Apache を再起動する。 * Caché を再起動する。 Caché のサイレントインストールには、次のようないくつかのオプションがあります。 * parameters.is ファイルを使用する。 テンプレートの .isc ファイルは以前のインストールによって作成されたもので、そのまま使用することも、変更して使用することもできます。 * 環境で設定されたキーと値のペアで cinstall_silent を使用する。 * %installer クラスを使用する。 この例では、install\_silent を使用することを選択しましたが、Ansible でテンプレートファイルを使用する方法を示すため、パラメーターファイルを使用する代替方法もコメントに含めています(./roles/hs\_server\_common/templates/parameters\_hs20152_rh64.isc を参照してください)。 後の投稿では、Caché をインストールする際とデータベースおよびネームスペースを設定する際に %installer クラスを使用する方法を説明します。 インストールオプションの詳細は、Caché のオンラインドキュメントで確認できます。また、コミュニティには %installer クラスの使用に関する素晴らしい投稿もあります。 パラメーターファイルは、旧バージョンの Caché で Caché 組み込みの Apache バージョン以外の Web サーバで CSP Gateway を使用するように Cachéをインストールして構成する場合に役立ちます。 この機能は、Caché 2016.1の %installer で使用できます。 **./testserver/roles/hs\_server\_common/tasks/setup_RedHat.yml** この例は、システム固有の変数(ansible_*)の使用方法とオペレーティングシステム変数の設定を説明するためのものです。 **./testserver/roles/hs\_server\_common/vars/*** 変数ファイルのキーと値のペアには変数が含まれています。ご覧のとおり、さまざまな環境や状況で同じスクリプトを再利用することができます。 ## Caché インストールの実行 この例では、システムが使用可能であり、次のように設定されていることを想定しています。 1. コントローラーに Ansible がインストールされており、次のディレクトリに GitHub からファイルと構造が読み込まれていること。 * **./testserver/*** :  インベントリ、.yml ファイルなどを含むディレクトリツリー。 次のディレクトリを含みます。 * **./testserver/Distribution_Files/Cache** :  (Caché ディストリビューションと cache.key を含むマニフェスト)。 2. ターゲットマシンに Red Hat と Apache がインストールされていること。 テスト環境に合わせてインストールをカスタマイズするには、次のファイルを編集する必要があります。 1. **inventory_test** テストサーバー名または IP アドレスを編集する必要があります。 2. **./testserver/roles/hs\_server\_common/vars/healthshare2015.yml** テスト環境に合わせてパスを編集する必要があります。 ターゲットサーバーの次のパスを確認します。 * **common\_install\_base_path**: マニフェストファイルがコピーされ、解凍され、Caché インストールが実行されるパスです。 * **ISC\_PACKAGE\_INSTALLDIR**: Caché のインストールディレクトリです。 ディレクトリパスが存在しない場合は、ターゲットサーバー上に作成されます。 注意: 自動デプロイの機能の一つに、複数サーバーの並行構築があります。 インベントリファイルに複数のサーバーがある場合、各ステップが各ターゲットサーバーで同時に完了した後、次のステップがグループ内の各サーバーで開始します。 いずれかのサーバーでステップが失敗した場合、スクリプトは停止します。 また、問題解決に役立つエラーメッセージが表示されます。 エラーを解消したら、再び最初から実行するだけです。これは、冪等性が保たれるように設計されているというスクリプトの重要な特徴です。 冪等性とは、あるモジュールが例えばファイルコピーを目的としてステップ内で実行される際、ファイルがすでに存在した場合はそのステップが再実行されず、スクリプトが次のステップに進むことを意味します。 コピーなどのモジュールにはコピーを強制するように設定できるパラメーターがありますが、これはデフォルトではありません。 スクリプトを詳しく調べると、"creates" パラメータがいくつかのケースで使用されていることがわかります。次に例を示します。 - name: unattended install of hs using cinstall_silent shell: > ISC_PACKAGE_INSTANCENAME="{{ ISC_PACKAGE_INSTANCENAME }}" ISC_PACKAGE_INSTALLDIR="{{ ISC_PACKAGE_INSTALLDIR }}" ISC_PACKAGE_UNICODE="{{ ISC_PACKAGE_UNICODE }}" ISC_PACKAGE_INITIAL_SECURITY="{{ ISC_PACKAGE_INITIAL_SECURITY }}" ISC_PACKAGE_MGRUSER="{{ ISC_PACKAGE_MGRUSER }}" ISC_PACKAGE_MGRGROUP="{{ ISC_PACKAGE_MGRGROUP }}" ISC_PACKAGE_USER_PASSWORD="{{ ISC_PACKAGE_USER_PASSWORD }}" ISC_PACKAGE_CACHEUSER="{{ ISC_PACKAGE_CACHEUSER }}" ISC_PACKAGE_CACHEGROUP="{{ ISC_PACKAGE_CACHEGROUP }}" ./cinstall_silent chdir="{{ common_install_base_path }}/{{ hs_install_unpack_path }}" args: creates: "{{ ISC_PACKAGE_INSTALLDIR }}/cinstall.log" 上の節は creates パラメータを使用し、このアクションが cinstall.log ファイルを作成することを Ansible モジュール(この場合は shell モジュール)に知らせています。 モジュールがこのファイルを検出した場合(Caché はすでにインストールされている状態)、このステップは実行されません。 すべての設定が完了したら、インストールを実行できます。 $ ansible-playbook dbserver.yml PLAY [dbservers] ************************************************************** GATHERING FACTS *************************************************************** ok: [db1] TASK: [hs_server_common | include_vars healthshare2015.yml] ******************* ok: [db1] TASK: [hs_server_common | include_vars os-RedHat.yml] ************************* ok: [db1] etc etc etc TASK: [hs_server_common | Create default cache group] ************************* changed: [db1] TASK: [hs_server_common | Create default cache manager group] ***************** changed: [db1] TASK: [hs_server_common | Create default cache user] ************************** changed: [db1] TASK: [hs_server_common | Create default cache system users] ****************** changed: [db1] TASK: [hs_server_common | Create full hs install temp directory] ************** changed: [db1] TASK: [hs_server_common | Check tar file (gunzipped already) does not exist] *** ok: [db1] TASK: [hs_server_common | Copy healthshare install file] ********************** changed: [db1] TASK: [hs_server_common | un zip hs folder] *********************************** changed: [db1] TASK: [hs_server_common | un tar hs install] ********************************** changed: [db1] TASK: [hs_server_common | Create hs install directory] ************************ changed: [db1] TASK: [hs_server_common | touch ztrak.conf.] ********************************** changed: [db1] TASK: [hs_server_common | Process parameters file] **************************** changed: [db1] TASK: [hs_server_common | unattended install of hs using cinstall_silent] ***** changed: [db1] TASK: [hs_server_common | copy hs key] **************************************** changed: [db1] TASK: [hs_server_common | Set default hs instance] **************************** changed: [db1] TASK: [hs_server_common | restart apache to initialize CSP.ini file] ********** changed: [db1] NOTIFIED: [hs_server_common | restart healthshare] **************************** changed: [db1] PLAY RECAP ******************************************************************** db1 : ok=32 changed=21 unreachable=0 failed=0 ターゲットサーバーを見ると、db サーバーの Caché が稼働しています。 $ ccontrol list Configuration 'H2015' (default) directory: /test/hs2015 versionid: 2015.2.1.705.0 conf file: cache.cpf (SuperServer port = 1972, WebServer = 57772) status: running, since Wed Feb 17 15:59:11 2016 state: ok ## 最後に 次の投稿では、構成ファイルの編集や %installer クラスを使用したアプリケーションの構成など、他のタスクでスクリプトを構築します。 この投稿に興味を持ち、独自のデプロイを作成し始めた方は、ご質問やご提案がございましたらお気軽にお問い合わせください。 私は仮想化とパフォーマンスについて Global Summit で定期的に講演を行っています。今年の Global Summit に参加される予定の方は自己紹介をお願いします。Ansible やその他のシステムアーキテクチャに関する皆様のご経験をお聞かせください。
記事
Shintaro Kaminaka · 2021年10月18日

FHIRリポジトリをカスタマイズしよう!パート2(カスタムOperation編)

## 特報!! この記事の中でご紹介している、FHIRオペレーションのデモを含め、FHIR PathやFHIRプロファイル対応などの2021.1のFHIR関連新機能をご紹介するウェビナーが、**2021年10月21日 12:30~13:00** に開催されます!!ご興味ある方はこちらからご登録ください!! ### [InterSystems IRIS 開発者向けウェビナーシリーズ](https://www.intersystems.com/jp/iris-tech-webinar/) 開発者の皆さん、こんにちは。 今日は前回の[FHIRリポジトリをカスタマイズしよう!パート1](https://jp.community.intersystems.com/node/504516)の記事に続き、パート2として、カスタムオペレーションの実装方法をご紹介したいと思います。この記事で紹介している内容のFHIRリポジトリカスタムオペレーションに関するドキュメントマニュアルは[こちら](https://docs.intersystems.com/irisforhealthlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=HXFHIR_server_customize_operations)になります。 この記事はIRIS for Health 2021.1 をベースに記載しています。バージョンによって実装方法が異なるケースも考えられますので、該当のバージョンのドキュメントをご参照ください。場合によっては新しいバージョンへアップグレードもご検討ください。 ## FHIRのOperation(オペレーション)とは? まず、FHIRのOperationについて、簡単にご紹介したいと思います。 HL7 FHIR公式ページの[Operationのページ](http://hl7.org/fhir/operations.html)には以下のように記載されています。 > The RESTful API defines a set of common interactions (read, update, search, etc.) performed on a repository of typed resources. These interactions follow the RESTful paradigm of managing state by Create/Read/Update/Delete actions on a set of identified resources. **While this approach solves many use cases, there is some functionality that can be met more efficiently using an RPC-like paradigm, where named operations are performed with inputs and outputs (Execute).** FHIRにおけるデータのアクセスがRESTのCRUDを基本とするのはご存知の通りですが、RPC的なアプローチでより効率的なデータアクセス、データ処理を実現しようというアプローチがFHIRのOperationと言えます。 HL7 FHIR公式ページで規定されているOpeartionは[こちら一覧のページ](http://hl7.org/fhir/operationslist.html)に記載されています。 代表的な所では、Patientリソースで指定できる *$everything* オペレーションや、Observationリソースで指定できる *$lastn* オペレーションがありますので紹介します。 # $everything オペレーション *$everything* オペレーションはPatientリソースと組み合わせて使用します。詳細は[こちらのページ](http://hl7.org/fhir/patient-operation-everything.html)を参照してください。 IRIS for Health のFHIRリポジトリの場合は、リソースの論理IDまで指定して ``` GET /Patient/5/$everything ``` のように指定して実行できます。 この場合、Patientリソースの論理ID=5に紐づいた関連するリソース(Observation, MedicationRequest, Procedure, Encounter など)を自動的に収集してBundle形式でクライアントに返してくれます。 例えばある患者さんの診療情報を一覧として見せたい場合などには便利な機能です。 # $lastn オペレーション *$lastn* オペレーションはObservationリソースと組み合わせ使用します。詳細は[こちらのページ](http://hl7.org/fhir/observation-operation-lastn.html)を参照してください。 IRIS for Health のFHIRリポジトリの場合は以下のように指定できます。categoryおよびpatient(またsubject)は必須の指定パラメータとなっています。 ``` GET /Observation/$lastn?max=10&category=vital-signs&patient=Patient/123 ``` このクエリでは、PatientリソースのID=123の患者に関連した、「vital-signs」カテゴリーに含まれる、最新 **10件** のObservationリソースがBundle形式でクライアントに返されます。直近のデータだけを使ってグラフを表示したい、というようなニーズにはぴったりですね。 ## カスタムオペレーションを作成してみよう FHIRのオペレーションとはどのようなものか?具体例を2つ挙げてご紹介しました。 カスタムオペレーションはこのようなオペレーションを、プロジェクトのニーズに応じて、自分で定義して実装し利用することができるようになる機能です。定義したカスタムオペレーションはCapability Statementに含めて公開することができます。 以下の手順でカスタムオペレーションを構築することができます。 # 1. 3つのカスタムクラス(Interactions等)を用意する まず、最初の手順として、前回の[FHIRリポジトリをカスタマイズしよう!パート1](https://jp.community.intersystems.com/node/504516)で記載した、3つのカスタムクラスを用意します。詳しい内容はパート1の記事をご覧ください。 # 2. カスタムオペレーション用のクラスを用意し、Interactionsクラスから参照する Interactionsクラス等と同様に、カスタムオペレーション用のクラスを継承します。 HS.FHIRServer.Storage.BuiltInOperationsを継承し、任意の名称のクラスを作成します。この記事ではCustomFS.MyOperationとします。 (場合によっては、HS.FHIRServer.API.OperationHandlerクラスを継承して作成することもありますが、FHIRリポジトリを利用している場合は、HS.FHIRServer.Storage.BuiltInOperationsを継承し、$everythingなどの実装済みのオペレーションが引き続き使用できるようにする必要があります。詳細はドキュメントをご覧ください。) これでFHIRリポジトリのカスタマイズに関連して作成したクラスは4つになりましたね。 | ベースクラス | 継承して作成したクラス | |:----------|:------------| | HS.FHIRServer.Storage.Json.Interactions | CustomFS.MyInteractions | | HS.FHIRServer.Storage.Json.InteractionsStrategy | CustomFS.MyInteractionsStrategy | | HS.FHIRServer.Storage.Json.RepoManager | CustomFS.MyRepoManager | | (new!) **HS.FHIRServer.Storage.BuiltInOperations** | **CustomFS.MyOperation** | さらに、このFHIRリポジトリのサーバ処理でこのカスタムオペレーション用のクラスが使用されるように、InteractionsクラスのOperationHandlerClassパラメータでこのクラスを指定します。 ``` Class CustomFS.MyInteractions Extends HS.FHIRServer.Storage.Json.Interactions { Parameter OperationHandlerClass As %String = "CustomFS.MyOperations"; ``` # 3. カスタムオペレーションの処理を実装する いよいよ、具体的にカスタムオペレーションの処理内容を実装していきます。2.で作成した、CustomFS.MyOperationsクラス内にメソッドを作成して実装します。 まず作成するオペレーションは影響範囲の応じて3つに分けることができます。 この3つの影響範囲=Scope + オペレーション名により、作成するべきメソッド名が決まってきます。 ### メソッド名命名ルールについて メソッド名命名には以下のようなルールがあります。 FHIR*Scope*Op*OperationName* まずメソッド名の先頭は **FHIR** です。 次に *Scope* には以下の3つのタイプのいずれかが入ります。 | Scope | 説明 | |:----------|:------------| | **System** | "ベース" の FHIR エンドポイントに追加する操作を指定します (例えば、http://fhirserver.org/fhir)。これらの操作は、サーバ全体に適用されます。 | | **Type** | FHIR エンドポイントにリソース・タイプと共に追加する操作を指定します (例えば、http://fhirserver.org/fhir/Patient)。これらの操作は、指定されたリソース・タイプのすべてのインスタンスで動作します。 | | **Instance** | リソースの特定のインスタンスを指す FHIR エンドポイントに追加する操作を指定します (例えば、http://fhirserver.org/fhir/Patient/1)。これらの操作は、リソースの特定のインスタンスでのみ動作します。 | 以下の図も影響範囲の理解の参考になると思います。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss1.jpg) そして、"Op" に続き、先頭を大文字にしたオペレーション名が続きます。 例えば、「$deleteall」というカスタムオペレーションをSystemレベルで作成したいなら **FHIRSystemOpDeleteall** というメソッドを作成します。 「$anonymize」というカスタムオペレーションをInstanceレベルで作成したいなら **FHIRInstanceOpAnonymize** というメソッドを作成します。 つまり **"FHIR" _ (System or Type or Instance) _ "Op" _ (先頭大文字にしたオペレーション名)** という命名ルールですね。 ### メソッドの実装方法 では、実際に、Instanceレベルの$anonymizeオペレーションを作成していきましょう。このオペレーションの目的はPatientリソースのnameエレメントの中身を匿名化)(*******で埋める)を実装することです。 このメソッドは ``` GET /Patient/5/$anonymize ``` のような形で実装されることを想定しています。 上記の例ででてきたように、FHIRInstanceOpAnonymizeメソッドを以下のように実装します。サンプルなので詳細なエラーハンドリングまでは実装していません。 ``` ClassMethod FHIRInstanceOpAnonymize(pService As HS.FHIRServer.API.Service, pRequest As HS.FHIRServer.API.Data.Request, pResponse As HS.FHIRServer.API.Data.Response) { ///RestClientクラスを利用してFHIRサーバへのアクセスを実行。指定された論理IDのPatientリソースを取得する Set clientObj = ##class(HS.FHIRServer.RestClient.FHIRService).CreateInstance(pRequest.SessionApplication) Do clientObj.SetResponseFormat("JSON") set clientResponseObj=clientObj.Read(pRequest.RequestMethod,pRequest.Type,pRequest.Id) set pResponse.Json=clientResponseObj.Json set pResponse.Status=clientResponseObj.Status set pResponse.ETag=clientResponseObj.ETag set pResponse.LastModified=clientResponseObj.LastModified set pResponse.Location=clientResponseObj.Location set pResponse.IsPrettyOut=clientResponseObj.IsPrettyOut //匿名化処理を実行する if pResponse.Status="200" { //DynamicObjectからnameエレメントのIteratorを取得し繰り返し処理 set iter=pResponse.Json.name.%GetIterator() while iter.%GetNext(.key,.value) { do pResponse.Json.name.%Get(key).%Set("text","***********") do pResponse.Json.name.%Get(key).%Set("family","***********") do pResponse.Json.name.%Get(key).%Set("given","***********") } } } ``` パート1のカスタマイズ処理では、実際に検索(GET)されたデータや、送信(POST/PUT)されたデータに対してカスタム処理を実施しましたが、オペレーションの場合はベースとなる検索を実行する必要があります。もちろん、オペレーションの実装目的によっては、検索をする必要がない場合もあるでしょう。 このメソッドでは、得られた検索結果に対して、DynamicObjectのデータ操作を使用して、データを更新し匿名化を行っています。 # 4. 作成したカスタムオペレーションの定義をCapability Statementに追加する 次に、ロジックを作成したカスタムオペレーションの定義をCapability Statementに追加します。まず、先ほどと同じCustomFS.MyOperationクラスにCapability Statement追加用のAddSupportedOperationsメソッドを記述します。 ``` ClassMethod AddSupportedOperations(pMap As %DynamicObject) { Do ##super(pMap) Do pMap.%Set("anonymize","http://myfhirserver/fhir/OperationDefinition/patient-anonymize") } ``` メソッド内の、pMap.%Setの最初の引数は"オペレーション名"、2番目の引数はそのオペレーションの定義を表すURIを記載します。 2番目の引数は例えば、先述のPatient/[id]/$everything オペレーションであれば、[こちらのページ](http://hl7.org/fhir/patient-operation-everything.html)に記載されているように > http://hl7.org/fhir/OperationDefinition/Patient-everything となります。例えば、あるデータ連携プロジェクトに基づいて実装した場合は、そのプロジェクトの実装ガイド内で規定されたURIになるでしょうし、自プロジェクト内で利便性のために構築したということであれば、任意のURIを指定することもできます。 次にコマンドラインユーティリティを起動して、この変更を反映します。 以下はCUSTOMFSネームスペース内で実行した例になります。 ``` USER>zn "customfs" CUSTOMFS>d ##Class(HS.FHIRServer.ConsoleSetup).Setup() Query returns no results HS.FHIRServer.Installer:InstallNamespace Created FHIR web application HS.FHIRServer.Installer:InstallNamespace Created FHIR API web application What do you want to do? 0) Quit 1) Create a FHIRServer Endpoint 2) Add a profile package to an endpoint 3) Display a FHIRServer Endpoint Configuration 4) Configure a FHIRServer Endpoint 5) Decommission a FHIRServer Endpoint 6) Delete a FHIRServer Endpoint 7) Update the CapabilityStatement Resource 8) Index new SearchParameters for an Endpoint 9) Upload a FHIR metadata package 10) Delete a FHIR metadata package Choose your Option[1] (0-10): 7 For which Endpoint do you want to update the CapabilityStatement? 1) /csp/healthshare/customfs/fhir/r4 [enabled] (for Strategy 'CustomFS' and Metadata Set 'hl7.fhir.r4.core@4.0.1') Choose the Endpoint[1] (1-1): 1 Update the /csp/healthshare/customfs/fhir/r4 service CapabilityStatement to reflect the endpoint strategy. Proceed? (y/n): yes ``` 以上の手順を実行すると、FHIRリポジトリのCapability Statementにカスタムオペレーションのエントリが追加されます! Capability StatementはFHIRリポジトリに以下のリクエストをすると取得できます。anonymizeオペレーションがちゃんと追加されていますね。 ``` GET http://fhirserver/csp/healthshare/customfs/fhir/r4/metadata ``` ``` "operation": [ { "name": "everything", "definition": "http://hl7.org/fhir/OperationDefinition/Patient-everything" }, (略) { "name": "anonymize", "definition": "http://myfhirserver/fhir/OperationDefinition/patient-anonymize" }, ``` # 5. 実行して動作を確認してみよう 以上で、カスタムオペレーション $anoymize の実装は完了です。早速動作確認してみましょう! まずカスタムオペレーションなしで普通にPatientリソースのデータをリクエストしてみます。 ``` GET http://localhost:52785/csp/healthshare/customfs/fhir/r4/Patient/2 ``` 私のデモ環境では、以下のようなnameエレメントを持つデータが格納されていました。 ``` { "resourceType": "Patient", "id": "2", (略) "name": [ { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "IDE" } ], "use": "official", "text": "山田 太郎", "family": "山田", "given": [ "太郎" ] }, { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "SYL" } ], "use": "official", "text": "ヤマダ タロウ", "family": "ヤマダ", "given": [ "タロウ" ] } ``` 次に、実装した $anonymizeを追加して実行してみます! ``` GET http://localhost:52785/csp/healthshare/customfs/fhir/r4/Patient/2/$anonymize ``` 以下のように匿名化されたデータが取得できました! ``` { "resourceType": "Patient", "id": "2", (略) "name": [ { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "IDE" } ], "use": "official", "text": "***********", "family": "***********", "given": "***********" }, { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "SYL" } ], "use": "official", "text": "***********", "family": "***********", "given": "***********" } ], ``` # カスタマイズを実装する際のTips パート1、パート2とIRIS for HealthのFHIRリポジトリをカスタマイズする方法をご紹介してきました。 ここで、カスタマイズの際のTipsを一つご紹介します。 IRISのFHIRリポジトリ処理では、パフォーマンス最適化のために、個別のプロセス内でFHIR処理用のサービスインスタンスが起動され、再利用される仕組みになっています。そのため、条件によっては、サーバ側のカスタム処理を書き換えたのにそれが反映されないことがあります。そのような際にはいくつかの対応方法があります。 1. FHIR Server Configurationページで「New Service Instance」のチェックを有効にする 開発環境であれば、この方法をお勧めします。FHIRリクエスト毎に新しいService Instanceが立ち上がるので、必ず変更が反映されます。ただし、パフォーマンスへの影響を考えると、本番環境で設定することはお勧めしません。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss2.jpg) 2. Web Gateway Management 画面からすべてのセッションをクリアする  System Status画面ですべてのセッションをクリアすることによって、起動しているIRIS側のプロセスもすべて再起動されます。下記画像の黄色の部分をクリックします。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss3.jpg) 3. 再起動する(常に最強の手段) ## まとめ いかがでしたでしょうか? IRIS for HealthのFHIRリポジトリカスタマイズ機能を利用することによって、プロジェクト開発で求められる様々な要件に柔軟に対応することができます。もちろん、カスタマイズを多用することが、FHIRの持つ汎用性に影響を及ぼすことを考慮する必要がありますが、パート1/2の記事でご紹介したカスタマイズ機能を効果的に使えば、より高度なFHIRアプリケーションの構築も可能になります。 パート1、パート2の内容を含むIRISのクラスを[こちらのGitHubサイト](https://github.com/Intersystems-jp/FHIR_Customize)からダウンロードすることができます。 また新たなカスタマイズ手法が実装されたらこちらの開発者コミュニティで紹介したいと思います。