文章 Kelly Huang · 十月 23, 2025 21m read

概述

快捷式医疗服务互操作资源 (FHIR) 是一个由 HL7 International 开发的标准化框架,旨在以灵活、对开发者友好且现代的方式促进医疗数据的交换。 它利用现代网络技术来确保在医疗保健系统间实现无缝集成与通信。

关键 FHIR 技术

  • 用于资源交互的 RESTful API
  • 用于数据表示的 JSON 和 XML
  • 用于安全授权和身份验证的 OAuth2

FHIR 围绕着称为资源的模块化组件构建,每个组件代表特定的医疗保健概念,包括:

  • 患者 – 受众特征和标识符
  • 观察数据 – 临床测量数据(例如,生命体征、实验室检测结果)
  • 诊疗 – 患者与医疗服务提供者的互动
  • 药物、过敏不耐受、健康状况等

资源单独定义,并且可以引用其他资源,以构成一个完善的数据模型。


InterSystems IRIS for Health:FHIR 支持

InterSystems IRIS for Health 是一个专为医疗保健行业设计的统一数据平台。 它包含对 HL7 FHIR 的原生支持。 它提供内置工具与服务,能够实现 FHIR 资源的存储、检索、转换和交换。IRIS 通过三大 FHIR 处理组件提升系统的互操作性:

1.FHIR 仓库服务器

IRIS 可以快速部署符合 FHIR 标准的服务器,并支持以下功能:

  • 完整的 FHIR 范式
  • 实现 FHIR RESTful API,包括搜索和查询参数
  • 导入并利用 FHIR 软件包和结构定义
  • 使用 FHIR 配置文件
  • 对 FHIR 资源进行原生 CRUD 操作
  • 以 JSON 或 XML 格式检索 FHIR 数据
  • 支持多种 FHIR 版本
  • FHIR SQL Builder 和批量 FHIR 处理功能

2. FHIR 装饰层

FHIR 装饰层是用于在现有架构(通常为非 FHIR 架构)之上提供符合 FHIR 标准的 API 接口的软件架构模式。 它还能简化医疗保健数据系统,包括电子健康记录系统 (EHR)、旧版数据库或 HL7 v2 消息存储库,无需将所有数据迁移到 FHIR 原生系统中。

此实现专门围绕 FHIR Interoperability Adapter 展开。

3. FHIR Interoperability Adapter

InterSystems IRIS for Health 具备高度灵活性和精细控制能力,可以实现 HL7 V2.x、C-CDA 等医疗消息标准与 FHIR 之间的双向转换​​(参见“消息转换示意图”)。 不过,部分 FHIR 实现需要使用专用的 FHIR 仓库服务器。 为支持此类场景,InterSystems IRIS for Health 内置了一套互操作性适配器工具包,无需使用 FHIR 服务器即可实现详细的消息转换。

此适配器能够处理来自外部系统的各种外部请求(例如, REST 或 SOAP API 请求),将这些请求转换为 FHIR 格式,然后路由到下游系统,且无需将数据持久存储在数据库中。

如有需要,该适配器也可以对数据进行转换并将其存储在数据库中。

它能有效提供外部接口层,使非 FHIR 数据库可以像 FHIR 服务器一样运行,从而实现无缝互操作性。

消息转换

SDA:摘要文档架构

摘要文档架构 (SDA) 是 InterSystems 推出的基于 XML 的中间格式,用于在 IRIS 和 HealthShare 产品内部表示患者数据。 利用这种功能强大的原生数据结构,您可以访问离散数据,并轻松实现多种数据格式之间的转换,包括 HL7 V2、CCDA、C32、HL7 FHIR 等。

SDA 结构

SDA(结构化数据架构)主要分为两个组成部分:

  1. 容器 – 包含一个或多个部分的顶层结构
  2. 部分 – 特定医疗元素(例如,患者、诊疗、过敏不耐受)的表示

容器

容器是 SDA 标准的顶层结构,其中包含多个部分(例如,患者、诊疗、过敏不耐受等)。

我们来深入探讨一下 SDA 的内部结构及其组成部分。

容器的类定义:

HS.SDA3.Container 类作为表示 SDA 文档的主要定义。 各个部分(如患者、诊疗)均定义为对象,并作为属性包含在此 class.Sections 中。

“部分”是指容器元素的独立片段,它以 IRIS 类定义的形式表示,并包含容器上的相关数据元素。

  1. 患者 – HS.SDA3.Patient
  2. 诊疗 – HS.SDA3.Encounter
  3. 过敏症 - HS.SDA3.Allergy

SDA 容器结构

以下 XML 结构表示整个 SDA 容器。

<Container><Patient/><Encounters/><Encounters/><AdvanceDirectives/></Container>

 

SDA 数据类型

FHIR 数据类型格式与 IRIS 标准数据类型不同。 因此,SDA 具有特定的自定义数据类型,与 %String、%Integer、%Stream 等标准属性相比,这些数据类型可以更有效地处理部分中的属性。 不过,标准属性也用于 SDA 部分中。

相应数据类型类也在 HS.SDA3* 软件包中定义:

  • HS.SDA3.Name
  • HS.SDA3.CodeTableDetail.Allergy
  • HS.SDA3.PatientNumber
  • HS.SDA3.TimeStamp

SDA 扩展

大多数情况下,SDA 具有充足的属性来管理和生成系统中传输的所有数据,以开发资源。 不过,如果您需要在实现过程中加入额外的数据,IRIS 提供了一种简单直接的方式可以帮助您轻松地将相应数据扩展到 SDA 扩展类中。

例如,HS.Local.SDA3.AllergyExtension 类定义是 HS.SDA3.Allergy 的扩展类。 您可以向此扩展类添加必要的数据元素,从而简化整个实现过程中的访问和操作流程。

下一步是创建容器对象。


创建容器对象

ClassMethod CreateSDAContainer()
{
<span class="hljs-keyword">set</span> SDAContainer = <span class="hljs-keyword">##class</span>(HS.SDA3.Container).<span class="hljs-built_in">%New</span>()

#<span class="hljs-comment">; create patient object</span>
<span class="hljs-keyword">set</span> patientSDA = <span class="hljs-keyword">##class</span>(HS.SDA3.Patient).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> patientSDA.Name.FamilyName = <span class="hljs-string">"stood"</span>
<span class="hljs-keyword">set</span> patientSDA.Name.GivenName = <span class="hljs-string">"test"</span>
<span class="hljs-keyword">set</span> patientSDA.Gender.Code=<span class="hljs-string">"male"</span>
<span class="hljs-keyword">set</span> patientSDA.Gender.Description=<span class="hljs-string">"birth gender"</span>
#<span class="hljs-comment">; create Encounter 1</span>
<span class="hljs-keyword">set</span> encounterSDA  = <span class="hljs-keyword">##class</span>(HS.SDA3.Encounter).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> encounterSDA.AccountNumber = <span class="hljs-number">12109979</span>
<span class="hljs-keyword">set</span> encounterSDA.ActionCode =<span class="hljs-string">"E"</span>
<span class="hljs-keyword">set</span> encounterSDA.AdmitReason.Code =<span class="hljs-string">"Health Concern"</span>
<span class="hljs-keyword">set</span> encounterSDA.AdmitReason.Description = <span class="hljs-string">"general health concern"</span>
#<span class="hljs-comment">; create Encounter 2</span>
<span class="hljs-keyword">set</span> encounterSDA1  = <span class="hljs-keyword">##class</span>(HS.SDA3.Encounter).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> encounterSDA1.AccountNumber = <span class="hljs-number">95856584</span>
<span class="hljs-keyword">set</span> encounterSDA1.ActionCode =<span class="hljs-string">"D"</span>
<span class="hljs-keyword">set</span> encounterSDA1.AdmitReason.Code =<span class="hljs-string">"reegular checkup"</span>
<span class="hljs-keyword">set</span> encounterSDA1.AdmitReason.Description = <span class="hljs-string">"general health ckeckup"</span>
#<span class="hljs-comment">; set the patientSDA into the container.</span>
<span class="hljs-keyword">set</span> SDAContainer.Patient = patientSDA

#<span class="hljs-comment">; set multiple encounters into the container SDA</span>
<span class="hljs-keyword">do</span> SDAContainer.Encounters.Insert(encounterSDA)
<span class="hljs-keyword">do</span> SDAContainer.Encounters.Insert(encounterSDA1)

#<span class="hljs-comment">; convert the SDA object into an XML string.</span>
<span class="hljs-keyword">do</span> SDAContainer.XMLExportToString(.containerString)
<span class="hljs-keyword">write</span> containerString

}


SDA – XML 文档输出

<Container><Patient><Name><FamilyName>stood</FamilyName><GivenName>test</GivenName></Name><Gender><Code>male</Code><Description>birth gender</Description></Gender></Patient><Encounters><Encounter><AccountNumber>12109979</AccountNumber><AdmitReason><Code>Health Concern</Code><Description>general health concern</Description></AdmitReason><ActionCode>E</ActionCode></Encounter><Encounter><AccountNumber>95856584</AccountNumber><AdmitReason><Code>reegular checkup</Code><Description>general health ckeckup</Description></AdmitReason><ActionCode>D</ActionCode></Encounter></Encounters><UpdateECRDemographics>true</UpdateECRDemographics></Container>

 在上一节中,我们探讨了 SDA 及其组成部分。 我们还学习了如何通过 Cache ObjectScript 生成 SDA。

接下来,我们将使用互操作性生产(之前称为 Ensemble)生成 FHIR 资源或捆绑包。

在创建 FHIR 资源之前,我们来简单了解一下互操作性生产。

带 FHIR 适配器的互操作性生产

互操作性生产是一个集成框架,用于连接系统和开发应用程序,以轻松实现互操作性。 它通常分为 3 大组成部分:

  1. 业务服务 – 连接到外部系统,并接收外部系统发出的请求。
  2. 业务流程 – 接收其他业务主机发出的请求、根据您定义的业务逻辑处理请求,并转换相关数据。 会使用多个组件进行数据转换:
    1. BPL – 业务流程语言
    2. DTL – 数据转换语言
    3. BR – 业务规则
    4. 记录映射
  3. 业务操作 – 与外部系统相连,并向外部系统发送响应。

首先,我们来构建 FHIR 消息。

创建 FHIR 资源

存在两种类型的系统:FHIR 服务器和非 FHIR 服务器。 在我们的案例中,我们的目标是使用 FHIR Interoperability Adapter 生成 FHIR 资源,将非 FHIR 的InterSystems IRIS 数据库表示为符合 FHIR 标准的系统。

在本节中,我们将演示如何借助带 FHIR 适配器的 InterSystems IRIS for Health 互操作性工具包,通过存储在 IRIS 数据库中的自定义数据生成 FHIR 资源。

在此实现过程中,我们将创建以下类型的 FHIR 资源:

  1. 标准 FHIR 资源 – 使用内置的 FHIR 类,进行少量修改或不做修改。
  2. 自定义 FHIR 资源 – 涉及向 SDA 模型添加扩展,以及为 FHIR 资源创建自定义数据转换 (DTL)。

每个实现都将通过专用的业务主机启动。

业务服务

RESTful 业务主机负责接收外部系统发出的请求。 您可以根据特定集成要求(例如,HTTP、SOAP 或其他受支持的协议)配置合适的适配器。

接收到外部系统发送的请求后,工作流将立即使用自定义或旧版数据库中持久存储的数据生成相应的 FHIR 资源。

FHIR 业务流程

FHIR 消息生成流程主要包括两个步骤:

  1. 将自定义/专有数据转换为 SDA(将 HL7 版本 2.X 转换为 SDA,将 CCDA 转换为 SDA,等等)。
  2. 将数据元素添加到 SDA,如有需要,创建自定义 DTL。 以下步骤为可选步骤,是否执行取决于具体实现需求,例如自定义 FHIR 资源生成。
  3. 然后,借助 IRIS 内置流程将生成的 SDA 转换为 FHIR 资源。

结构化数据架构 (SDA) 格式充当中介,可以实现灵活的数据转换。 数据以 SDA 格式提供后,即可轻松映射到 FHIR 或其他医疗保健数据标准。

将自定义/专有数据转换为 SDA 格式
使用这种方式时,先创建持久或互操作性请求类,以便转换为 SDA 格式。 此过程涉及定义自定义患者类,用于将您的旧版或自定义数据库结构中的数据映射为符合 SDA 标准的对象。

利用自定义患者类可以提供极高的灵活性:

  • 简化对象处理和操作流程。
  • 以数据转换语言 (DTL) 实现清晰映射。
  • 轻松重用其他转换或业务逻辑层中的对象。

请求外部层的类以转换 SDA:

Class Samples.FHIRAdapt.CustomStorage.Patient Extends (Ens.Request,%JSON.Adaptor)
{
Property Name As%String;Property BirthDate As%String;Property Citizenship As%String;Property Religion As%String;Property PrimaryLanguage As%String;Property Married As%String;Property MRN As%String;
}

 

此请求类作为外部接口层,启动从您的数据库格式转换为 SDA 的流程。 SDA 对象创建完毕后,可以通过标准或自定义 DTL 映射无缝转换为所需 FHIR 资源:

  1. 添加 Samples.FHIRAdapt.CustomStorage.Patient(使用您的类定义)类作为转换的源类。
  2. 确定并选择适合映射的 SDA 目标类。 在本例中,HS.SDA3.Patient 是适合将自定义数据转换为 SDA 格式的类。

DTL 转换示例

Class Samples.FHIRAdapt.DTL.CustomDataToPatientSDA Extends Ens.DataTransformDTL [ DependsOn = (Samples.FHIRAdapt.CustomStorage.Patient, HS.SDA3.Patient) ]
{

Parameter IGNOREMISSINGSOURCE = 1;Parameter REPORTERRORS = 1;Parameter TREATEMPTYREPEATINGFIELDASNULL = 0; XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ] { <transform sourceClass='Samples.FHIRAdapt.CustomStorage.Patient' targetClass='HS.SDA3.Patient' create='new' language='objectscript' > <assign value='$Piece(source.Name,",")' property='target.Name.GivenName' action='set' /> <assign value='$Piece(source.Name,",")' property='target.Name.FamilyName' action='set' /> <assign value='$Piece($Piece(source.Name,",",2)," ",2)' property='target.Name.MiddleName' action='set' /> <assign value='source.Citizenship' property='target.Citizenship' action='set' /> <assign value='"fullname"' property='target.Name.Type' action='set' /> <assign value='$Select(source.Married=1:"married",1:"single")' property='target.MaritalStatus.Code' action='set' /> </transform> }

}

在这一阶段,数据已成功转换为 SDA 文档,并准备好转换为 FHIR 资源。

在生成 FHIR 资源之前,应创建额外的支持 FHIR 资源作为此响应的组成部分。 此外,还需要在 FHIR 输出中包含自定义字段。 要支持这些自定义元素,必须将相应的属性纳入 SDA 结构。

此操作可以借助 SDA 扩展完成,SDA 扩展可以将准确、完整地生成 FHIR 资源所需的自定义数据元素包含在 SDA 结构中。

SDA 扩展

FHIR 遵循 80/20 法则,即核心 FHIR 规范负责处理约 80% 的常见医疗保健用例,而剩余的 20% 则通过自定义约束和扩展来解决。

为说明这一点,我们将使用自定义扩展创建一个 AllergyIntolerance 资源。

在 InterSystems IRIS 中正确实现扩展数据元素需要执行两个关键步骤:

  1. HS.SDA3.*******Extension 用于将额外的数据元素添加到各个 SDA 部分。 例如,类 HS.Local.SDA3.AllergyExtension 通过定义所需自定义属性对 HS.SDA3.Allergy 进行扩展。
  2. 由于预构建的 DTL 映射不包含这些自定义扩展,必须创建自定义 DTL 来相应地转换处理。

Allergy 扩展类

要在用于创建所需过敏症资源的 HS.Local.SDA3.AllergyExtension 类中构建所需字段,请使用以下代码行:

Class HS.Local.SDA3.AllergyExtension Extends HS.SDA3.DataType
{

Parameter STREAMLETCLASS = "HS.SDA3.Streamlet.Allergy";/// Mapped this property due to not being available in the SDA to FHIR conversionProperty Criticality As%String;/// Mapped this property due to not being available in the SDA to FHIR conversionProperty Type As%String(MAXLEN = ""); Storage Default { <Data name="AllergyExtensionState"> <Subscript>"AllergyExtension"</Subscript> <Value name="1"> <Value>Criticality</Value> </Value> <Value name="2"> <Value>Type</Value> </Value> </Data> <State>AllergyExtensionState</State> <Type>%Storage.Serial</Type> }

}

创建扩展只是完成了整个流程的一半,因为标准 DTL 未提供扩展字段的映射。 现在,我们需要构建自定义 DTL,以正确转换 FHIR 响应。


自定义 DTL 创建

在自定义 DTL 类之前,您需要为所有自定义 DTL 实现定义专用软件包。 为此,InterSystems 建议使用名为 HS.Local.FHIR.DTL 的软件包。

要为 Allergy 构建自定义 DTL,请先从现有的数据转换类
HS.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance 开始,该类用于处理从 SDA 到 FHIR 资源的转换。

首先,将此类复制到自定义包中,将其命名为

HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance. 然后,将自定义扩展映射到 FHIR 资源生成流程中,以对其进行扩展。

例如,示例类 HS.Local.FHIR.DTL.FromSDA.Allergy 说明了如何便捷地映射 Allergy 扩展字段,同时从基类 HS.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance 继承所有其他映射。

示例自定义 DTL 映射如下图所示:

/// Transforms SDA3 HS.SDA3.Allergy to vR4 AllergyIntoleranceClass HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance Extends Ens.DataTransformDTL [ DependsOn = (HS.SDA3.Allergy, HS.FHIR.DTL.vR4.Model.Resource.AllergyIntolerance), ProcedureBlock ]
{

XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ] { <transform sourceClass='HS.SDA3.Allergy' targetClass='HS.FHIR.DTL.vR4.Model.Resource.AllergyIntolerance' create='existing' language='objectscript' > <assign value='source.Extension.Criticality' property='target.criticality' action='set' /> <assign value='source.Extension.Type' property='target.type' action='set' > <annotation>11/07/2023; ak; Added this set to populate type in AllergyIntolerance resource</annotation> </assign> </transform> }

}

为自定义 DTL 创建类软件包后(在自定义 DTL 软件包不存在的情况下),必须进行注册,以获得今后的 FHIR 数据转换结果。

set status = ##class(HS.FHIR.DTL.Util.API.ExecDefinition).SetCustomDTLPackage("HS.Local.FHIR.DTL")

 此外,您还可以通过调用类方法获取自定义 DTL 软件包详细信息(如果已定义)。

Write ##class(HS.FHIR.DTL.Util.API.ExecDefinition).GetCustomDTLPackage()


请求消息的流容器类

SDA 及其可选 SDA 扩展的设置,以及构建 SDA 的可选自定义 DTL 创建过程现已完成。 不过,现在必须将 SDA 对象转换为标准化的 Ens.StreamContainer,该容器专门用于 SDA 到 FHIR 的转换业务流程。

下面的简单步骤可以将 SDA 对象转换为 Ens.StreamContainer。

ClassMethod CreateEnsStreamContainer()
{
	set ensStreamCntr=""try {
        #; refer the CreateSDAContainer() method above#dim SDAContainer As HS.SDA3.Container = ..CreateSDAContainer()
		do SDAContainer.XMLExportToStream(.stream)
		#; Create Ens.StreamContainer is the default format for processing the SDA to FHIR processSet ensStreamCntr = ##class(Ens.StreamContainer).%New(stream)
	}
	catch ex {
		Write ex.DisplayString()
		set ensStreamCntr=""
	}
	return ensStreamCntr
}

 创建 SDA 的第一阶段已完成。 第二阶段(即生成 FHIR 资源)已由 InterSystems IRIS 处理。

下文介绍如何将 SDA 文档转换为 FHIR 资源。


SDA 转换为 FHIR

针对 FHIR 创建配置互操作性业务主机

生成 FHIR 的业务逻辑已完成。 现在,我们来配置互操作性生产设置:

  1. 设置入站服务,以接收外部系统发出的请求。
  2. 业务流程 – 这是创建 FHIR 资源的关键步骤。

业务流程实现

此业务流程侧重于 SDA 到 FHIR 的转换。 InterSystems IRIS 包含一套全面的内置业务流程,即 S.FHIR.DTL.Util.HC.SDA3.FHIR.Process,该流程可以促进 SDA 与 FHIR 消息的转换。 通过将生成的 SDA 文档发送到此业务流程,您可以接收以 JSON 响应形式发送的 FHIR 资源。

此流程支持两种类型的 FHIR 响应,具体取决于 SDA 输入。

  1. 捆绑包 – 如果整个 SDA 容器对象以 Ens.StreamConainter 形式发送,该流程会返回包含所有资源的 FHIR 捆绑包。
  2. 资源 – 如果个别 SDA 部分(例如,患者、诊疗、过敏症)以 Ens.StreamConainter 的形式发送,它会以捆绑包的形式发送对应的单个 FHIR 资源。

业务操作

FHIR 捆绑包现已准备就绪,可被返回给请求方或发送到外部系统。

生产设置:


业务服务类

该业务服务类负责处理外部系统发出的请求,以生成 FHIR。

  1. 一旦接收到请求,它就会使用现有逻辑创建 SDA。
  2. 该 SDA 随后会被转换为流对象。
  3. 此流会被转换为标准业务流程预期使用的格式。
  4. 最后,处理好的输入会被发送到业务流程。
Class Samples.Interop.BS.GenerateFHIRService Extends Ens.BusinessService
{

Parameter ADAPTER = "Ens.InboundAdapter";Property TargetConfigName As Ens.DataType.ConfigName [ InitialExpression = "HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process" ]; Method OnProcessInput(pInput As%RegisteredObject, Output pOutput As%RegisteredObject) As%Status { #; create your SDA container object and export to streamdo..CreateSDAContainer().XMLExportToStream(.sdaStream)

#<span class="hljs-comment">; convert to the standard Ens.StreamContainer message format</span>
<span class="hljs-keyword">set</span> ensStreamCtnr = <span class="hljs-keyword">##class</span>(Ens.StreamContainer).<span class="hljs-built_in">%New</span>(sdaStream)

#<span class="hljs-comment">; send to the Business process</span>
<span class="hljs-keyword">do</span> <span class="hljs-built_in">..SendRequestSync</span>(<span class="hljs-built_in">..TargetConfigName</span>,ensStreamCtnr,.pOutput)
<span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>

}

ClassMethod CreateSDAContainer() As HS.SDA3.Container {

<span class="hljs-keyword">set</span> SDAContainer = <span class="hljs-keyword">##class</span>(HS.SDA3.Container).<span class="hljs-built_in">%New</span>()

#<span class="hljs-comment">; create patient object</span>
<span class="hljs-keyword">set</span> patientSDA = <span class="hljs-keyword">##class</span>(HS.SDA3.Patient).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> patientSDA.Name.FamilyName = <span class="hljs-string">"stood"</span>
<span class="hljs-keyword">set</span> patientSDA.Name.GivenName = <span class="hljs-string">"test"</span>
<span class="hljs-keyword">set</span> patientSDA.Gender.Code=<span class="hljs-string">"male"</span>
<span class="hljs-keyword">set</span> patientSDA.Gender.Description=<span class="hljs-string">"birth gender"</span>
#<span class="hljs-comment">; create Encounter 1</span>
<span class="hljs-keyword">set</span> encounterSDA  = <span class="hljs-keyword">##class</span>(HS.SDA3.Encounter).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> encounterSDA.AccountNumber = <span class="hljs-number">12109979</span>
<span class="hljs-keyword">set</span> encounterSDA.ActionCode =<span class="hljs-string">"E"</span>
<span class="hljs-keyword">set</span> encounterSDA.AdmitReason.Code =<span class="hljs-string">"Health Concern"</span>
<span class="hljs-keyword">set</span> encounterSDA.AdmitReason.Description = <span class="hljs-string">"general health concern"</span>
#<span class="hljs-comment">; set the patientSDA into the container.</span>
<span class="hljs-keyword">set</span> SDAContainer.Patient = patientSDA

#<span class="hljs-comment">; set encounters into the container SDA</span>
<span class="hljs-keyword">do</span> SDAContainer.Encounters.Insert(encounterSDA)
<span class="hljs-keyword">return</span> SDAContainer

} }


使用 ObjectScript 创建 SDA 到 FHIR 的转换

在上一个示例中,FHIR 资源是借助互操作性框架通过 SDA 生成的。 在本节中,我们将直接使用 ObjectScript 构建 FHIR 捆绑包。


通过 SDA 容器创建 FHIR 捆绑包

CreateSDAContainer 方法会返回 HS.SDA3.Container 类型的对象(我们在上文中提到过)。 在将此 SDA 容器传递给 TransformStream 方法之前,必须先将其转换为流。 TransformStream 方法随后会处理该流,并在 tTransformObj.bundle 中以 %DynamicObject 形式返回 FHIR 捆绑包。

ClassMethod CreateBundle(fhirVersion As%String = "R4") As%DynamicObject
{
	try {	
		Set SDAContainer = ..CreateSDAContainer()
		Do SDAContainer.XMLExportToStream(.stream)
		#; Should pass stream, not a container objectSet tTransformObj = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformStream( stream, "HS.SDA3.Container", fhirVersion)
		return tTransformObj.bundle
	}
	catch ex {
		write ex.DisplayString()
	}
	return""
}


使用 SDA 部分创建 FHIR 捆绑包

使用此方式时,会直接在 ObjectScript 中声明 patientSDA。 此 SDA 对象随后会被传递到 TransformObject 方法,这个方法负责处理此 SDA 对象,并以 %DynamicObject 形式返回 FHIR 捆绑包。

ClassMethod CreatePatientResourceDirectSet()
{
	try {
		#; convert you're custom dataset into SDA by your DTLset patientSDA = ##class(HS.SDA3.Patient).%New()
		set patientSDA.Name.FamilyName = "stood"set patientSDA.Name.GivenName = "test"set patientSDA.Gender.Code="male"set patientSDA.Gender.Description="birth gender"#dim tTransformObj As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformObject(patientSDA,"R4")
		set patinetBundle = tTransformObj.bundle
	}
	catch ex {
		write ex.DisplayString()
	}
	return patinetBundle
}

使用自定义 FHIR DTL 和 Allergy 扩展创建过敏症资源

  1. 直接在 SDA 对象中填充所有必需字段,包括自定义扩展字段。
  2. 您应当在 TransformObject 方法中将 FHIR 版本类型作为第二个参数提及(“R4”代表 Resource4 FHIR 消息)。
  3. 将完成的 SDA 对象传递给 FHIR 转换类,以生成 AllergyIntolerance FHIR 捆绑包。

注:过敏症资源的自定义扩展已定义,自定义 DTL 映射已注册。

ClassMethod CreateAllergyWithDTL()
{
	#; I already registered the "HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance" for extension mapping
	#; fetch the data from the table/global and set it into AllergySDA directly.	set allerySDA = ##class(HS.SDA3.Allergy).%New()
	set allerySDA.Extension.Criticality = "critial"set allerySDA.Extension.Type = "t1"set allerySDA.Comments = "testing allergies"set allerySDA.AllergyCategory.Code="food"set allerySDA.AllergyCategory.Description="sea food"
	#; Set the required and additional properties in SDA, depending on your requirements.
	#; create a FHIR resource from the allergySDA with extension fields that uses a custom "HS.Local.FHIR.*" DTL#dim tTransformObj As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformObject(allerySDA,"R4")
	Set patinetBundle = tTransformObj.bundle
}

FHIR 转换为 SDA

自定义数据、HL7 v2.x 或 CCDA 消息之前已被转换为 FHIR。 接下来的实现涉及将 FHIR 捆绑包或资源转换为 SDA 格式,随后可以存储在数据库中或转换为 CCDA 或 HL7 v2.x 格式。

JSON 或 XML 格式的 FHIR 资源接收自外部系统。 收到后,必须将资源转换为内部数据结构并存储在 IRIS 数据库中。

业务服务

可以根据要求通过 HTTP/REST 或其他任何入站适配器接收请求。


业务流程 – FHIR 转换为 SDA

InterSystems IRIS 接收到 FHIR 请求消息后,会提供全面的内置业务流程 (HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process)。 此业务流程会将 FHIR 资源或捆绑包作为输入。 FHIR 输入只能是配置的 FHIR 版本。 此业务流程会将 FHIR 数据转换为 SDA3、将 SDA3 流转发给指定的业务主机、接收业务主机发送的响应,并返回 FHIR 响应。

请注意,您无法将收到的请求直接发送至业务流程。

请求输入应为以下类型:

  1. HS.FHIRServer.Interop.Request – 用于互操作性生产。
  2. HS.Message.FHIR.Request – FHIR 仓库服务器。

这意味着在发送请求之前,必须将请求转换为上述格式之一。

Creating Interop.Request

ClassMethod CreateReqObjForFHIRToSDA(pFHIRResource As%DynamicObject) As HS.FHIRServer.Interop.Request
{
             #; sample message set pFHIRResource = {"resourceType":"Patient","name":[{"use":"official","family":"ashok te","given":["Sidharth"]}],"gender":"male","birthDate":"1997-09-08","telecom":[{"system":"phone","value":"1234566890","use":"mobile"},{"system":"email","value":"tornado1212@gmail.com"}],"address":[{"line":["Some street"],"city":"Manipal1","state":"Karnataka1","postalCode":"1234561"}]}
<span class="hljs-keyword">set</span> stream = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Stream.GlobalCharacter</span>).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">do</span> stream.<span class="hljs-keyword">Write</span>(pFHIRResource.<span class="hljs-built_in">%ToJSON</span>())
#<span class="hljs-comment">; create Quick stream </span>
<span class="hljs-keyword">set</span> inputQuickStream = <span class="hljs-keyword">##class</span>(HS.SDA3.QuickStream).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> inputQuickStreamId = inputQuickStream.<span class="hljs-built_in">%Id</span>()
<span class="hljs-built_in">$$$ThrowOnError</span>( inputQuickStream.CopyFrom(stream) ) 
	
<span class="hljs-keyword">#dim</span> ensRequest <span class="hljs-keyword">as</span> HS.FHIRServer.Interop.Request = <span class="hljs-keyword">##class</span>(HS.FHIRServer.Interop.Request).<span class="hljs-built_in">%New</span>()

<span class="hljs-keyword">set</span> ensRequest.QuickStreamId = inputQuickStreamId

<span class="hljs-keyword">return</span> ensRequest

在 HS.FHIRServer.Interop.Request 消息创建完毕后,立即将其发送至业务流程,以将 FHIR 资源转换为 SDA 捆绑包。

生产设置:


业务服务类

该类通过 HTTP 请求接收 FHIR 资源流,将此流输入转换为标准流程预期使用的格式,即 HS.FHIRServer.Interop.Request,最后调用 FHIR 适配器流程类以生成 SDA。

Class Samples.Interop.BS.FHIRReceiver Extends Ens.BusinessService
{

Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter";Property TargetConfigName As Ens.DataType.ConfigName [ InitialExpression = "HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process" ]; Method OnProcessInput(pInput As%Stream.Object, Output pOutput As%Stream.Object) As%Status { set inputQuickStream = ##class(HS.SDA3.QuickStream).%New() set inputQuickStreamId = inputQuickStream.%Id() $$$ThrowOnError( inputQuickStream.CopyFrom(pInput) )

<span class="hljs-keyword">#dim</span> ensRequest <span class="hljs-keyword">as</span> HS.FHIRServer.Interop.Request = <span class="hljs-keyword">##class</span>(HS.FHIRServer.Interop.Request).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">set</span> ensRequest.QuickStreamId = inputQuickStreamId

<span class="hljs-keyword">Do</span> <span class="hljs-built_in">..SendRequestSync</span>(<span class="hljs-built_in">..TargetConfigName</span>, ensRequest, .pOutput)

<span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>

}

}


使用 ObjectScript 通过 FHIR 资源创建 SDA

在上一个示例中,SDA 文档是借助互操作性框架通过 FHIR 生成的。 在本节中,我们将直接使用 ObjectScript 实现从 FHIR 到 SDA 的转换。

在您收到以请求形式发送到 IRIS 中的 FHIR 资源/捆绑包后,立即将 FHIR JSON 转换为 SDA 容器:

  1. 将 InterSystems %DynamicObject AKA JSON 转换为 %Stream 对象。
  2. 通过 HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 类执行 TransformStream 方法,这会以响应形式返回 SDA 容器对象。
///Simple, straightforward FHIR JSON resource to SDA conversionClassMethod CreateSDAFromFHIRJSON()
{
	try {
		; have to send as a stream, not a %DynamicObjectset patientStream = ##Class(%Stream.GlobalCharacter).%New()
		do patientStream.Write({"resourceType":"Patient","name":[{"use":"official","family":"ashok te","given":["Sidharth"]}],"gender":"male","birthDate":"1997-09-08","telecom":[{"system":"phone","value":"1234566890","use":"mobile"},{"system":"email","value":"tornado1212@gmail.com"}],"address":[{"line":["Some street"],"city":"Manipal1","state":"Karnataka1","postalCode":"1234561"}]}.%ToJSON())
		#dim SDAObj As HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 = ##class(HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3).TransformStream(patientStream,"R4","JSON")
		set SDAContainer = SDAObj.container
	<span class="hljs-comment">; XML-based SDA output</span>
	<span class="hljs-keyword">write</span> SDAContainer.XMLExport()
}
<span class="hljs-keyword">catch</span> ex {
	<span class="hljs-keyword">write</span> ex.DisplayString()
}

}


FHIR XML 转换为 SDA 容器。

  1. 将 XML 转换为 %Stream 对象。
  2. 通过 HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 类执行 TransformStream 方法,这会以响应形式返回 SDA 容器对象。
/// Simple, straightforward FHIR XML resource to SDA conversionClassMethod CreateSDAFromFHIRXML()
{
	try {
		set patientXML = "<Patient xmlns=""http://hl7.org/fhir""><id value=""example""/><text><status value=""generated""/><div xmlns=""http://www.w3.org/1999/xhtml""><p>John Doe</p></div></text><identifier><use value=""usual""/><type><coding><system value=""http://terminology.hl7.org/CodeSystem/v2-0203""/><code value=""MR""/></coding></type><system value=""http://hospital.smarthealth.org""/><value value=""123456""/></identifier><name><use value=""official""/><family value=""Doe""/><given value=""John""/></name><gender value=""male""/><birthDate value=""1980-01-01""/></Patient>"set patientStream = ##Class(%Stream.GlobalCharacter).%New()
		do patientStream.Write(patientXML)
		#dim SDAObj As HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 = ##class(HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3).TransformStream(patientStream,"R4","XML")
		set SDAContainer = SDAObj.container
	<span class="hljs-comment">; XML-based SDA output</span>
	<span class="hljs-keyword">write</span> SDAContainer.XMLExport()
}
<span class="hljs-keyword">catch</span> ex {
	<span class="hljs-keyword">write</span> ex.DisplayString()
}

}

按照上文详细介绍的步骤,您可以在数据与 FHIR 资源之间进行无缝转换。

其他内置的 FHIR 仓库和 FHIR 装饰选项是公开符合 FHIR 标准的系统、高效处理和存储 FHIR 资源的重要工具。

0
0 16
文章 Kelly Huang · 十月 23, 2025 15m read

img

在本节中,我们将探讨如何在 IRIS 中使用 Python 作为主要编程语言,在使用 Python 编写应用程序逻辑的同时仍能利用 IRIS 的强大功能。

使用方法 (irispython)

我们先来介绍官方操作方式,即使用 irispython 解释器。

您可以使用 irispython 解释器直接在 IRIS 中运行 Python 代码。 这样,您可以编写 Python 代码,并在 IRIS 应用程序的运行环境中执行相应代码。

什么是 irispython?

irispython 是位于 IRIS 安装目录 (<installation_directory>/bin/irispython) 下的 Python 解释器,用于在 IRIS 的运行环境中执行 Python 代码。

它的功能包括:

  • 设置 sys.path,以包含 IRIS Python 库和模块。
    • 此操作通过 <installation_directory>/lib/python/iris_site.py 中的 site.py 文件执行。
    • 如需了解详情,请参阅模块文章 Python 模块简介
  • 允许您导入 iris 模块,这是一个特殊模块,用于访问 IRIS 功能,例如实现任何 ObjectScript 类与 Python 的双向桥接。
  • 修复权限问题并动态加载 iris 内核库。

irispython 使用示例

您可以通过命令行运行 irispython 解释器:

<installation_directory>/bin/irispython

我们来运行一个简单的示例:

# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # print message: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

您可以使用 irispython解释器运行此脚本:

<installation_directory>/bin/irispython src/python/article/irispython_example.py

您将看到如下输出:

Iris version: IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2025.1 (Build 223U) Tue Mar 11 2025 18:23:31 EDT
message: Hello World

此例展示了如何使用 irispython 解释器在 IRIS 的运行环境中执行 Python 代码。

优点

  • Python 优先:您可以使用 Python 编写应用程序逻辑,这样,您可以利用 Python 的功能和库。
  • IRIS 集成:您可以轻松将 Python 代码与 IRIS 功能相集成。

缺点

  • 调试受限:在 irispython 中调试 Python 代码并不像在专用 Python 环境中那样简单直接。
    • 这并不是说无法进行调试,而是并不像在专用 Python 环境中那样简单。
    • 如需了解详情,请参阅补充部分
  • 虚拟环境:在 irispython 中为 Python 代码搭建虚拟环境比较困难。
    • 这并不是说无法搭建,只是操作起来比较困难。因为默认情况下,虚拟环境会查找名为 pythonpython3 的解释器,而 IRIS 中的情况并非如此。
    • 如需了解详情,请参阅补充部分

结论

总的来说,使用 irispython 解释器让您既可以利用 Python 编写应用程序逻辑,又能利用 IRIS 的强大功能。 不过,这种方式也存在调试和虚拟环境搭建方面的限制。

使用 WSGI

在本节中,我们将探讨如何使用 WSGI(Web 服务器网关接口)在 IRIS 中运行 Python Web 应用程序。

WSGI 是 Web 服务器与 Python Web 应用程序或框架之间的标准接口。 利用 WSGI,您可以在 Web 服务器环境中运行 Python Web 应用程序。

IRIS 支持 WSGI,这意味着您可以在 IRIS 中使用内置的 WSGI 服务器运行 Python Web 应用程序。

使用方法

要在 IRIS 中使用 WSGI,您需要创建 WSGI 应用程序,并向 IRIS Web 服务器注册此应用程序。

如需了解详情,请参阅官方文档

WSGI 使用示例

有关完整模板,请参见此处:iris-flask-example

优点

  • Python Web 框架:您可以使用流行的 Python Web 框架(如 Flask 或 Django)来构建 Web 应用程序。
  • IRIS 集成:您可以轻松将 Python Web 应用程序与 IRIS 功能相集成。

缺点

  • 复杂程度:构建 WSGI 应用程序会比直接在 Python Web 框架中使用 uvicorngunicorn 复杂一些。

结论

总的来说,在 IRIS 中使用 WSGI 让您既可以利用 Python 构建功能强大的 Web 应用程序,又能利用 IRIS 的功能。

DB-API

在本节中,我们将探讨如何使用 Python DB-API 与 IRIS 数据库进行交互。

Python DB-API 是 Python 中用于连接数据库的标准接口。 利用此接口,您可以执行 SQL 查询,并从数据库中检索结果。

使用方法

您可以使用 pip 进行安装:

pip install intersystems-irispython

随后,您可以使用 DB-API 连接 IRIS 数据库并执行 SQL 查询。

DB-API 使用示例

它的使用方法与其他所有 Python DB-API 相同,示例如下:

# src/python/article/dbapi_example.py
import iris

def run():
    # Connect to the IRIS database
# Open a connection to the server
    args = {
        'hostname':'127.0.0.1', 
        'port': 1972,
        'namespace':'USER', 
        'username':'SuperUser', 
        'password':'SYS'
    }
    conn = iris.connect(**args)

    # Create a cursor
    cursor = conn.cursor()

    # Execute a query
    cursor.execute("SELECT 1")

    # Fetch all results
    results = cursor.fetchall()

    for row in results:
        print(row)

    # Close the cursor and connection
    cursor.close()
    conn.close()
if __name__ == "__main__":
    run()

您可以使用任何 Python 解释器运行此脚本:

python3 /irisdev/app/src/python/article/dbapi_example.py

您将看到如下输出:

(1,)

优点

  • 标准接口:DB-API 提供用于连接数据库的标准接口,因此可以轻松切换不同的数据库。
  • SQL 查询:您可以使用 Python 执行 SQL 查询,并从数据库检索结果。
  • 远程访问:您可以使用 DB-API 连接到远程 IRIS 数据库。

缺点

  • 功能有限:DB-API 仅可通过 SQL 访问数据库,因此,您无法使用高级 IRIS 数据库功能,如执行 ObjectScript 或 Python 代码。

备选方案

还提供社区版 DB-API,参见此处:intersystems-irispython-community

该版本能更好地支持 SQLAlchemy、Django、langchain,以及其他使用 DB-API 的 Python 库。

如需了解详情,请参阅 补充部分

结论

总的来说,将 Python DB-API 与 IRIS 结合使用能够让您构建功能强大的应用程序,实现与数据库的无缝交互。

Notebook

现在,我们已了解如何在 IRIS 中使用 Python,接下来我们将探讨如何将 Jupyter Notebooks 与 IRIS 结合使用。

Jupyter Notebooks 是交互式编写和执行 Python 代码的绝佳方式,并且可与 IRIS 结合使用,以充分利用 IRIS 的功能。

使用方法

要在 IRIS 中使用 Jupyter Notebooks,您需要安装 notebookipykernel 这两个软件包:

pip install notebook ipykernel

然后,您可以创建新的 Jupyter Notebook 并选择 Python 3 内核。

Notebook 使用示例

您可以创建新的 Jupyter Notebook 并编写以下代码:

# src/python/article/my_notebook.ipynb
# Import the necessary modules
import iris
# Do the magic
iris.system.Version.GetVersion()

您可以使用 Jupyter Notebook 运行此 notebook:

jupyter notebook src/python/article/my_notebook.ipynb

优点

  • 交互式开发:利用 Jupyter Notebooks,您可以交互式编写和执行 Python 代码,非常适合数据分析和探索。
  • 丰富的输出:您可以直接在 Notebook 中显示丰富的输出,如图表和表格。
  • 文档:您可以在代码旁添加文档和说明。

缺点

  • 设置有难度:设置将 Jupyter Notebooks 与 IRIS 结合使用存在一定的难度,特别是对于内核配置而言。

结论

总的来说,将 Jupyter Notebooks 与 IRIS 结合使用可以交互式编写和执行 Python 代码,同时利用 IRIS 的功能。 不过,设置起来存在一定的难度,特别是对于内核配置而言。

补充部分

从本节开始,我们将探讨一些与在 IRIS 中使用 Python 相关的高级主题,例如远程调试 Python 代码、使用虚拟环境等。

以下大部分主题均未获得 InterSystems 的官方支持,但如果您要在 IRIS 中使用 Python,了解相关内容会提供很大的帮助。

使用原生解释器(无 irispython

在本节中,我们将探讨如何使用原生 Python 解释器代替 irispython 解释器。

这样一来,您可以直接使用虚拟环境,并使用您习惯的 Python 解释器。

使用方法

要使用原生 Python 解释器,您需要在机器本地安装 IRIS,并需要安装 iris-embedded-python-wrapper 软件包。

您可以使用 pip 进行安装:

pip install iris-embedded-python-wrapper

接下来,您需要设置一些环境变量指向 IRIS 安装目录:

export IRISINSTALLDIR=<installation_directory>
export IRISUSERNAME=<username>
export IRISPASSWORD=<password>
export IRISNAMESPACE=<namespace>

然后,您可以使用您的原生 Python 解释器运行 Python 代码:

python3 src/python/article/irispython_example.py
# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # print message: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

如需了解详情,请参阅 iris-embedded-python-wrapper 文档

优点

  • 虚拟环境:您可以将虚拟环境与原生 Python 解释器结合使用,从而可以更加轻松地管理依赖项。
  • 熟悉的工作流:您可以使用习惯的 Python 解释器,从而可以更轻松地与现有工作流相集成。
  • 调试:可以使用您喜欢的 Python 调试工具(如 pdbipdb)在 IRIS 中调试 Python 代码。

缺点

  • 设置的复杂程度:设置环境变量和 iris-embedded-python-wrapper 软件包可能会比较复杂,特别是对于初学者来说。
  • 未获官方支持:此方式未获 InterSystems 的官方支持,因此您可能遇到文档中未记录或不受支持的问题。

DB-API 社区版

在本节中,我们将探讨 GitHub 上提供的社区版 DB-API。

使用方法

您可以使用 pip 进行安装:

pip install sqlalchemy-iris

此代码将安装社区版 DB-API。

或使用特定版本:

pip install https://github.com/intersystems-community/intersystems-irispython/releases/download/3.9.3/intersystems_iris-3.9.3-py3-none-any.whl

然后,您可以使用 DB-API 连接 IRIS 数据库,并执行 SQL 查询或其他任何使用 DB-API 的 Python 代码,如 SQLAlchemy、Django、langchain、pandas 等。

DB-API 使用示例

它的使用方法与其他所有 Python DB-API 相同,示例如下:

# src/python/article/dbapi_community_example.py
import intersystems_iris.dbapi._DBAPI as dbapi

config = {
    "hostname": "localhost",
    "port": 1972,
    "namespace": "USER",
    "username": "_SYSTEM",
    "password": "SYS",
}

with dbapi.connect(**config) as conn:
    with conn.cursor() as cursor:
        cursor.execute("select ? as one, 2 as two", 1)   # second arg is parameter value
        for row in cursor:
            one, two = row
            print(f"one: {one}")
            print(f"two: {two}")

您可以使用任何 Python 解释器运行此脚本:

python3 /irisdev/app/src/python/article/dbapi_community_example.py

也可以使用 sqlalchemy:

from sqlalchemy import create_engine, text

COMMUNITY_DRIVER_URL = "iris://_SYSTEM:SYS@localhost:1972/USER"
OFFICIAL_DRIVER_URL = "iris+intersystems://_SYSTEM:SYS@localhost:1972/USER"
EMBEDDED_PYTHON_DRIVER_URL = "iris+emb:///USER"

def run(driver):
    # Create an engine using the official driver
    engine = create_engine(driver)

    with engine.connect() as connection:
        # Execute a query
        result = connection.execute(text("SELECT 1 AS one, 2 AS two"))

        for row in result:
            print(f"one: {row.one}, two: {row.two}")

if __name__ == "__main__":
    run(OFFICIAL_DRIVER_URL)
    run(COMMUNITY_DRIVER_URL)
    run(EMBEDDED_PYTHON_DRIVER_URL)

您可以使用任何 Python 解释器运行此脚本:

python3 /irisdev/app/src/python/article/dbapi_sqlalchemy_example.py

您将看到如下输出:

one: 1, two: 2
one: 1, two: 2
one: 1, two: 2

优点

  • 更好的支持:对 SQLAlchemy、Django、langchain 以及其他使用 DB-API 的 Python 库提供更好的支持。
  • 依托于社区:它由社区维护,这意味着随着时间的推移,可能会对其进行更新和改进。
  • 兼容性:它兼容官方 InterSystems DB-API,因此您可以在官方版与社区版之间轻松切换。

缺点

  • 速度:社区版的优化程度可能不如正式版高,某些场景下可能会导致速度变慢。

在 IRIS 中调试 Python 代码

在本节中,我们将探讨如何在 IRIS 中调试 Python 代码。

默认情况下,无法在 IRIS 中调试 Python 代码(在包含语言标签或 %SYS.Python 的 objectscript 中),但可以通过社区解决方案在 IRIS 中调试 Python 代码。

使用方法

先安装 IoP 基于 Python 的互操作性

pip install iris-pex-embedded-python
iop --init

此代码将安装 IoP 和新的 ObjectScript 类,以便您可以在 IRIS 中调试 Python 代码。

然后,您可以使用 IOP.Wrapper 类包装 Python 代码并实现调试。

Class Article.DebuggingExample Extends %RegisteredObject
{
ClassMethod Run() As %Status
{
    set myScript = ##class(IOP.Wrapper).Import("my_script", "/irisdev/app/src/python/article/", 55550) // Adjust the path to your module
    Do myScript.run()
    Quit $$$OK
}
}

然后,向 launch.json 文件添加以下配置,将 VsCode 配置为使用 IoP 调试器:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python in IRIS",
            "type": "python",
            "request": "attach",
            "port": 55550,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}/src/python/article",
                    "remoteRoot": "/irisdev/app/src/python/article"
                }
            ]
        }
    ]
}

现在,您可以运行用于导入 Python 模块的 ObjectScript 代码,然后将 VsCode 中的调试器关联到端口 55550

您可以使用以下命令运行此脚本:

iris session iris -U IRISAPP '##class(Article.DebuggingExample).Run()'

然后,您可以在 Python 代码中设置断点,调试器将在这些断点处停止执行,以便您检查变量并单步执行代码。

远程调试实际运作视频(针对 IoP,但原理是相同的):

Python 代码中还提供回溯信息,这对调试非常有用。

启用回溯时:

Traceback enabled

禁用回溯时:

Traceback disabled

优点

  • 远程调试:您可以远程调试在 IRIS 中运行的 Python 代码,在我看来,这是一项革命性的功能。
  • Python 调试功能:您可以使用所有 Python 调试功能,例如断点、变量检查和单步执行代码。
  • 回溯:您可以看到 Python 代码中错误的完整回溯信息,这对调试非常有用。

缺点

  • 设置的复杂程度:设置 IoP 和调试器可能会比较复杂,特别是对于初学者来说。
  • 社区解决方案:该解决方案属于社区解决方案,因此可能不像官方解决方案那样稳定,文档也可能不完善。

结论

总的来说,在 IRIS 中调试 Python 代码可以通过 IoP 社区解决方案来实现,借助该解决方案,您可以使用 Python 调试器调试在 IRIS 中运行的 Python 代码。 不过,此解决方案需要执行一些设置操作,并可能不像官方解决方案一样稳定。

IoP(基于 Python 的互操作性)

在本节中,我们将探讨 IoP(基于 Python 的互操作性)解决方案,利用该解决方案,您可以使用 Python 优先的方式在 IRIS 中运行 Python 代码。

我开发这个解决方案已经有一段时间了,可以说它是我的心血之作,该解决方案尝试解决或改善我们在本系列文章中提到的所有问题。

IoP 的要点:

  • Python 优先:您可以使用 Python 编写应用程序逻辑,这样,您可以利用 Python 的功能和库。
  • IRIS 集成:您可以轻松将 Python 代码与 IRIS 功能相集成。
  • 远程调试:您可以远程调试在 IRIS 中运行的 Python 代码。
  • 回溯:您可以看到 Python 代码中错误的完整回溯信息,这对调试非常有用。
  • 虚拟环境:支持虚拟环境功能,因此您可以更加轻松地管理依赖项。

要详细了解 IoP,您可以查阅官方文档

然后,您可以阅读以下文章详细了解 IoP:

🐍❤️如您所见,通过 IoP 这一功能强大的方法,我们可以将 Python 与 IRIS 相集成,从而可以更轻松地开发和调试应用程序。

您无需继续使用 irispython,也不必手动设置 sys.path,而是可以使用虚拟环境,并且可以调试在 IRIS 中运行的 Python 代码。

结论

希望大家喜欢这一系列关于在 IRIS 中使用 Python 的文章。

如果您对这一系列的文章有任何疑问或反馈,请随时联系我。

祝您在 IRIS 中使用 Python 时一切顺利!

0
0 18
文章 Kelly Huang · 六月 5, 2025 7m read

在过去的几个月里,我一直在从事 SMART on FHIR EHR Launch 的工作,使用 CSIRO 的两个开源应用程序:SMART-EHR-Launcher 和 SMART 表单应用程序来测试 IRIS for Health 的功能。这段旅程非常有趣,我非常感谢能有机会参与这项任务并探索 IRIS for Health 的更多潜力。

在 HL7 AU FHIR Connectathon 上成功演示了多个外部 SMART 应用程序的无缝启动后,我很高兴能与社区分享我的心得。我希望我的见解能帮助其他人更快地开始类似的项目。

这项任务涉及使用 SMART-EHR-Launcher 作为 EHR 来启动 SMART 表单应用程序。同时,IRIS for Health 被用作 EHR 的 FHIR 资源库,其 OAuth2 服务器被用作授权服务器。

在进入激动人心的时刻之前,让我们先仔细了解一下 SMART on FHIR 和 SMART on FHIR EHR 启动仪式。让我们问问我们的好朋友 ChatGPT 和 豆包。

什么是 SMART on FHIR?

SMART on FHIR 是一种用于开发医疗保健应用程序的平台,旨在实现医疗保健系统之间的互操作性、安全性和可扩展性。以下是其详细介绍:

0
1 75
文章 Kelly Huang · 九月 3, 2023 8m read

大家好。

在上一篇文章中,我们了解了如何配置 EMPI 来接收 FHIR 消息。为此,我们安装了 InterSystems 提供的 FHIR 适配器,该适配器配置了一个可以向其发送 FHIR 消息的 REST 端点。然后,我们将获取消息并将其转换为 %String,我们将通过 TCP 将其发送到 HSPIDATA 命名空间中配置的 EMPI 的输出。

好吧,是时候看看我们如何检索消息、将其转换回 %DynamicObject 并将其解析为 EMPI 用来存储信息的类。

TCP消息接收

正如我们所指出的,从配置了 FHIR 资源接收的生产中,我们已将消息发送到我们有业务服务侦听的特定 TCP 端口,在我们的例子中,该业务服务将是一个简单的EnsLib.TCP。 PassthroughService的目标是捕获消息并将其转发到业务流程,我们将在其中执行所需的数据转换。

这里有我们的商业服务:

这是它的基本配置:

FHIR 消息的转变

正如你所看到的,我们只配置了通过 TCP 接收消息的端口以及我们将向其发送消息的组件,在我们的例子中我们将其称为 Local.BP.FHIRProcess,让我们看一下说类来看看我们如何从 FHIR 资源中检索信息:

0
0 173
文章 Kelly Huang · 九月 3, 2023 7m read

对于即将到来的Python 竞赛,我想制作一个小型演示,介绍如何使用 Python 创建一个简单的 REST 应用程序,该应用程序将使用 IRIS 作为数据库。使用这个工具

  • FastAPI框架,高性能,易学,快速编码,可用于生产
  • SQLAlchemy 是 Python SQL 工具包和对象关系映射器,为应用程序开发人员提供 SQL 的全部功能和灵活性
  • Alembic 是一个轻量级数据库迁移工具,可与 SQLAlchemy Database Toolkit for Python 一起使用。
  • Uvicorn 是 Python 的 ASGI Web 服务器实现。
0
0 153
文章 Kelly Huang · 八月 2, 2023 18m read

这是一个使用 IKO 在 k3d 上部署  iris-oauth-fhir  的示例。

*  iris-oauth-fhir 是一个示例,用于部署带有 OAuth2 身份验证功能的 FHIR 服务器,InterSystems IRIS for Health 作为资源服务器,Google OpenId 则作为授权服务器。

* k3d 作为一个轻量级封装器,用于在 docker 中运行 k3s (Rancher Lab 的最小 Kubernetes 发行版)

IKO 是一个在 Kubernetes 上部署 InterSystems IRIS for Health 的工具。

2. 目录表

0
0 151
文章 Kelly Huang · 七月 19, 2023 8m read

在之前的文章中,我们已经了解了如何配置和自定义我们的 EMPI,我们已经了解了如何通过 HL7 消息传递将新患者纳入我们的系统中,但当然,并不是所有的东西都是 HL7 v.2!我们如何配置 EMPI 实例以使用 FHIR 消息传递?

什么是FHIR?

对于那些不太熟悉 FHIR 这个术语的人,只需指出它们是FastHealthcareInteroperabilityResource的首字母缩写即可。 FHIR是HL7制定的医疗保健互操作性标准,基于JSON格式和REST通信,建立了一系列不同类型信息(患者数据、医院中心、诊断、医疗预约......)的“资源”。您可以在他们的官方页面上查看所有这些资源

InterSystems 和 FHIR

从 InterSystems 中,我们了解到 FHIR 为医疗保健互操作性领域提供的实用程序,因此我们拥有广泛的产品和功能,使我们能够充分利用并发挥其全部潜力:

好吧,在我们的文章中,我们将利用适配器提供的功能来接收 FHIR 消息。

EMPI配置

0
0 178
文章 Kelly Huang · 七月 12, 2023 4m read

在本文中,我将分享我们在 2023 年全球峰会技术交流室中提出的主题。我和@Rochael Ribeiro  

借此机会,我们就以下话题进行探讨:

  • 用于快速 API 的开放交换工具
  • 开放API规范
  • 传统与快速 Api 开发
  • 复合 API(互操作性)
  • 规范优先或 API 优先方法
  • API 治理和监控
  • 演示(视频)

用于快速 API 的开放交换工具

当我们谈论快速现代 API 开发(Rest / json)时,我们将使用两个 Intersystems Open Exchange 工具:

第一个是用于快速开发 API 的框架,我们将在本文中详细介绍。

https://openexchange.intersystems.com/package/IRIS-apiPub

第二种是使用 Swagger 作为用户界面,用于 IRIS 平台上开发的 Rest API 的规范和文档,以及它们的使用/执行。其运行的基础是开放 API 规范 (OAS) 标准,如下所述:

https://openexchange.intersystems.com/package/iris-web-swagger-ui

 

什么是开放 API 规范 (OAS)?

它是全球范围内用于定义、记录和使用 API 的标准。在大多数情况下,API 甚至在实现之前就已经设计好了。我将在下一个主题中详细讨论它。

0
0 139
文章 Kelly Huang · 七月 12, 2023 4m read

FHIR 通过提供标准化数据模型来构建医疗保健应用程序并促进不同医疗保健系统之间的数据交换,彻底改变了医疗保健行业。由于 FHIR 标准基于现代 API 驱动的方法,因此移动和 Web 开发人员更容易使用它。然而,与 FHIR API 交互仍然具有挑战性,尤其是在使用自然语言查询数据时。

隆重推出FHIR - AI 和 OpenAPI 链应用程序,该解决方案允许用户使用自然语言查询与 FHIR API 进行交互。该应用程序使用OpenAILangChainStreamlit构建,简化了查询 FHIR API 的过程并使其更加用户友好。

 

FHIR OpenAPI 规范是什么?

OpenAPI 规范(以前称为 Swagger,目前是OpenAPI Initiative的一部分)已成为软件开发领域的重要工具,使开发人员能够更有效地设计、记录 API 并与 API 交互。 OpenAPI 规范定义了一种标准的机器可读格式来描述 RESTful API,提供了一种清晰一致的方式来理解其功能并有效地使用它们。

在医疗保健领域,FHIR 成为数据交换和互操作性的领先标准。为了增强FHIR的互操作能力, HL7正式记录了FHIR OpenAPI规范,使开发人员能够将FHIR资源和操作无缝集成到他们的软件解决方案中。

 

FHIR OpenAPI 规范的优点:

0
0 395
文章 Kelly Huang · 三月 28, 2023 1m read

嗨大家好!

最近我需要使用 IRIS For Health 设置本地 FHIR 服务器,我认为我找到了有史以来最简单的方法!

只需在终端中运行以下两行:

docker run --rm --name my-iris -d --publish 9091:1972 --publish 9092:52773 intersystemsdc/irishealth-community

docker exec -it my-iris iris session iris -U "USER" '##class(%ZPM.PackageManager).Shell("install fhir-server")'

您将在 http://localhost:9092/fhir/r4 本地运行 FHIR 服务器。

就是这么简单!

FHIR 服务器将使用最新版本的 InterSystems IRIS for Health Community Edition,并将通过 FHIRSERVER 命名空间中的 IPM 包从该应用程序部署 FHIR 服务器

这是针对 Mac OS的,所以请在评论中添加它在 Windows 中的工作方式。

这是一篇非常短的文章,因为使用 InterSystems IRIS for Health 和IPM Package Manager 设置本地 FHIR 服务器真的很容易。

0
0 255
文章 Kelly Huang · 二月 27, 2023 15m read

物联网( IoT ,Internet of things )即“万物相连的互联网”,是互联网基础上的延伸和扩展的网络,将各种信息传感设备与网络结合起来而形成的一个巨大网络,实现任何时间、任何地点,人、机、物的互联互通 

物联网是新一代信息技术的重要组成部分,IT行业又叫:泛互联,意指物物相连,万物万联。由此,“物联网就是物物相连的互联网”。这有两层意思:第一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络;第二,其用户端延伸和扩展到了任何物品与物品之间,进行信息交换和通信。因此,物联网(Internet of Things,简称IoT)是指通过各种信息传感器、射频识别技术全球定位系统红外感应器、激光扫描器等各种装置与技术,实时采集任何需要监控、 连接、互动的物体或过程,采集其声、光、热、电、力学、化学、生物、位置等各种需要的信息,通过各类可能的网络接入,实现物与物、物与人的泛在连接,实现对物品和过程的智能化感知、识别和管理。物联网是一个基于互联网、传统电信网等的信息承载体,它让所有能够被独立寻址的普通物理对象形成互联互通的网络。在https://baike.baidu.com/item/物联网/7306589?fromtitle=IoT&fromid=552548&fr… 查看更多信息

0
0 228