Nova postagem

Pesquisar

Artigo
· Set. 17, 2024 5min de leitura

FHIR Object Modelを使ったInteroperability開発

開発者の皆さん、こんにちは。

突然ですが、2024年6月25日に開発者向けセミナー「FHIR 新機能のご紹介~2024.1~」が開催されました。
ご視聴になられた方も多数いらっしゃると思います。
まだご視聴になられていない方は是非一度、ご覧になってみてください。
YouTubeリンク

さて、こちらのセミナーにおいてご紹介された、IRIS for Health 2024.1からの新機能「FHIR Object Model」を用いて、リポジトリタイプのInteroperability開発の具体的なサンプルを作成してみました。
自身の備忘のため、すぐ開発環境を構築できるよう、コンテナ環境かつGitHubの公開もしております。
利用方法は、GitHub内のREADMEを参照ください。
GitHubリンク

目次

  1. FHIR Object Modelとは?

  2. メリット・デメリットを深堀り

  3. GitHub公開ソースについて

  4. 所感


1. FHIR Object Modelとは?


まずはFHIR Object Modelとはなにか、簡単に説明します。
FHIR Object Modelとは、FHIRリソースをオブジェクトモデル化したクラス群です。
IRIS for HealthでFHIR開発に多く携わっている方は、あれ?と思うわけです。
既に公開中のJSONテンプレートエンジンとなにが違うの?メリット・デメリットは?書き替えた方がいいの?
だいぶ主観が入りますが、JSONテンプレートエンジンとの比較をしてみたいと思います。

 

1.1. JSONテンプレートエンジンとなにが違う?


JSONテンプレートエンジン
こちらは、テンプレートクラスに記載されたテンプレートを元に、プロパティやパラメータ値を設定してJSONデータを出力します。
一方、FHIR Object Modelは、FHIRの全リソース構造を網羅したクラスを元に、プロパティを設定してFHIRオブジェクトに変換し、操作・編集が容易なクラスライブラリです。より詳細を知りたい方は、冒頭のリンクのYouTube動画を見ていただくと理解が深まると思います。


1.2. メリット・デメリットは?

  • メリット
  1. 自身でなにも用意しなくていい!ゼロベースで(IRIS for Healthをインストールさえしてあれば)使える
  2. オフィシャルのためIDEのサポートが充実
  3. DynamicAbstractObjectとの相互変換メソッド
  • デメリット
  1. 入れ子になったオブジェクトの操作は慣れが必要
  2. カスタムプロファイルに対応したモデルクラスがない
  3. 日本語ベースのドキュメントがほぼない

 

1.3. 書き替えた方がいいの?

 

個人的な意見は NO です。なぜならば、FHIR Object ModelはあくまでFHIR開発のサポートを行うためのツールであり、既に実装済みのコードがあるのであれば、書き替えるほどの強力なインパクトはありません。

 

2. メリット・デメリットを深堀り

  • メリット
  1. 自身でなにも用意しなくていい、という真意は、JSONテンプレートエンジンを利用しようとすると、どうしても自身でテンプレートクラスを作成しなくてはいけない作業が発生します。JSONテンプレートエンジンは、用意されているリソースの数に限りがあるのと、元々退院時サマリーのFHIRモデルをベースにしたテンプレートのためです。一方、FHIR Object Modelは、現状R4ベースという制限はあるものの、リソース定義がすべてクラス化されており、使い方さえわかればすぐ開発に取り掛かれます。
  2. IDEのサポートが充実しているのは、自動入力補完機能(オートコンプリート)が利用できるのと各メソッド、各プロパティにDescriptionがちゃんと(英語ですが)ついていることに尽きると思います。
  3. セミナー内の絵を拝借しますが、文字列、ダイナミックオブジェクト、FHIR Modelオブジェクトは、各クラスごとに用意されているメソッドで相互に変換でき、利用の幅が広がります。

 

  • デメリット
  1. IncludeXXXX() と MakeEntry()、そして add() する順番などが最初混乱しました。慣れてしまえば問題はないかと。
  2. カスタムプロファイルに対応したモデルクラスがないのは惜しいです。今後のリリースに期待いたします。
  3. まだ新しい機能なので、使い方や応用、実務向けサンプルなどが少ないです。だからこそ本記事を書いております。少しでもご参考になれば幸いです。


3. GitHub公開ソースについて


リポジトリタイプのInteroperabilityをコードベースで作成しました。
環境は、コンテナで動作するIRIS for Health Community 2024.1です。
インプットデータはCSVファイルで、レコードマップを定義しています。

  • Patientリソースを作成するためのPatient.csv
  • Observationリソースを作成するためのBodyMeasurement.csv

の2つを用意しており、どちらのリソースもサンプルのCSVを取り込むと常にBundleリソースに含めてtype=transactionでPOSTする形式です。

set bundle = ##class(HS.FHIRModel.R4.Bundle).%New()
set bundle.type = "transaction"
do bundle.IncludeEntry()
// ここまでは初回(bundle.entryに初めてaddするとき)のみ実行
set entry = bundle.entry.MakeEntry()
set entry.fullUrl = "urn:uuid:"_$ZCONVERT($SYSTEM.Util.CreateGUID(),"L")
do entry.IncludeResource()
// resource = HS.FHIRModel.FHIRClassSuper(HS.FHIRModel.R4.Patientなど)
set entry.resource = resource
do entry.IncludeRequest()
set entry.request.method = "POST"
set entry.request.url = resource.resourceType
do bundle.entry.add(entry)


とはいえ、Patientリソースのほうは「identifier.system|identifier.value」の条件で、存在すればPOSTしないifNoneExistプロパティを追加していますので、同じ患者IDのPatientリソースは作成されないようにしています。

// GitHubソース上では、先述のコードサンプルの bundle.entry.add() の前に入れ込んでいます
set:resource.resourceType="Patient" entry.request.ifNoneExist = "identifier=urn:oid:1.2.392.100495.20.3.51.11234567890|"_resource.identifier.get(0).get("value")


概要図はコチラです。

 

4. 所感


新機能!と思って飛びついてみましたが、IRIS経験者であればさほど苦も無く利用できると思います。
オフィシャルであることも強みで、今後の拡張やサポートにも期待しております。
GitHubのソースについて、なにかご質問あればコメントください。わかる範囲でご回答いたします。

Discussão (0)1
Entre ou crie uma conta para continuar
Anúncio
· Set. 16, 2024

第2回 開発者コミュニティ・ミートアップ Python ワークショップの事前準備について

※ 本内容は随時更新予定です。ワークショップに必要な内容をご覧いただき、参加のご検討などしていただければ幸いです。

Pythonワークショップにご参加いただく場合は、事前に以下の環境をご用意ください。

  • IRIS 2024.1.1 for Windows Community Edition (※ これからダウンロードされる方は、バージョンが異なりますので下記コメントをご確認ください)
    • キットダウンロードはこちらの記事をご覧ください。
    • インストールオプションはデフォルト (インストールタイプ: 開発、初期セキュリティ設定: 最小)
  • Visual Studio Code (任意のバージョン) と ObjectScript用エクステンション
    • エクステンションのインストール方法はこちらの記事をご覧ください。
  • 以下のPythonライブラリを irispip (<IRISインストールディレクトリ\bin\irispip.exe) でインストール
    • flask, nicegui, sqlalchemy-iris,  scikit-learn,  numpy, pandas
8 Comments
Discussão (8)2
Entre ou crie uma conta para continuar
Pergunta
· Set. 16, 2024

What is the best way to do a silent install of an IRIS application?

We have an ObjectScript application that runs in Cache' and IRIS. Our typical installation involves a .zip file containing several files necessary for the installation and operation of the application. Steps are: expand the .zip file to a folder that will not be used by the application. Do ^%RI for the installation routines in the production namespace. Do the Installation routine. We have a customer that is trying to do a silent installation. He does not want to have to respond to any prompts on the installation. We do have a silent option for the Installation routine and that is working well. But he also does not want to have to respond to prompts for the Do ^%RI step. Currently we are doing set sc=$System.OBJ.Export(routineString,destinationPath.xml). And then we can do a set sc=$System.OBJ.Load(destinationPath.xml,"cuk",.errlog) in the installation script.

Is there a better way to do this?

3 Comments
Discussão (3)2
Entre ou crie uma conta para continuar
Artigo
· Set. 16, 2024 5min de leitura

Native Python dans IRIS, partie 2

Dans la section précédente, nous avons exploré le processus d'installation et initié l'écriture de l'IRIS en Python natif. Nous allons maintenant examiner la traversée globale et nous intéresser aux objets de classe IRIS. 

get : cette fonction est utilisée pour obtenir des valeurs à partir du nœud de traversée.

def traversal_firstlevel_subscript():
    """
    ^mygbl(235)="test66,62" and ^mygbl(912)="test118,78"
    """
    for  i in irispy.node('^mygbl'):
        print(i, gbl_node.get(i,''))

node et items : parcours à un seul niveau avec nœud et obtenir les mêmes valeurs que $Order(^mygbl(subscript), direction, data)

#single level traversal
def traversal_dollar_order_single_level():
    for  sub,val in irispy.node('^mygbl').items():
         print('subscript:',sub,' value:', val)
# multi level traversal
def traversal_dollar_order_multi_level():
    for  sub,val in irispy.node('^mygbl').items():
         print(f'sub type is: {type(sub)} {sub} and val type is {type(val)}')
         for sub1,val1 in irispy.node('^mygbl',sub).items():
            print('subscript:',sub1,' value:', val1)
        

nextsubscript : contrairement au code ci-dessus, vous pouvez utiliser nextsubscript pour obtenir facilement l'indice suivant

def traversal_dollar_order_use_nextsubscript():
      direction = 0
      next_sub = ''
      while next_sub != None:
            next_sub = irispy.nextSubscript(direction,'^mygbl', next_sub)
            print(f'next subscript = {next_sub}' )
            next_sub1=''
            if next_sub == None:return
            while next_sub1 != None:
                next_sub1 = irispy.nextSubscript(direction,'^mygbl',next_sub,next_sub1)
                print(f'1st subscript = {next_sub} next subscript {next_sub1}' )

Classes et objets

Vous pouvez appeler les méthodes de classe, les méthodes de la définition de classe en utilisant la fonction spécifique. Comme je l'ai mentionné plus tôt, les méthodes de conversion de type sont essentielles pour obtenir la réponse appropriée d'IRIS.

Avant cela, il est important de noter que, contrairement aux types de données IRIS, pour lesquels nous pouvons tout traiter comme des chaînes, les types de données Python tels que int, str, bool et list sont classés comme des objets. Chacun de ces types possède ses propres attributs et méthodes ; par exemple, le type de chaîne Python inclut des fonctions telles que .upper() et .lower(), qui ne sont pas applicables aux autres types de données. Par conséquent, IRIS est équipé de la capacité de convertir les valeurs de chaîne IRIS en objets de type de données pris en charge par Python grâce à l'utilisation de méthodes de conversion de type. Cette fonctionnalité s'applique également aux méthodes de classe, aux fonctions définies par l'utilisateur et aux procédures. Alternativement, il faut utiliser les fonctions de conversion de type de Python pour obtenir le type de données souhaité.

classMethodValue : appelez la méthode Classmethod depuis Python sans initialiser l'objet comme (ex : Do ##Class(Test.MYTest).FirstNameGetStored(1)) et obtenez la valeur par défaut de « string » en Python. Il existe différentes méthodes de conversion de type disponibles pour la valeur de retour attendue au lieu de la chaîne. Veuillez vous référer ci-dessous.

def get_clsmethod_value():
    print(irispy.classMethodValue('Test.MYTest','FirstNameGetStored',1)) #return string 
    date_horolog = irispy.classMethodInteger('Test.MYTest','GetHorolog') #return +$H value
    print(irispy.classMethodVoid('Test.MYTest','SetTestGlobal','test')) # no return resposne

classMethodObject : Fonction importante pour instancier un nouvel objet IRIS ou ouvrir l'objet existant. Définissez les propriétés et appelez les méthodes d'instance, etc.

Nouvel objet IRIS : initiez l'objet de classe pour Test.MYTest et définissez les propriétés.

def cls_object_new():
    """
    initiate new object and store
    """
    iris_proxy_obj = irispy.classMethodObject('Test.MYTest','%New','ashok','kumar')

    birthdate_horolog = irispy.classMethodInteger('Test.MYTest','GetHorolog','12/12/1990')
    horolog = irispy.classMethodInteger('Test.MYTest','GetHorolog')
    iris_proxy_obj.set('BirthDate',birthdate_horolog) #set birthdate property
    iris_proxy_obj.set('RegisteredDate',horolog) #set the RegisteredDate property
    status = iris_proxy_obj.invoke('%Save') #call instance method
    return status

Ouvrez l'objet IRIS : dans le code ci-dessous. Ouvrez l'objet de classe Test.MyTest et récupérez les valeurs Birthdate et RegisteredDate à partir de l'objet avec l'ID  = « 2 » et convertissez RegisteredDate en liste Python

def cls_object_open():
    iris_proxy_obj = irispy.classMethodObject('Test.MYTest','%OpenId',2)
    birth_date = iris_proxy_obj.get('BirthDate')
    full_name iris_proxy_obj.InvokeString("GetFullName")
    data = [birth_date, iris_proxy_obj.get('RegisteredDate')]
    return data

Définition de la classe IRIS que j'ai utilisée pour la démonstration du code Python de classe et d'objet

 
Spoiler

Méthodes de conversion de type :

il s'agit de quelques méthodes de conversion de type permettant de récupérer les valeurs de retour appropriées d'IRIS

classMethodValue() - pour appeler des méthodes de classe générales

classMethodInteger - Renvoie une valeur integer
classMethodVoid - Aucune valeur de retour
classMethodValue - string par défaut
classMethodFloat - valeur float


invoke() - est utilisé pour appeler les méthodes d'instance. Vous devez initialiser l'objet pour appeler ces fonctions d'appel

invokeString - string par défaut
invokeFloat - float par défaut
invokeInteger - integer par défaut

Nous aborderons les fonctions, les appels de procédure dans les routines et d'autres fonctionnalités dans le prochain article.

Discussão (0)2
Entre ou crie uma conta para continuar
Anúncio
· Set. 16, 2024

HealthShare Unified Care Record Overview - Virtual October 8-9, 2024 - Registration space available

  • HealthShare Unified Care Record Overview – Virtual October 8-9, 2024
    • The HealthShare Unified Care Record Overview course is a great way for anyone to become familiar with Unified Care Record, but especially those who need to understand its capabilities but not how to configure HealthShare Unified Care Record.
    • This is a non-technical, instructor-led in person training course providing a comprehensive introduction to HealthShare Unified Care Record.
    • This course is for anyone who needs to know about the functionality and architecture of HealthShare Unified Care Record.  (If you need information on configuring and troubleshooting Unified Care Record, consider the HealthShare Unified Care Record Fundamentals class.)
    • No prior knowledge or experience is required for the Overview class and any InterSystems employee may enroll.
  • Self-Register Here
Discussão (0)1
Entre ou crie uma conta para continuar