搜索​​​​

清除过滤器
文章
Jingwei Wang · 二月 15

使用嵌入式 Python 和 OpenAI API 在 IRIS 中进行数据标签

大型语言模型(例如 OpenAI 的 GPT-4)的发明和普及掀起了一波创新解决方案浪潮,这些解决方案可以利用大量非结构化数据,在此之前,人工处理这些数据是不切实际的,甚至是不可能的。此类应用程序可能包括数据检索(请参阅 Don Woodlock 的 ML301 课程,了解检索增强生成的精彩介绍)、情感分析,甚至完全自主的 AI 代理等! 在本文中,我想演示如何使用 IRIS 的嵌入式 Python 功能直接与 Python OpenAI 库交互,方法是构建一个简单的数据标记应用程序,该应用程序将自动为我们插入IRIS 表中的记录分配关键字。然后,这些关键字可用于搜索和分类数据,以及用于数据分析目的。我将使用客户对产品的评论作为示例用例。 先决条件 运行的IRIS实例 OpenAI API 密钥(您可以在此处创建) 配置好的开发环境(本文将使用VS Code ) Review类 让我们首先创建一个 ObjectScript 类,该类将定义客户评论的数据模型。为了简单起见,我们将只定义 4 个 %String 字段:客户姓名、产品名称、评论正文以及我们将生成的关键字。该类应该扩展%Persistent,以便我们可以将其对象保存到磁盘。 Class DataTagging.Review Extends %Persistent { Property Name As %String(MAXLEN = 50) [ Required ]; Property Product As %String(MAXLEN = 50) [ Required ]; Property ReviewBody As %String(MAXLEN = 300) [ Required ]; Property Keywords As %String(MAXLEN = 300) [ SqlComputed, SqlComputeOnChange = ReviewBody ]; } 由于我们希望在插入或更新 ReviewBody 属性时自动计算 Keywords属性,因此我将其标记为SqlComputed。您可以在此处了解有关计算值的更多信息。 KeywordsComputation方法 我们现在想要定义一种方法,用于根据ReviewBody计算Keywords。我们可以使用Embedded Python直接与官方的openai Python包进行交互。但首先,我们需要安装它。为此,请运行以下 shell 命令: <your-IRIS-installation-path>/bin/irispip install --target <your-IRIS-installation-path>/Mgr/python openai 我们现在可以使用 OpenAI 的聊天完成 API 来生成关键字: ClassMethod KeywordsComputation(cols As %Library.PropertyHelper) As %String [ Language = python ] { ''' This method is used to compute the value of the Keywords property by calling the OpenAI API to generate a list of keywords based on the review body. ''' from openai import OpenAI client = OpenAI( # Defaults to os.environ.get("OPENAI_API_KEY") api_key="<your-api-key>", ) # Set the prompt; use few-shot learning to give examples of the desired output user_prompt = "Generate a list of keywords that summarize the content of a customer review of a product. " \ + "Output a JSON array of strings.\n\n" \ + "Excellent watch. I got the blue version and love the color. The battery life could've been better though.\n\nKeywords:\n" \ + "[\"Color\", \"Battery\"]\n\n" \ + "Ordered the shoes. The delivery was quick and the quality of the material is terrific!.\n\nKeywords:\n" \ + "[\"Delivery\", \"Quality\", \"Material\"]\n\n" \ + cols.getfield("ReviewBody") + "\n\nKeywords:" # Call the OpenAI API to generate the keywords chat_completion = client.chat.completions.create( model="gpt-4", # Change this to use a different model messages=[ { "role": "user", "content": user_prompt } ], temperature=0.5, # Controls how "creative" the model is max_tokens=1024, # Controls the maximum number of tokens to generate ) # Return the array of keywords as a JSON string return chat_completion.choices[0].message.content } 请注意,在提示中,我首先指定了我希望 GPT-4 如何“生成总结产品客户评论内容的关键字列表”的一般说明,然后给出两个示例输入以及所需的输入输出。然后,我插入 cols.getfield("ReviewBody") 并以“Keywords:”一词结束提示,通过提供与我给出的示例格式相同的关键字来推动它完成句子。这是Few-Shot Prompting技术的一个简单示例。 为了演示的简单性,我选择将关键字存储为 JSON 字符串;在生产中存储它们的更好方法可能是DynamicArray ,但我将把它作为练习留给读者。 关键词生成 现在,我们可以通过管理门户使用以下 SQL 脚本向表中插入一行来测试我们的数据标记应用程序: INSERT INTO DataTagging.Review (Name, Product, ReviewBody) VALUES ('Ivan', 'BMW 330i', 'Solid car overall. Had some engine problems but got everything fixed under the warranty.') 如下所示,它自动为我们生成了四个关键字。做得好! 结论 总而言之,InterSystems IRIS 嵌入 Python 的能力在处理非结构化数据时提供了多种可能性。利用 OpenAI 的强大功能进行自动数据标记只是利用这一强大功能可以实现的目标之一。这可以减少人为错误并提高整体效率。
文章
Michael Lei · 二月 14

FHIR 用例集: 打破数字医疗壁垒,实现高质量发展

FHIR 用例集: 打破数字医疗壁垒,实现高质量发展 --促进互联互通,改进工作流程,提高数据洞察 简介 HL7® FHIR®(快速医疗互操作性资源)是以电子方式访问、交换和管理医疗信息的国际标准。与以往的标准不同,FHIR 可让帮助行业从业者轻松构建创新应用程序,有效地收集、汇总和分析来自不同来源的各种医疗保健和管理数据。医疗机构、社保/保险公司、政府机构、生命科学公司、医疗设备制造商和医疗科技等多种主体利用 FHIR 来简化信息流、提高数据洞察力、改善临床效果和业务成果。 FHIR 基于 JSON、HTTP 和 REST 等流行的网络技术。有了 FHIR,没有医疗信息化背景的软件开发人员也能使用熟悉的开发工具和开源技术,快速、轻松地满足政府机构、临床医生、研究人员、医疗行业从业者以及各类市场主体的数据需求。 FHIR 是一种灵活、适应性强的医疗数据模型,可轻松定制,以实现各种用例的互操作性。FHIR 由称为 "资源 "的离散、可计算的数据对象组成,以实现最佳效率。通过 FHIR 资源,应用程序可以访问单个医疗记录元素,而无需检索摘要文档中包含的所有数据。 本文回顾了 FHIR 的实际应用,并提供了 InterSystems 客户如何使用 FHIR 连接不同系统、加速数字化转型和提高数据洞察力的真实案例。 FHIR 商机无限 FHIR 正在改变医疗健康数据的访问和交换。无论您是为政府、医疗机构、公共卫生机构、保险公司还是厂商工作,FHIR 都能帮助您高效地获取、检索和共享来自电子病历系统、智能医疗设备、可穿戴设备、临床试验和公共卫生监测系统等不同来源的医疗数据。 当前应用和未来的 FHIR 用例FHIR支持实现大量的不同业务场景。您可以在各种部署场景中将 FHIR 用于各种目的。下面的列表总结了 FHIR 在不同行业领域的一些当前应用和潜在的未来用例。 医疗机构 应用场景: 患者数据访问 API机会:可以基于FHIR资源和技术框架实现卫健委互联互通三年攻坚计划以及国家数据局"数据要素x医疗行业"三年行动计划中提到的相关电子健康档案共享、检验检查互认、医疗行业数据要素流通、交易等战略目标,通过基于标准的 (FHIR) API 让患者以程序化的方式访问其健康数据(病史、化验结果、治疗计划等),以及未来可能的全国统一医疗健康档案超级APP(患者端)。 应用场景: 临床决策支持机会: 使用 FHIR 改善临床决策系统的洞察力。将实时电子病历数据安全传输到第三方系统进行分析并返回建议,帮助临床医生做出明智决策。与以往的标准和方法不同,使用 FHIR,您可以将临床决策支持功能直接嵌入电子病历,以简化流程。 应用场景: 医疗机构与支付方(医保/保险公司)的合规数据交换 机会: 利用 FHIR 自动化医疗机构与支付方之间的数据交换。消除资源密集、耗时的人工流程(降低飞行检查和审计成本)。允许医疗机构直接将电子病历数据转发给支付方,无需人工干预。 使用案例: 临床试验和研究机会: 使用 FHIR 无缝共享临床试验招募和分析所需的患者数据,加快临床研究进程。 设备制造商、医疗科技公司和应用开发商 用例:远程医疗和远程监控机会: 使用 FHIR 可将患者数据从家用医疗设备安全地传输给医疗服务提供者,以便他们有效地远程监控和管理患者。 用例: 移动医疗应用程序机遇: 患者可以在手机端访问在不同医院治疗的电子病历,并且确保患者数据的隐私和安全。 用例: 慢性病管理应用程序机会: 使用 FHIR 在医疗服务提供者之间无缝共享患者数据,以实现一致的监控和协调的护理计划。 用例: 药物管理应用程序机会: 为临床医生和护理人员创建多功能药物管理应用程序。使用 FHIR 在区域全民健康信息平台之间高效共享处方信息、用药计划和药房记录。 生命科学公司、政府机构和付款人 用例:健康信息交换机会: 使用 FHIR,政府、公共卫生、保险公司等可高效开展电子健康档案/电子病历共享调阅数据,以进行质量评估、护理差距识别、理赔裁定以及开展潜在的数据交易等。 用例: 护理计划机会: 利用 FHIR,让跨机构护理团队--医生、家庭医疗工作者、社区护理人员、家庭成员等--能够无缝交换信息。让不同的医疗保健系统进行有效沟通。确保所有护理团队成员都能获得最新的患者信息。 用例: 公共卫生报告机会: 使用 FHIR 有效地汇总和共享患者数据,以进行监控和人口健康管理,从而简化公共卫生报告。利用电子病历批量检索功能。(注:该功能自 2022 年起已成为所有美国电子病历系统的强制性要求,在WHO、OECD、欧盟、亚洲、港澳台等地区也正在逐步推广普及) 以上只是部分FHIR的用例,有了FHIR,从业者可以打开无限想象空间,创建丰富多样、互联互通的数字医疗创新应用。
文章
Claire Zheng · 二月 9

InterSystems开发者社区中文版恭祝开发者们龙年大吉!

农历甲辰龙年迤逦而来,InterSystems开发者社区在过去的一年里得到了各位开发者的厚爱与支持,在这新的一年里,恭祝大家龙行龘龘,前程朤朤!
公告
Claire Zheng · 二月 6

InterSystems 编程大赛获奖名单公布:FHIR和数字医疗互操作性

Hi 开发者们, 是时候宣布 InterSystems 编程大赛:FHIR和数字医疗互操作性的获奖者了! 我们收到了12 份申请,感谢这些出色的参赛者 🔥 专家提名奖 🥇第一名,5,000 美元,@José.Pereira、@Henry.HamonPereira、@Henrique.GonçalvesDias ,应用程序iris-fhirfy 🥈第二名,3,000 美元,@Muhammad.Waseem ,应用程序iris-fhir-lab 🥉第三名,1,500 美元,@Flavio.Naves、Denis Kiselev、Maria Ogienko、Anastasia Samoilova、Kseniya Hoar ,应用程序ai-query 🏅第四名,750 美元,@Maria.Gladkova、@KATSIARYNA.Shaustruk、@Maria.Nesterenko、@Alena.Krasinskiene,应用程序Health Harbor 🏅第五名和第六名,各300 美元 @xuanyou du 应用程序 FHIR-OCR-AI @Oliver.Wilms 应用程序iris-hl7 🌟 100 美元,@shan yue 应用程序Fhir-HepatitisC-Predict 🌟 100 美元,@Shanshan Yu,应用程序fhirmessageverification 🌟 100 美元,@Yuri.Gomes,应用程序Clinical Mindmap Viewer 🌟 100 美元,@Chang Dao,应用程序Patient-PSI-Data 社区提名奖 🥇第一名,1,000 美元, @José.Pereira、@Henry.HamonPereira、@Henrique.GonçalvesDias 应用程序iris-fhirfy 🥈第二名,750 美元,@shan.yue ,应用程序Fhir-HepatitisC-Predict 🥉第三名,500 美元,@xuanyou.du ,应用程序FHIR-OCR-AI 🏅第四名,300 美元,@Muhammad.Waseem ,应用程序iris-fhir-lab 🏅第五名,200 美元,@Flavio.Naves、Denis Kiselev、Maria Ogienko、Anastasia Samoilova、Kseniya Hoar,应用程序ai-query 我们向所有参赛者和获奖者表示最诚挚的祝贺! 下次再一起享受乐趣吧;)
文章
Qiao Peng · 一月 31

用Java开发互操作产品 - PEX

InterSystems IRIS、Health Connect和上一代的Ensemble提供了优秀的互操作架构,但即便有低代码开发能力,很多开发者还是希望能用自己的技术栈语言在InterSystems的产品上开发互操作产品。 考虑到互操作产品本身的开放性要求和各个技术栈背后庞大的生态价值,InterSystems IRIS和Health Connect提供了Production EXtension (PEX)架构,让开发者使用自己的技术栈语言来开发互操作解决方案。目前PEX支持Java、.net、Python。 这里我们介绍使用Java利用PEX进行互操作产品的开发。 一 InterSystems IRIS上使用Java开发的基础 在进入PEX主题前,需要简单介绍一下Java在InterSystems IRIS上开发的各种技术选项,因为PEX也是以这些技术选项为基础的。 如果仅把InterSystems IRIS作为一个数据库看待,可以使用JDBC对它进行SQL访问,这是最传统的开发方式; Java是一个面向对象的开发语言,而InterSystems IRIS也是支持面向对象的数据平台。InterSystems IRIS的外部语言服务器技术,提供了一套Java原生SDK,让Java和InterSystems IRIS可以互相访问对方的对象,甚至Java可以通过它直接访问InterSystems IRIS后台的持久化多维数组。外部语言服务器提供了非常灵活、高效的开发方式; 如果是想把Java对象直接持久化到InterSystems IRIS,除了Hibernate,InterSystems IRIS提供一种更高性能的方法 - XEP(Express Event Persistence表达事件持久化); 最后,Java可以通过PEX开发InterSystems IRIS的互操作产品组件。PEX基于Java原生SDK。 作为多种Java访问方式的基础,InterSystems IRIS的Java外部语言服务器的架构如下: InterSystems IRIS和Java通过动态代理对象的方式操作对方对象,动态代理无需在对方代码变更时重新生成代理类。 InterSystems IRIS提供了intersystems-jdbc-<版本号>.jar,不仅用于JDBC连接、也用于Java外部语言服务器连接,提供Java原生SDK。 在Java端通过jdbc.IRIS管理InterSystems IRIS连接,使用jdbc.IRISObject反向操作IRIS对象。 InterSystems IRIS端提供并管理包括Java语言服务器在内的一系列外部语言服务器。注意,一般情况下,使用系统开箱的这些外部服务器就够了,不需要额外建立额外的Java语言服务器。而且,也无需事先启动,外部语言服务器会在调用时自动启动。 Java连接到InterSystems IRIS,并创建IRIS外部服务器的示例: String connStr = "jdbc:IRIS://127.0.0.1:1972/USER"; String user = "superuser"; String pwd = "SYS"; // 使用DriverManager 创建IRIS连接 // IRISConnection conn = (IRISConnection)java.sql.DriverManager.getConnection(connStr,user,pwd); // 或使用IRISDataSource 创建IRIS连接 IRISDataSource ds = new IRISDataSource(); ds.setURL(connStr); ds.setUser(user); ds.setPassword(pwd); IRISConnection conn = (IRISConnection) ds.getConnection(); // 创建IRIS外部服务器 IRIS irisjv = IRIS.createIRIS(conn); // 调用IRIS类%PopulateUtils的类方法Name,产生随机姓名 String tempTrader = irisjv.classMethodString("%PopulateUtils", "Name"); 二 PEX 开发 PEX针对于互操作产品的开发,通过PEX使用外部语言开发互操作产品所需的组件,甚至可以通过PEX开发互操作产品的所有组件。 2.1 InterSystems IRIS互操作产品架构 典型的InterSystems IRIS互操作产品架构如下,它的典型工作机制是: 业务服务通过入站适配器监听外部系统,例如TCP和文件系统,将数据组织成消息发送给业务流程 业务流程根据流程需要在特定流程节点将消息发送给业务操作 业务操作通过出站适配器访问外部应用,发送数据并获取响应,并将响应数据组织成消息反馈给业务流程 在互操作产品内部流转的都是消息,消息默认自动持久化并可以通过SQL等方式结构化查询 互操作产品涉及3类组件: 业务组件:包括业务服务、业务流程、业务操作 适配器:包括入站适配器和出站适配器 消息 这3类组件都可以通过PEX进行开发。 2.2 PEX 类和类包 InterSystems IRIS 提供了一个intersystems-utils-<版本号>.jar包,提供com.intersystems.enslib.pex类包,用于基于Java开发互操作产品组件。 在Java代码里还要调用IRIS Object Script开发的组件和代码,因此,还需要intersystems-jdbc-<版本号>.jar。 2.3 示例业务场景介绍 下面我们根据一个示例业务场景介绍如何使用Java PEX进行互操作产品的开发。 业务场景是一个银行间汇款的流程: 业务服务(Finance.FromFileTransaction)监听特定文件夹,并从新汇款申请文件中解析出汇款请求,发送给业务流程(Finance.ProcessPaymentRequest); 业务流程先将请求发送给汇出行的业务操作(Finance.ToPayFromBank),获取汇出行的审核结果; 如果汇出行审核批准,则业务流程继续将请求发送给接收行的业务操作(Finance.ToPayToBank) 这里汇出行的业务操作和接收行的业务操作都会将数据写入特定文件夹的文件中。 这个场景中,我们完全使用Java开发全部的组件,包括:请求、响应消息;入站、出站文件适配器;业务操作;业务流程和业务服务。 下面我们就开始吧。 2.4 消息开发 Java消息类是com.intersystems.enslib.pex.Message的子类,消息中的属性,需要定义为public。它会在互操作业务组件间传递时自动持久化。 在IRIS端,Java消息自动映射到EnsLib.PEX.Message,它是一个持久化的IRIS类,包含以下属性: %classname属性:Java消息类名 %json属性:Java消息的JSON类型(IRIS动态对象) 在InterSystems IRIS端,例如消息可视化追踪页面和消息表,你看到的Java消息都是EnsLib.PEX.Message类型。 PEX消息用到的共同账号信息类的示例代码: package Finance; // 封装银行账号信息的类. public class PaymentProfile extends com.intersystems.enslib.pex.Message { public int AccountNumber; public int RoutingNumber; public String UserName; } 请求消息的示例代码: package Finance; import Finance.PaymentProfile; // PEX开发的转账请求消息. public class TransactionRequest extends com.intersystems.enslib.pex.Message { public double TransactionAmount; // 转账金额 public PaymentProfile PayFrom; // 付方银行账号信息 public PaymentProfile PayTo; // 收方银行账号信息 public String FromCurrency; // 付方货币 public String ToCurrency; // 收方货币 // 实例化银行账号属性. public TransactionRequest(){ PayFrom = new PaymentProfile(); PayTo = new PaymentProfile(); } } 响应消息的示例代码: package Finance; // PEX开发的转账响应消息. public class TransactionResponse extends com.intersystems.enslib.pex.Message { public boolean approved; } 2.5 业务组件和适配器的运行时变量 在互操作产品的管理配置页面,可以设置各个业务组件和适配器的配置项,例如文件适配器的文件路径,方便实施和管理。 对于Java开发的业务组件和适配器,同样我们需要这样的配置项。这些配置项,我们称之为运行时变量,这样进行定义: 运行时变量是Java业务组件类和适配器类的public类型的属性 对这些属性使用Java annotation进行元数据描述,例如: @FieldMetadata(IsRequired=true,Description="文件路径") public String FilePath; 后面的Java业务组件和适配器会用到运行时变量的声明方法。 2.6 入站适配器开发 如果要开发Java入站适配器,需要定义一个com.intersystems.enslib.pex.InboundAdapter的Java子类。并在类中实现以下方法: 方法 参数 说明 OnTask 无 适配器根据调用间隔设置,周期性地调用该方法对数据源进行查询;将数据调用BusinessHost.ProcessInput()将数据发送给业务服务;BusinessHost是业务服务的固定的变量名 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 例如入站文件适配器示例代码如下: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类 // 这是一个PEX的入站适配器,检测定义在InboundFilePath的文件夹路径。如果文件夹下有文件,遍历这些文件,使用ProcessInput()将文件路径发送给业务服务 public class PEXInboundAdapter extends com.intersystems.enslib.pex.InboundAdapter { @FieldMetadata(IsRequired=true,Description="输入文件路径") public String InboundFilePath; // 文件夹路径配置项. public void OnTearDown() {} public void OnInit() {} public void OnTask() throws Exception { // 检查文件夹路径,并遍历文件. File folder = new File(InboundFilePath); File[] list = folder.listFiles(); if (list.length > 0) { for (File file : list) { // 忽略.keep后缀文件. // 其它文件路径发送给业务组件BusinessHost. if (file.getName().equals(".keep")) {continue;} BusinessHost.ProcessInput(file.getAbsolutePath()); } } } } 2.7 Java开发组件的注册与更新 开发好的Java组件,需要在InterSystems IRIS端进行注册,让互操作产品可以直接使用这些组件。 注册的方法在Production扩展页面,点击注册新组件: 在远程类名称中填写Java组件类名 在代理名称中填写IRIS生成的代理类名称,可以和Java类名不同。这个类名是在互操作产品中看到和使用的名字。 选择外部语言服务器为%Java Server 将封装有Java组件类的jar文件路径和其它依赖jar文件路径添加到网关额外CLASSPATHS下 注册后就可以在列表中看到注册的组件和组件类型,并在互操作产品中可以直接使用了。 如果后来修改了Java代码,则需要选中已经组册的组件,对其进行更新: * 记得下面这些Java开发的组件也需要注册后使用。 2.8 出站适配器开发 同样,可以通过继承com.intersystems.enslib.pex.OutboundAdapter来开发Java出站适配器类。 它需要实现以下方法: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 其它方法 根据需要 执行具体的适配器操作 例如出站文件适配器示例代码如下,它提供写文件的方法: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import java.lang.StringBuffer; // 导入string buffer类. import java.io.FileWriter; // 写文件的包. import java.util.Date; // 处理日期的包. import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类. import java.text.SimpleDateFormat; // 格式化日期字符串的包. // 这是一个PEX的出站适配器,通常被业务操作使用,连接到外部系统. 这里适配器提供WriteToFile()方法,供业务操作调用. public class PEXOutboundAdapter extends com.intersystems.enslib.pex.OutboundAdapter { @FieldMetadata(IsRequired=true,Description="输出文件路径") public String FilePath; // 输出文件路径. public void OnTearDown() {} public void OnInit() {} //写文件的方法,输入参数input是向文件中写入的内容 public Object WriteToFile(java.lang.Object input) throws Exception { // 转换为字符串 String OutputMessage = (String)input; // 允许用户输入的路径有或没有尾部路径分隔符. if (FilePath.substring(FilePath.length() - 1) != File.separator) { FilePath = FilePath + File.separator; } // 用当前日期时间产生文件名. Date today = new Date(); SimpleDateFormat Formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); String DateString = Formatter.format(today); // 产生完整文件路径. String OutputPath = FilePath + DateString; // 创建文件. File OutputFile = new File (OutputPath); // 实例化FileWriter对象. FileWriter writer = new FileWriter(OutputFile); // 将内容写入文件 writer.write(OutputMessage); writer.close(); return null; } } 2.9 业务操作开发 Java业务操作类,是com.intersystems.enslib.BusinessOperation的子类。需要实现以下功能: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 OnMessage 无 个方法会在业务操作收到其它业务组件传递过来的消息时被调用 在该方法内部,可以调用适配器的方法 - Adapter.invoke("适配器方法名", 方法参数) Adapter是适配器对象,已经实例化,无需执行自己的实例化代码。Adapter是固定变量名 getAdapterType 无 返回使用的适配器类名 如果是PEX开发的适配器,返回的是它注册到InterSystems IRIS的代理类名 如果使用默认适配器,返回 Ens.InboundAdapter 如果不使用适配器,返回空字符串 例如我们的示例中,有以下2个业务操作: 1. 与汇出银行接口的业务操作类: package Finance; import Finance.TransactionRequest; import Finance.PaymentProfile; import Finance.TransactionResponse; import java.lang.StringBuffer; // PEX业务操作类,和支付银行接口. // 它从业务流程接收请求消息Finance.ProcessPaymentRequest, 将消息内容写入文件并返回内容为'approval' 的响应消息(Finance.TransactionResponse). public class ToPayFromBank extends com.intersystems.enslib.pex.BusinessOperation { public void OnTearDown() {} public void OnInit(){} // 确定适配器 public String getAdapterType() { return "Finance.PEXOutboundAdapter"; } // 响应请求消息 public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的类实例. TransactionRequest request = (TransactionRequest)object; // 初始化StringBuffer对象,构造输出文件内容. StringBuffer outputMessage = new StringBuffer(); // 将数据写入StringBuffer. outputMessage.append("Debit request:" + System.lineSeparator()); outputMessage.append("Route:" + request.PayFrom.RoutingNumber + System.lineSeparator()); outputMessage.append("Account: " + request.PayFrom.AccountNumber + System.lineSeparator()); outputMessage.append("Amount: " + request.TransactionAmount); // 调用出站适配器的方法,将数据写入文件. Adapter.invoke("WriteToFile", outputMessage.toString()); // 实例化响应消息,并对响应消息赋值后返回给业务流程. TransactionResponse response = new TransactionResponse(); response.approved = true; return response; } } 2. 与接收银行接口的业务操作类: package Finance; import Finance.TransactionRequest; import Finance.PaymentProfile; import java.lang.StringBuffer; // PEX业务操作类,和收款银行接口. // 从业务流程接收请求消息,并将消息内容写入文件. public class ToPayToBank extends com.intersystems.enslib.pex.BusinessOperation { public void OnTearDown() {} public void OnInit(){} // 确定适配器 public String getAdapterType() { return "Finance.PEXOutboundAdapter"; } // 响应请求消息 public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的消息类实例. TransactionRequest request = (TransactionRequest)object; // 实例化StringBuffer对象以构造文件内容. StringBuffer outputMessage = new StringBuffer(); // 将数据写入StringBuffer. outputMessage.append("credit request:" + System.lineSeparator()); outputMessage.append("SourceRouting:" + request.PayFrom.RoutingNumber + System.lineSeparator()); outputMessage.append("SourceAccount: " + request.PayFrom.AccountNumber + System.lineSeparator()); outputMessage.append("ToAccount: " + request.PayTo.AccountNumber + System.lineSeparator()); outputMessage.append("Amount: " + request.TransactionAmount); // 调用出站适配器方法将数据写入文件 Adapter.invoke("WriteToFile", outputMessage.toString()); // 无需响应消息. return null; } } 2.10 业务流程开发 使用Java开发业务流程,则完全是代码开发模式,而非基于BPL的低代码模式。 Java业务流程类是com.intersystems.enslib.pex.BusinessProcess 的子类,需要实现以下方法: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 OnRequest request 请求消息 处理发送给业务流程的请求消息,这个请求消息启动业务流程 OnResponse request 请求消息, response 响应消息, callRequest - 本次异步调用发起的请求消息, callResponse - 本次异步调用收到的响应消息, completionKey - 异步调用发起时传入的completionKey 处理异步调用返回的响应消息-callResponse OnComplete request 请求消息, response 响应消息 整个业务流程完成时,被调用的方法 另外,类里还可以声明需要在业务流程期间保存的持久化数据,和在BPL中要到的上下文(context)数据一样,例如记录汇出行的审核结果。声明时,需要加@Persistent这个Java annotation: @Persistent // 定义名为runningTotal的持久化的属性 public integer runningTotal = 0; 本用例的业务流程示例代码如下: package Finance; import Finance.TransactionRequest; //导入请求消息类 import Finance.TransactionResponse; //导入响应消息类 // 这是一个PEX业务流程类,它从业务服务(Finance.FromFileService)接收请求消息. // 先将汇款请求消息发送给汇出行业务操作(Finance.ToPayFromBank) 并等待审核结果. 如果批准, 将请求消息发送给接收行业务操作(Finance.ToPayToBank). public class ProcessPaymentRequest extends com.intersystems.enslib.pex.BusinessProcess { public Object OnComplete(Object object,Object object2) {return null;} public void OnTearDown(){} public void OnInit(){} // 无需返回响应消息给调用者 public java.lang.Object OnResponse(java.lang.Object request, java.lang.Object response, java.lang.Object callRequest, java.lang.Object callResponse, java.lang.String completionKey) throws java.lang.Exception { return null; } // 处理请求消息 public java.lang.Object OnRequest(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的消息类实例. TransactionRequest request = (Finance.TransactionRequest) object; // 将支付请求消息以同步请求的方式发送给汇出行. Object response = SendRequestSync("Finance.ToPayFromBank", request); // 将收到的响应消息对象转换为对应的消息类实例. TransactionResponse bankResponse = (TransactionResponse)response; // 记录汇出行审核结果,用于调试 LOGINFO("汇出行审核结果是:"+bankResponse.approved); // 检查汇出行审核结果,如果是批准,则将汇款请求发送给接收行. if (bankResponse.approved) { // 使用异步调用方式通知接收行,无需等待返回. SendRequestAsync("Finance.ToPayToBank", request); } return null; } } 2.11 业务服务开发 Java业务服务类是com.intersystems.enslib.pex.BusinessService 的子类。它有一个父类定义的属性 – TargetComponentNames, 用于设置发送消息目标的下游业务组件名列表。可以同时发送消息给多个下游业务组件,组件名之间通过逗号分隔。 业务服务可以使用适配器,这时它会根据适配器的设置定期轮询外部系统,例如SQL适配器轮询外部SQL表、文件适配器轮询外部文件夹。但业务服务也可以不使用适配器,而直接被外部系统调用,例如发布为SOAP、RESTful服务的业务服务就不使用适配器。 适配器 执行过程 需要实现的方法 使用专业适配器 适配器的OnTask()方法定期执行获得数据,将数据发送给业务服务的ProcessInput() OnProcessInput() 使用默认适配器 Ens.InboundAdapter 适配器的OnTask()方法定期执行,并调用业务服务的ProcessInput(); 业务服务的OnProcessInput()执行数据获取 OnProcessInput() 不使用适配器 不定期执行,用户代码在需要时通过Director.CreateBusinessService() 创建业务服务,并执行其方法 OnProcessInput() 或其它需要的方法 本示例中的业务服务使用前面Java开发的文件入站适配器,其代码如下: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import java.util.Scanner; // 导入Scanner类读取文本文件. import Finance.TransactionRequest; // 导入请求消息类. // 这是一个PEX的业务服务类,从文件读取汇款请求. 将文件内容转换为Finance.TransactionRequest消息对象,并检查运行时变量TargetComponentNames,确定需要把请求消息发送给哪些业务组件. public class FromFileTransaction extends com.intersystems.enslib.pex.BusinessService { public String TargetComponentNames; // 用逗号分隔的发送目标组件列表,运行时从配置项获取. public void OnTearDown() {} public void OnInit() {} // 确定适配器 public String getAdapterType() { return "Finance.PEXInboundAdapter"; } // OnProcessInput根据业务服务的'call interval' 设置会被定期调用. public java.lang.Object OnProcessInput(java.lang.Object messageInput) throws java.lang.Exception { String path = (String)messageInput; File file = new File(path); // 创建scanner对象读取文件. Scanner reader = new Scanner(file); // 实例化请求消息TransactionRequest对象. TransactionRequest request = new TransactionRequest(); // 设置消息属性. request.TransactionAmount = Float.parseFloat(reader.nextLine().split(":")[1]); String tempString = reader.nextLine(); // 解析嵌套的PaymentProfile对象,并赋值给请求消息的PayFrom属性. String[] tempStringArray = tempString.split(":"); String[] PaymentProfile = tempStringArray[1].split("\\|"); request.PayFrom.AccountNumber = Integer.parseInt(PaymentProfile[0]); request.PayFrom.RoutingNumber = Integer.parseInt(PaymentProfile[1]); request.PayFrom.UserName = PaymentProfile[2]; // 解析PaymentProfile对象,并赋值给PayTo属性. tempString = reader.nextLine(); tempStringArray = tempString.split(":"); PaymentProfile = tempStringArray[1].split("\\|"); request.PayTo.AccountNumber = Integer.parseInt(PaymentProfile[0]); request.PayTo.RoutingNumber = Integer.parseInt(PaymentProfile[1]); // 设置剩余属性. request.PayTo.UserName = PaymentProfile[2]; request.FromCurrency = reader.nextLine().split(":")[1]; request.ToCurrency = reader.nextLine().split(":")[1]; reader.close(); // 处理后删除文件. file.delete(); // 获取Split target business component string and send to each component. String[] targetNames = TargetComponentNames.split(","); for (String name : targetNames){ SendRequestAsync(name, request); } return null; } } 2.12 组装互操作产品并进行测试 将这些Java开发的组件组册后,就可以像InterSystems IRIS的本地组件一样使用了。我们将业务操作、业务流程和业务服务依次加入到Production,并配置好相应的配置项: 对于每个业务操作,需要配置一项: 文件路径:输出的文件夹路径 对于业务服务,需要配置两项: InboundFilePath: 监听的汇款请求文件夹路径 TargetComponentNames: 目标业务流程,这里应该填Finance.ProcessPaymentRequest 下面是用于测试的汇款请求文件内容,把它copy到一个文本文件中保存: TransactionAmount:59.43 PayFrom:232422|23532532|TJohnson21 PayTo:24224242|423533453|ERichards55 FromCurrency:USD ToCurrency:USD 启动Production后,可以将测试数据文件copy到业务服务监听到文件夹下。如果成功,应该可以看到这样的消息追踪结果,可以看到,用Java开发的PEX组件运行结果和IRIS自带的组件没有区别: 2.13 需要实现的Java类方法总结 下图总结了用Java开发不同组件时,需要实现的方法,以及这些组件间的调用流程和关系: 完整的规范参见这里。 三 在Java组件中使用Object Script开发的组件 上面是使用Java开发全套互操作产品组件的示例。实际情况下,InterSystems IRIS已经提供了大量适配器、消息和业务组件,而且使用低代码工具 - 例如业务流程建模图形化工具 - 往往更方便,所以通常Java可以使用Object Script开发的大量组件,而无需全部由Java开发。 在低代码开发业务流程时,可以直接在BPL里调用Java PEX开发的业务流程和业务操作,和IRIS本地开发的组件无异。 另外两种典型的用例是Java组件使用Object Script的消息、Java组件使用Object Script的适配器。在Java端使用Object Script类和对象,需要有前面讲的Java外部语言服务器的基础,文档参见这里。 3.1 Java组件使用Object Script的消息 在Java PEX中使用Object Script定义的消息,直接使用IRIS类的反向代理类IRISObject即可。例如在Java PEX业务操作的OnMessage方法中,要获得传入的Object Script消息的属性值,只需要把传入消息对象转换为IRISObject对象,并调用它的getXXX方法获取属性即可,可以这样: @Override public Object OnMessage(Object object) throws Exception { // 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值 // 使用ObjectScript消息,将Object转换为 IRISObject IRISObject requestObj = (IRISObject)object; 通过IRISObject的getString方法获取它名为StringValue属性的值 String value = requestObj.getString("StringValue"); ... } 那怎么在Java组件中创建新的Object Script消息实例呢?你需要已经建立了IRIS连接的类型为com.intersystems.jdbc.IRIS的实例。 PEX的Java业务组件类和适配器类都继承于Common类,从Common类继承一个公共属性irisHandle,类型为IRISObject。而irisHandle有一个公共属性iris,类型为com.intersystems.jdbc.IRIS。因此可以通过它来创建Object Script消息实例。例如我们要创建一个类型为Ens.StringContainer的响应消息,并给其StringValue属性赋值: @Override public Object OnMessage(Object object) throws Exception { // 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值 // 使用ObjectScript消息,将Object转换为 IRISObject IRISObject requestObj = (IRISObject)object; String value = requestObj.getString("StringValue"); // 创建一个类型为Ens.StringContainer的ObjectScript响应消息 IRISObject response = (IRISObject)(this.irisHandle.iris.classMethodObject("Ens.StringContainer","%New")); response.set("StringValue",value+"test me"); return response; } 3.2 Java业务组件使用Object Script的适配器 如果Java业务服务使用Object Script的适配器,无需做任何处理,适配器会将数据发送给Java业务服务的OnProcessInput方法,而Java业务服务只需要将接收的数据转换为IRISObject类型进行处理即可。 如果是Java业务操作要使用Object Script适配器,则需要调用适配器的方法。调用适配器方法,可以使用Adapter属性的invoke方法调用适配器类的方法,语法是 Adapter.invoke("方法名", 方法参数),例如: // 使用Object Script的出站文件适配器(EnsLib.File.OutboundAdapter),并调用它的Exists方法检查是否存在文件a.txt Object obj = Adapter.invoke("Exists", "a.txt"); 虽然这里介绍的是使用Java PEX开发互操作产品组件,您也可以使用.net 和Python进行开发,而且任何语言开发的PEX组件都可以一起使用。通过PEX,可以充分利用已有的生态代码和组件快速开发互操作产品。
公告
Claire Zheng · 一月 30

【投票时间】InterSystems 编程大赛:FHIR和数字医疗互操作性

Hi开发者们, 投票时间到了!来为InterSystems 编程大赛:FHIR和数字医疗互操作性中的最佳应用程序投票: 🔥投票选出最佳应用程序🔥 如何投票?详细信息如下。 专家提名奖(Experts Nomination)- InterSystems 经验丰富的评审团将选出最佳应用程序。欢迎我们的专家: ⭐️ @Guillaume Rongier, Sales Engineer⭐️ @Sylvain Guilbaud, Sales Engineer⭐️ @Alexander Koblov, Senior Support Specialist⭐️ @Eduard Lebedyuk, Senior Cloud Engineer⭐️ @Steve Pisani, Senior Solution Architect⭐️ @Alexander.Woodhead, Senior Systems Developer⭐️ @Andreas Dieckow , Principal Product Manager⭐️ @Aya Heshmat, Product Manager⭐️ @Benjamin De Boe, Product Manager⭐️ @Bob Kuszewski, Product Manager⭐️ @Carmen Logue , Product Manager⭐️ @Luca Ravazzolo, Product Manager⭐️ @Raj Singh, Product Manager⭐️ @Patrick Jamieson, Product Manager⭐️ @Stefan Wittmann, Product Manager⭐️ @Thomas Dyar, Product Manager⭐️ @Daniel Franco, Senior Manager - Interoperability Product Management⭐️ @Timothy Leavitt, Development Manager⭐️ @Evgeny Shvarov, Senior Manager of Developer and Startup Programs⭐️ @Dean Andrews, Head of Developer Relations⭐️ @Jeff Fried, Director of Product Management 社区提名奖(Community Nomination) 对于每个用户,从以下两个类别中选择较高的分数: 满足条件 排名 第一名 第二名 第三名 在开发者社区上发布了文章并将应用程序上传到 Open Exchange (OEX) 9 6 3 在开发者社区上发布了至少 1 篇文章或已将 1 个应用上传到 OEX 6 4 2 对开发者社区做出任何有效贡献(发表评论/问题等) 3 2 1 等级 排名 第一名 第二名 第三名 Global Masters 的 VIP 级别 或 InterSystems 产品经理 15 10 5 Global Masters 的 Ambassador级别 12 8 4 Global Masters的Expert 级别或开发者社区版主 9 6 3 Global Masters的Specialist级别 6 4 2 Global Masters的Advocate级别,或 InterSystems员工 3 2 1 Blind vote! 每个应用获得的投票数将对所有人不可见。我们会每天在这个帖子(英文原贴)的评论区发布一次排行榜。 在竞赛页面上,项目按如下顺序排列:提交申请的时间越早,在列表中的排名就越靠前。 PS 不要忘记订阅(请订阅英文原贴),点击铃铛图标(如下所示),即可收到最新评论。 要参加投票,您需要: 登录 Open Exchange – 使用开发者社区账号即可。 在社区内进行有效贡献 ——回答问题、发帖、在Open Exchange发布新应用等等都可以,然后你的账号才可以参与投票。点击查看本帖 ,了解如何更好地成为有效的社区贡献者! 投票期间,如果你改了主意,可以随时将票改投给其他项目。 来支持您喜欢的应用吧! 注意:在投票期间,参赛者可以继续修复bug,提升应用,所以投票者不要错过最新发布的版本哦~
公告
Claire Zheng · 一月 28

InterSystems推出两款新的云原生智能数据服务,加速数据库和机器学习应用程序的开发

近日,InterSystems宣布 InterSystems IRIS® Cloud SQL 和 InterSystems IRIS® Cloud IntegratedML® 服务全面上市。 这些全面托管的云原生智能数据服务使开发人员能够轻松地在SQL环境中构建云原生数据库和机器学习(ML)应用程序。 通过 Cloud SQL和 Cloud IntegratedML,开发人员可以访问下一代关系数据库即服务(DBaaS),DBaaS快速且易于配置和使用。 嵌入式AutoML功能支持开发人员在全面托管的、弹性的云原生环境中,仅仅通过几条类似SQL的命令即可轻松开发并执行机器学习模型。 为关键任务型应用程序打造完整的数据管理组合 作为InterSystems Cloud智能数据服务组合的一部分,Cloud SQL和Cloud IntegratedML为应用开发人员提供了在 AWS上使用InterSystems成熟的企业级功能的机会,这些功能是自助式的、全面托管的产品,同时为 InterSystems IRIS®数据平台的全套功能提供了快速、无缝的接入渠道。 InterSystems IRIS 是为实施智能数据编织(smart data fabrics)的企业设计的下一代数据平台,可提供强大的数据库管理、集成和应用开发能力—— InterSystems IRIS将这些功能整合到单一产品中, 加速了数据赋能的价值实现,简化了整体系统架构,减少了维护工作和成本。 InterSystems数据平台全球主管Scott Gnau表示:“InterSystems IRIS的功能可以通过这些易于部署和使用的新服务得以展示,我们对此感到非常兴奋。 通过对AutoML的本地支持,我们为开发人员提供了构建全面、预测性和规范性应用程序的能力。” 通过InterSystems IRIS Cloud SQL实现全面托管,具备企业级的可靠性 Cloud SQL 令应用程序开发人员能够轻松地利用高级关系数据库功能,将其作为一种全面托管的、安全、可扩展、高性能、高可用性的云原生数据库即服务(DBaaS)。 Cloud SQL为SQL开发者带来以下优势: 极致的高性能,尤其体现在大规模、低延迟地采集和处理传入数据并对数据执行SQL查询方面 配置及使用快速、简便 可通过JDBC、ODBC、DB-API和ADO.NET驱动轻松连接客户端应用程序 自动安全、数据加密和备份 通过InterSystems IRIS Cloud IntegratedML 实现机器学习任务的自动化 作为InterSystems IRIS Cloud SQL客户的附加云托管服务,Cloud IntegratedML扩展了Cloud SQL的功能,SQL开发人员仅需通过几条类似SQL的命令即可快速构建、调整和执行机器学习模型,无需将数据移动或复制到不同的环境。 Cloud IntegratedML 的一个显著优势是无需将数据传输或复制到外部平台来构建 ML 模型,也无需将 ML 模型移动到不同的环境中执行。 Cloud IntegratedML为SQL开发者带来以下优势: 机器学习流程和资源密集型任务(如特征工程、模型开发和微调)的自动化 在Cloud SQL中无缝集成使用Cloud IntegratedML 开发和训练的模型,促进在事件和事务响应中的实时预测见解以及规范性行动 对于正在根据自身需求量身定制健壮、高性能数据库解决方案的SQL开发者来说,这套全面的智能数据服务令InterSystems Cloud智能数据服务组合成为SQL开发者的最佳选择。 新的Cloud SQL和Cloud IntegratedML服务可通过 InterSystems Developer Hub获取。
文章
Michael Lei · 一月 26

InterSystems 常见问题解答--日志文件长期保留而未被删除的原因

InterSystems 常见问题解答 如果系统24小时没有停止,旧的日志文件将根据“日志文件删除设置”在0:30删除。 导致日志文件保留的时间早于“日志文件删除设置”的一个可能原因是存在仍处于开放状态的事务。 在这种情况下,您将能够通过搜索执行事务的进程并完成事务来删除日志文件。 下面的示例检查是否存在未完成的事务,如果存在,则输出目标文件名和日志记录信息。 (示例可以从这里下载 *注意*如果要检查的日志文件较大或日志文件较多,则执行需要时间,因此请联系我们的支持中心。 Class ISJ.JournalUtility { ClassMethod GetOpenTransaction() As %Status { set status= $$$OK #dim ex As %Exception.AbstractException #dim rset As %ResultSet try { //current journal file write !, "Current journal file name:" , ##class ( %SYS.Journal.System ).GetCurrentFileName(),!! // Open transaction file // Get info about journals recorded in WIJ $$$ThrowOnError ( ##class ( %SYS.Journal.System ).GetImageJournalInfo(.filename,.jrnoffset,.jrnfilecount,.opentranoffset,.opentranfilecount)) if $get (opentranoffset)= "" { write !, "There are no open transactions" ,! return status } //If there is a differeence in file counts(jrnfilecount-opentranfilecount>0 ) // There is an open transaction in the old journal file, so please search for a target file name if jrnfilecount-opentranfilecount> 0 { set loopcnt=jrnfilecount-opentranfilecount for i= 1 : 1 :loopcnt { set currentfile=filename $$$ThrowOnError ( ##class ( %SYS.Journal.File ).GetPrev(currentfile,.filename)) } } write "〇〇 list of open target journal records 〇〇" ,! set rset= ##class ( %ResultSet ). %New ( "%SYS.Journal.Record:List" ) do rset. %Execute (filename,,,, $LB ( "Address" , "=" ,opentranoffset)) write !, "=== File Name : " ,filename, " ===" ,! write "Address : TimeStamp : ProcessID : RemoteSystemID : TypeName : Transaction" ,! while rset. %Next () { write rset. %Get ( "Address" ), " : " , rset. %Get ( "TimeStamp" ), " : " , rset. %Get ( "ProcessID" ), " : " , rset. %Get ( "RemoteSystemID" ), " : " , rset. %Get ( "TypeName" ), " : " , rset. %Get ( "InTransaction" ),! } } catch ex { set status=ex.AsStatus() } return status } } 执行示例如下。 USER> do ##class (ISJ.JournalUtility).GetOpenTransaction() Current journal file name:/usr/irissys/mgr/journal/ 20210330.002 〇〇 list of open target journal records 〇〇 === File Name : /usr/irissys/mgr/journal/ 20210330.001 === Address : TimeStamp : ProcessID : RemoteSystemID : TypeName : Transaction 1834156 : 2021 - 03 - 30 13 : 19 : 00 : 5194 : 1073741824 : BeginTrans : 1
文章
Claire Zheng · 一月 15

视频合集 | InterSystems IRIS医疗版互联互通套件产品用例

本文汇聚了InterSystems IRIS医疗版互联互通套件产品用例视频,共19个视频,欢迎收藏、观看!您也可以通过B站视频合集观看全部内容。 互联互通套件产品用例:互联互通文档转FHIR 互联互通套件产品用例:vscode连接HCC容器版 互联互通套件产品用例:互联互通套件Docker版安装步骤 互联互通套件产品用例:糖尿病预测AI应用 互联互通套件产品用例:HCC3.0 发布订阅,服务 互联互通套件产品用例:Rest API介绍 互联互通套件产品用例:共享文档:数据校验 - SQL前校验 互联互通套件产品用例:IRIS Studio连接HCC容器版 Smart On FHIR用例:心血管疾病风险预测 Smart On FHIR用例:儿童生长发育曲线 互联互通套件产品用例-服务:患者注册 互联互通套件产品用例-共享文档:文档生成 + 文档查阅 互联互通套件产品用例-共享文档:数据校验 - SQL 互联互通套件产品用例-共享文档:数据导入 互联互通套件产品用例-共享文档:数据校验 -文档校验 互联互通套件产品用例-共享文档:值集更新 互联互通套件产品用例:平台性能监控 互联互通套件产品用例:批量生成电子病历共享文档 互联互通套件产品用例:国家三级公立医院绩效考核指标
文章
Claire Zheng · 一月 15

InterSystems第三次入围Gartner云数据库管理系统魔力象限,2023年荣膺“挑战者”称号

Gartner魔力象限是业内知名的分析报告,针对特定市场进行严谨、基于事实的研究后发布的魔力象限报告,可为用户提供全面视图,以便其了解在高速增长、差异化明显的市场中供应商的相对位置。在魔力象限中,供应商被定位在四个象限中:领导者(Leader)、挑战者(Challenger)、远见者(Visionary)和利基玩家(Niche Player)。 2023年年底,在 Gartner 2023年最新发布的“云数据库管理系统(Cloud DBMS)魔力象限”中,InterSystems再次荣膺“挑战者”(Challenger)称号,这是InterSystems第三次入围这一报告并得到认可(2022年“远见者”,2021年“挑战者”)。 Gartner此次评估面向包括InterSystems在内的19家云数据库管理系统供应商进行。我们相信,Gartner魔力象限“挑战者”这一定位,证明了InterSystems有能力挑战现状、推动创新,为市场提供独特的解决方案。 InterSystems IRIS数据平台提供的结缔组织(connective tissue)可将不同来源的分散数据转换为单一、完整的视图,从而在医疗保健、金融服务和供应链等关键市场中为具有关键数据需求的客户提供更好的结果。InterSystems提供了一种独特的智能数据编织方式,可提供高性能多模型和多工作负载数据库管理、智能数据服务、互操作性和分析能力。 IInterSystems数据平台主管Scott Gnau表示:“‘挑战者’这一称号证实了我们专注于创新并为客户提供价值的承诺。InterSystems是此次Gartner魔力象限中唯一的‘挑战者’,这足以说明我们不断超越,在云数据库管理方面取得的成功,InterSystems成功帮助企业在云中实现了数据集成、处理和分析。” 查看《2023云数据库管理系统魔力象限》免费副本:点击链接。 官方报道链接:Gartner® 推出2023年云数据库管理系统魔力象限™,InterSystems荣膺“挑战者”称号 ============ Gartner 免责声明:Gartner 不支持其研究出版物中描述过的任何供应商、产品或服务,也不建议技术用户只选择具有高评级或其他荣誉的供应商。Gartner研究出版物由Gartner研究机构的意见构成,不应被视为事实陈述。Gartner 不为本研究提供任何明示或暗示的担保,包括任何适销性或适用于特定用途的担保。 GARTNER和魔力象限(MAGIC QUADRANT)是 Gartner, Inc. 和/或其附属公司在美国境内和境外的注册商标,已获准用于此处。保留所有权利。
公告
Michael Lei · 一月 10

全球创新:2023 年欧洲医疗健康黑克松Hackathon InterSystems FHIR 挑战赛获胜数字健康项目

嗨,大家好, 我们想重点介绍 2023 年布拉格欧洲欧洲医疗健康黑克松Hackathon期间创建的一些杰出项目。IKEM 和阿斯利康向参与者提出了九个现实世界的医疗保健挑战。 InterSystems 向参与者介绍了使用 FHIR 存储库并通过在 AWS 上提供 FHIR 云服务来在其解决方案中执行 FHIR 可用性的机会。 来认识一下我们挑战的获胜者: 第一名Čarodějové (PathoSync) “PathoSync 软件是复杂病理学家平台的坚实基础。通过使用自定义映射,任何实验室都可以将其数据投影到 FHIR7 标准,该标准很快将在全球范围内强制执行。这使得数字化过程更加顺利。与 InterSystems 的连接确保了质量并实现了很多医疗保健功能。此外,使用位于欧洲的FHIR服务器严格遵循GDPR规范,因此软件的使用遵循欧洲标准。 项目详情|视频演示| GitHub链接 1链接 2 第二名ICU SPYEYES(生命视力Vital Vision) “ICU 需要一个系统来自动记录视频循环,捕捉患者和人员移动等关键活动。该系统将允许人进行回顾性注释、预先注释和识别人员,并可选择模糊患者面部。它的目的是收集数据以用于开发未来医院中的患者监控算法。 我们为 ICU 开发了一个系统,该系统利用运动检测、LLM 和标准 CV 技术进行视频分析。它构建了一个带注释的视频数据库,对于专注于患者监护的训练算法至关重要。我们的解决方案生成通过 FHIR 共享的结构化报告和视频,确保高效的数据处理。通过开源平台 CVAT 进行手动审核,质量得到提高,优化了我们用于监测患者康复情况的实时警报系统。” 项目详情|视频演示| GitHub 第三名 VariantCall (PathoX) “端到端解决方案 PathoX 是一个可轻松进行数据摄取、特征提取和映射的平台,可增强病理学家的工作流程。导入器工作流程支持列映射并通知用户缺失的信息。我们使用 FHIR 来保证未来的互操作性和合规性与未来的立法。病理学家还可以像平常的工作流程一样突出显示数据并留下评论,并查看所有文件的分析。” 项目详情|视频演示| GitHub 大家都很棒,恭喜!希望能对大家有所启发,我们也期待看到您的项目如何发展成为创新且有影响力的初创企业!
公告
Claire Zheng · 一月 10

InterSystems 编程大赛:FHIR和数字医疗互操作性

Hi 开发者们, 我们非常高兴地邀请大家参加新的 InterSystems 在线编程竞赛,此次编程大赛关注于“FHIR与数字医疗互操作性”这个主题。 🏆 InterSystems编程大赛:FHIR 与数字医疗互操作性🏆 时间: 2024年1月15日至2月5日(美国东部时间) 奖金池: 14,000 美元 话题 欢迎您开发互操作性 FHIR 解决方案或医疗互操作性解决方案,您也可以开发辅助类解决方案,以帮助其他用户使用 InterSystems IRIS for Health、Health Connect 或 FHIR 服务器开发或/和维护互操作性解决方案。 一般要求: 应用程序或库必须功能齐全。该应用程序不应该是另一种语言中已有库的导入或直接接口(C++ 除外,您确实需要做大量工作来为 IRIS 创建接口)。不允许对现有应用程序或库进行复制粘贴。 有效应用程序:100%全新的Open Exchange Apps或已有的应用程序(但有显著提升)。所有参赛者/团队提交的应用程序只有经过我们团队的审核之后才会被批准参赛。 该应用程序应在 IRIS Community Edition 或 IRIS for Health Community Edition 上运行。两者都可作为host (Mac, Windows)版从Evaluation Site下载,或者可以按从InterSystems Container Registry或Community Container中提取的容器形式使用: intersystemsdc/iris-community:latest 或 intersystemsdc/irishealth-community:latest 。 该应用程序需开源并在GitHub上发布。 应用程序的README文件应为英文,包含安装步骤,并包含视频demo或/和应用程序如何运行的描述。 一名开发者只允许提交 3 份作品。 注意。我们的专家将根据申请的复杂性和实用性标准对是否批准参加比赛拥有最终决定权。他们的决定是最终决定,不得上诉。 奖品 1. 专家提名奖(Experts Nomination)——获奖者由我们特别挑选的专家团选出: 🥇第一名 - 5,000 美元 🥈第二名 - 3,000 美元 🥉第三名 - 1,500 美元 🏅第四名 - 750 美元 🏅第五名 - 500 美元 🌟第 六名~第十名 - 100 美元 2. 社区提名奖(Community Nomination)- 获得总票数最多的应用程序: 🥇第一名 - 1,000 美元 🥈第二名 - 750 美元 🥉第三名 - 500 美元 🏅第四名 - 300 美元 🏅第五名 - 200 美元 如果几位参与者获得相同数量的选票,他们都将被视为获胜者,奖金由获胜者分享。 谁可以参加? 任何开发者社区的成员均可参加,InterSystems内部员工除外(InterSystems contractor员工可以参加)。 ✅ 还没有账号?点击此处创建一个账号! 👥开发人员可以组队创建协作应用程序。一个团队允许 2 到 5 名开发人员。 请注意,要在您的README文件中标注您的团队成员——社区用户profile。 重要截止日期: 🛠 应用程序开发和注册阶段: 2024 年 1 月 15 日(美国东部时间 00:00):比赛开始。 2024 年 1 月28 日(美国东部时间 23:59):提交截止日期。 ✅ 投票期限: 2024 年 1 月 29 日(美国东部时间 00:00):投票开始。 2024 年 2 月 5 日(美国东部时间 23:59):投票结束。 注意:在整个参赛期间(开发与投票期间),开发者可持续编辑、提升其应 资源助力: ✓ 应用示例(英文): FHIR 服务器模板 iris-healthtoolkit-模板 互操作性-嵌入式-python FHIR HL7 SQL 演示FHIR DropBox HL7 和 SMS 互操作性演示 IrisHealth 演示 单元测试 DTL HL7 医疗保健 HL7 XML FHIR 互操作性示例 FHIR-Orga-dt FHIR 伪匿名化代理 FHIR-客户端-java FHIR-客户端-.net FHIR-客户端-python Open Exchange 上的 FHIR 相关应用程序 Open Exchange 上的 HL7 应用程序 ✓ 在线课程(英文): 交互式数字医疗互操作性基础- 使用 InterSystems IRIS for Health 构建数字医疗互操作性产品的入门课程 FHIR 集成 HL7 集成 了解软件开发人员的FHIR 探索 FHIR 资源 API 使用 InterSystems IRIS for Health 减少再入院率 将设备连接到 InterSystems IRIS for Health 监测婴儿的血氧饱和度 FHIR 集成快速入门 ✓ 视频(英文): 6 个 FHIR 快速问题 SMART on FHIR:基础知识 使用 FHIR 进行开发 - REST API InterSystems IRIS for Health 中的 FHIR FHIR API 管理 在 IRIS for Health 中搜索 FHIR 资源 ✓ IRIS 初学者(英文): 使用 InterSystems IRIS 构建服务器端应用程序 初学者的学习路径 ✓ 对于ObjectScript 包管理器 (IPM)的初学者(英文): 如何使用 InterSystems IRIS 的 REST 应用程序构建、测试和发布 IPM 包 采用 InterSystems IRIS 和 IPM 的封装优先开发方法 ✓ 如何将您的APP提交给大赛: 首先您需要发布应用:如何在 Open Exchange 上发布应用程序 然后,您可以提交申请:如何提交比赛申请 需要帮忙? 加入 InterSystems Discord 服务器上的竞赛频道或在本文评论中留言告诉我们。 期待您的精彩项目——加入我们的编码马拉松吧! ❗️参加本次比赛即表示您同意此处列出的比赛条款。请在继续之前仔细阅读它们。 ❗️ 中文资源参考-视频合集 | InterSystems IRIS医疗版互联互通套件产品用例
文章
姚 鑫 · 一月 5

第十六章 调用Callout Library函数

# 第十六章 调用Callout Library函数 `Callout` 库是一个共享库(`DLL` 或 `SO` 文件),其中包含 `$ZF Callout` 接口的挂钩,允许各种 $ZF 函数在运行时加载它并调用其函数。 `$ZF Callout` 接口提供了四种不同的接口,可用于在运行时加载 `Callout` 库并从该库调用函数。这些接口的主要区别在于如何识别库并将其加载到内存中: - 使用 `$ZF()` 访问 `iriszf` 标注库描述了如何使用名为 `iriszf` 的特殊共享库。当该库可用时,可以通过 `$ZF("funcname",args)` 形式的调用来访问其函数,而无需事先加载该库或指定库名称。 - 使用 `$ZF(-3)` 进行简单库函数调用描述了如何通过指定库文件路径和函数名来加载库并调用函数。它使用简单,但虚拟内存中一次只能有一个库。与其他接口不同,它在调用库函数之前不需要任何初始化。 - 使用 `$ZF(-5)` 通过系统 `ID` 访问库描述了一种可用于一次有效维护和访问多个库的接口。可以同时加载和使用多个库,每个库所需的处理开销比 `$ZF(-3)` 少得多。内存中的库由加载库时生成的系统定义的 `ID` 来标识。 - 使用 `$ZF(-6)` 按用户索引访问库描述了处理大量标注库的最有效接口。该接口通过`Global`定义的索引表提供对库的访问。该索引可供 `IRIS` 实例中的所有进程使用,并且多个库可以同时位于内存中。每个索引库都被赋予一个唯一的、用户定义的索引号,并且可以在运行时定义和修改索引表。当库文件被重命名或重新定位时,与给定库 `ID` 关联的文件名可以更改,并且此更改对于按索引号加载库的应用程序来说是透明的。 # 使用 `$ZF()` 访问 `iriszf` 标注库 当名为 `iriszf` 的 `Callout` 库在实例的 `/bin` 目录中可用时,可以通过仅指定函数名称和参数的 `$ZF` 调用来调用其函数(例如,`$ZF("functionName",arg1, arg2))`.。无需事先加载库即可调用 `iriszf` 函数,并且实例中的所有进程都可以使用 `iriszf` 函数。 自定义 `iriszf` 库是通过创建标准 `Callout` 库、将其移动到实例的 `/bin` 目录并将其重命名为 `iriszf`(具体为 `iriszf.dll` 或 `iriszf.so`,具体取决于平台)来定义的。 以下是编译 `simplecallout.c` 示例(请参阅“创建 `Callout` 库”)并将其设置为 `iriszf` 库的步骤。这些示例假设实例在 `Linux` 下运行,安装在名为 `/intersystems/iris` 的目录中,但所有平台上的过程基本相同: 1. 编写并保存 `simplecallout.c`: ```java #define ZF_DLL #include "iris-cdzf.h" int AddTwoIntegers(int a, int b, int *outsum) { *outsum = a+b; /* set value to be returned by $ZF function call */ return IRIS_SUCCESS; /* set the exit status code */ } ZFBEGIN ZFENTRY("AddInt","iiP",AddTwoIntegers) ZFEND ``` 2. 生成`Callout`库文件(`simplecallout.so`): ```java gcc -c -fPIC simplecallout.c -I /intersystems/iris/dev/iris-callin/include/ -o simplecallout.o gcc simplecallout.o -shared -o simplecallout.so ``` 3. 从 `IRIS` 终端会话中使用 `$ZF(-3)` 测试库: ```java USER>write $ZF(-3,"/mytest/simplecallout.so","AddInt",1,4) 5 ``` 4. 现在安装该库以与 `$ZF()` 一起使用。将 `simplecallout.so` 复制到 `/bin`中,并将其重命名为 `iriszf.so`: ```java cp simplecallout.so /intersystems/iris/bin/iriszf.so ``` 5. 确认可以从 `IRIS` 会话中使用 `$ZF()` 调用代码: ```java USER>write $zf("AddInt",1,4) 5 ``` `iriszf` 库在首次使用时加载一次,并且永远不会卸载。它完全独立于本章前面描述的其他 `$ZF` 加载和卸载操作。 注意:静态链接库 `$ZF Callout Interface` 的早期版本允许将代码静态链接到 `InterSystems` 内核并使用 `$ZF()` 进行调用。不再支持静态链接,但 `irisz` 库提供相同的功能,无需重新链接内核。
文章
姚 鑫 · 十二月 31, 2023

第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串

# 第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串 # 使用 `J` 链接类型传递标准计数字符串 `iris-callin.h` 头文件定义了计数字符串结构 `IRIS_EXSTR`,表示标准 `IRIS` 字符串。此结构包含一个字符元素数组(`8` 位、`16` 位 `Unicode` 或 `32` 位 `wchar t`)和一个指定数组中元素数量的 `int` 值(最多字符串长度限制): ```java typedef struct { unsigned int len; /* length of string */ union { Callin_char_t *ch; /* text of the 8-bit string */ unsigned short *wch; /* text of the 16-bit string */ wchar_t *lch; /* text of the 32-bit string */ /* OR unsigned short *lch if 32-bit characters are not enabled */ } str; } IRIS_EXSTR, *IRIS_EXSTRP; ``` C Datatype| Input |In/Out |Notes ---|---|---|--- IRIS_EXSTR| 1j or j |1J or J| 8 位国家字符的标准字符串 IRIS_EXSTR |2j or n| 2J or N|16 位 Unicode 字符的标准字符串 IRIS_EXSTR| 4j |4J |32 位字符的标准字符串 wchar_t 字符 `IRIS_EXSTR` 数据结构由 `Callin API`(低级 `InterSystems` 函数调用库)中的函数进行操作。有关详细信息,请参阅使用 `Callin API` 中的“`Callin` 函数参考”。尽管名称相似,`Callin API` 和 `$ZF`标注接口是完全独立的产品)。 以下函数用于创建和销毁 `IRIS_EXSTR` 实例: - `IrisExStrNew[W][H`] — 为字符串分配请求的存储量,并使用长度和指向该结构的值字段的指针填充 `IRIS_EXSTR` 结构。 - `IrisExStrKill` — 释放与 `IRIS_EXSTR` 字符串关联的存储。 这是一个 `Callout` 库,它使用所有三种链接类型来返回数字字符串: ### 使用 `J` 连接传递字符串 以下三个函数均生成一个随机整数,将其转换为最多包含 `6` 位数字的数字字符串,并使用 `J` 链接返回字符串 。 ```java #define ZF_DLL // Required when creating a Callout library. #include #include #include #include int get_sample_L(IRIS_EXSTRP retval) { // 8-bit characters Callin_char_t numstr[6]; size_t len = 0; sprintf(numstr,"%d",(rand()%1000000)); len = strlen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.ch,numstr,len); // copy to retval->str.ch return ZF_SUCCESS; } int get_sample_LW(IRIS_EXSTRP retval) { // 16-bit characters unsigned short numstr[6]; size_t len = 0; swprintf(numstr,6,L"%d",(rand()%1000000)); len = wcslen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.wch,numstr,(len*sizeof(unsigned short))); // copy to retval->str.wch return ZF_SUCCESS; } int get_sample_LH(IRIS_EXSTRP retval) { // 32-bit characters wchar_t numstr[6]; size_t len = 0; swprintf(numstr,6,L"%d",(rand()%1000000)); len = wcslen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.lch,numstr,(len*sizeof(wchar_t))); // copy to retval->str.lch return ZF_SUCCESS; } ZFBEGIN ZFENTRY("GetSampleL","1J",get_sample_L) ZFENTRY("GetSampleLW","2J",get_sample_LW) ZFENTRY("GetSampleLH","4J",get_sample_LH) ZFEND ``` 注意:始终终止 `IRIS_EXSTRP` 输入参数 在前面的示例中,始终调用 `IRISEXSTRKILL(retval)` 以从内存中删除输入参数。即使参数不用于输出,也应该始终这样做。如果不这样做可能会导致内存泄漏。
文章
Lilian Huang · 十二月 29, 2023

使用 FHIR 适配器在传统系统上提供 FHIR 服务 - 阅读资源

我们继续推出有关可供 HealthShare HealthConnect 和 InterSystems IRIS 用户使用的 FHIR 适配器工具的系列文章。 在前几篇文章中,我们介绍了小型应用程序,并在此基础上建立了我们的工作,并展示了安装 FHIR 适配器后在 IRIS 实例中部署的架构。在今天的文章中,我们将看到一个示例,说明如何执行最常见的 CRUD(创建 - 读取 - 更新 - 删除)操作之一,即读取操作,我们将通过恢复资源来完成此操作。 什么是资源? FHIR 中的一个资源对应一种相关的临床信息,这种信息可以是病人(Patient)、对实验室的请求(ServiceRequest)或诊断(Condition)等。每种资源都定义了组成它的数据类型,以及对数据的限制和与其他类型资源的关系。每个资源都允许对其包含的信息进行扩展,从而满足 FHIR 80% 以外的需求(满足 80% 以上用户的需求)。 在本文的示例中,我们将使用最常见的资源 "Patient"。让我们来看看它的定义: { "resourceType" : "Patient" , // from Resource: id, meta, implicitRules, and language // from DomainResource: text, contained, extension, and modifierExtension "identifier" : [{ Identifier }], // An identifier for this patient "active" : <boolean>, // Whether this patient's record is in active use "name" : [{ HumanName }], // A name associated with the patient "telecom" : [{ ContactPoint }], // A contact detail for the individual "gender" : "<code>" , // male | female | other | unknown "birthDate" : "<date>" , // The date of birth for the individual // deceased[x]: Indicates if the individual is deceased or not. One of these 2 : "deceasedBoolean" : <boolean>, "deceasedDateTime" : "<dateTime>" , "address" : [{ Address }], // An address for the individual "maritalStatus" : { CodeableConcept }, // Marital (civil) status of a patient // multipleBirth[x]: Whether patient is part of a multiple birth. One of these 2 : "multipleBirthBoolean" : <boolean>, "multipleBirthInteger" : <integer>, "photo" : [{ Attachment }], // Image of the patient "contact" : [{ // A contact party (eg guardian, partner, friend) for the patient "relationship" : [{ CodeableConcept }], // The kind of relationship "name" : { HumanName }, // IA name associated with the contact person "telecom" : [{ ContactPoint }], // IA contact detail for the person "address" : { Address }, // I Address for the contact person "gender" : "<code>" , // male | female | other | unknown "organization" : { Reference(Organization) }, // I Organization that is associated with the contact "period" : { Period } // The period during which this contact person or organization is valid to be contacted relating to this patient }], "communication" : [{ // A language which may be used to communicate with the patient about his or her health "language" : { CodeableConcept }, // R! The language which can be used to communicate with the patient about his or her health "preferred" : <boolean> // Language preference indicator }], "generalPractitioner" : [{ Reference(Organization|Practitioner| PractitionerRole) }], // Patient's nominated primary care provider "managingOrganization" : { Reference(Organization) }, // Organization that is the custodian of the patient record "link" : [{ // Link to a Patient or RelatedPerson resource that concerns the same actual individual "other" : { Reference(Patient|RelatedPerson) }, // R! The other patient or related person resource that the link refers to "type" : "<code>" // R! replaced-by | replaces | refer | seealso }] } 正如您所看到的,它几乎涵盖了患者的所有管理信息需求。 从我们的 HIS 中恢复患者信息 如果您还记得之前的文章中我们部署了一个模拟 HIS 系统数据库的 PostgreSQL 数据库,那么让我们看一下我们特定 HIS 中的示例表。 虽然数量不多,但对于我们的例子来说已经足够了。让我们更详细地看看我们的患者表。 这里我们有 3 个示例患者,您可以看到每个患者都有一个唯一的标识符 ( ID ) 以及一系列与卫生组织相关的管理数据。我们的首要目标是为我们的一位患者获取 FHIR 资源。 患者咨询 我们如何从我们的服务器请求患者数据?根据 FHIR 制定的实现规范,我们必须通过 REST 对包含我们服务器地址、资源名称和标识符的 URL 执行 GET。我们必须调用: http://SERVER_PATH/Patient/{id} 在我们的示例中,我们将搜索 Juan López Hurtado,其 id = 1,因此我们必须调用以下 URL: http://localhost:52774/Adapter/r4/Patient/1 为了进行测试,我们将使用 Postman 作为客户端。让我们看看服务器的响应是什么: { "resourceType" : "Patient" , "address" : [ { "city" : "TERUEL" , "line" : [ "CALLE SUSPIROS 39 2ºA" ], "postalCode" : "98345" } ], "birthDate" : "1966-11-23" , "gender" : "M" , "id" : "1" , "identifier" : [ { "type" : { "text" : "ID" }, "value" : "1" }, { "type" : { "text" : "NHC" }, "value" : "588392" }, { "type" : { "text" : "DNI" }, "value" : "12345678X" } ], "name" : [ { "family" : "LÓPEZ HURTADO" , "given" : [ "JUAN" ] } ], "telecom" : [ { "system" : "phone" , "value" : "844324239" }, { "system" : "email" , "value" : "juanitomaravilla@terra.es" } ] } 现在让我们分析一下我们的请求在生产中所采取的路径: 这里我们有路径: 请求到达我们的 BS InteropService。 将请求转发到我们已配置为 BS 目的地的 BP,在该 BP 中将恢复所接收呼叫的患者标识符。 从我们的 BO FromAdapterToHIS 查询到我们的 HIS 数据库。 将患者数据转发到我们的 BP,并将其转换为 FHIR 患者资源。 将响应转发给BS。 让我们看一下我们在 BP ProcessFHIRBP中收到的消息类型: 让我们看一下三个属性,它们对于识别客户端请求的操作类型至关重要: Request.RequestMethod:它告诉我们要执行什么类型的操作。在此示例中,搜索病人将采用 GET 方式。 Request.RequestPath:该属性包含到达服务器的请求路径,该属性将指示我们要处理的资源,在本例中,它将包括恢复资源的特定标识符。 Quick.StreamId: FHIR 适配器会将收到的每条 FHIR 消息转换为流,并为其分配一个标识符,该标识符将保存在此属性中。在本例中,我们不需要它,因为我们执行的是 GET,并没有发送任何 FHIR 对象。 让我们深入分析负责处理的 GLP,继续我们的消息之旅。 流程FHIRBP: 我们在生产中实施了 BPL,它将管理我们从业务服务收到的 FHIR 消息传递。让我们看看它是如何实现的: 让我们看看每个步骤中将执行的操作: 管理 FHIR 对象: 我们将调用负责连接到 HIS 数据库并负责数据库查询的 BO FromAdapterToHIS。 Method ManageFHIR(requestData As HS.FHIRServer.Interop.Request, response As Adapter.Message.FHIRResponse) As %Status { set sc = $$$OK set response = ##class (Adapter.Message.FHIRResponse). %New () if (requestData.Request.RequestPath = "Bundle" ) { If requestData.QuickStreamId '= "" { Set quickStreamIn = ##class (HS.SDA3.QuickStream). %OpenId (requestData.QuickStreamId,, .tSC) set dynamicBundle = ##class ( %DynamicAbstractObject ). %FromJSON (quickStreamIn) set sc = ..GetBundle (dynamicBundle, .response) } } elseif (requestData.Request.RequestPath [ "Patient" ) { if (requestData.Request.RequestMethod = "POST" ) { If requestData.QuickStreamId '= "" { Set quickStreamIn = ##class (HS.SDA3.QuickStream). %OpenId (requestData.QuickStreamId,, .tSC) set dynamicPatient = ##class ( %DynamicAbstractObject ). %FromJSON (quickStreamIn) set sc = ..InsertPatient (dynamicPatient, .response) } } elseif (requestData.Request.RequestMethod = "GET" ) { set patientId = $Piece (requestData.Request.RequestPath, "/" , 2 ) set sc = ..GetPatient (patientId, .response) } } Return sc } 我们的 BO 将检查收到的HS.FHIRServer.Interop.Request类型的消息,在本例中,通过设置 GET 并在与患者资源对应的路径中指示将调用GetPatient方法,我们将在下面看到: Method GetPatient(patientId As %String , Output patient As Adapter.Message.FHIRResponse) As %Status { Set tSC = $$$OK set sql= "SELECT id, name, lastname, phone, address, city, email, nhc, postal_code, birth_date, dni, gender FROM his.patient WHERE id = ?" //perform the Select set tSC = ..Adapter .ExecuteQuery(.resultSet, sql, patientId) If resultSet.Next() { set personResult = { "id" :(resultSet.GetData( 1 )), "name" : (resultSet.GetData( 2 )), "lastname" : (resultSet.GetData( 3 )), "phone" : (resultSet.GetData( 4 )), "address" : (resultSet.GetData( 5 )), "city" : (resultSet.GetData( 6 )), "email" : (resultSet.GetData( 7 )), "nhc" : (resultSet.GetData( 8 )), "postalCode" : (resultSet.GetData( 9 )), "birthDate" : (resultSet.GetData( 10 )), "dni" : (resultSet.GetData( 11 )), "gender" : (resultSet.GetData( 12 )), "type" : ( "Patient" )} } else { set personResult = {} } //create the response message do patient.Resource.Insert(personResult. %ToJSON ()) Return tSC } 正如您所看到的,此方法仅在我们的 HIS 数据库上启动查询并恢复所有患者信息,然后生成一个 DynamicObject,随后将其转换为 String 并存储在Adapter.Message.FHIRResponse类型的变量中。我们已将 Resource 属性定义为字符串列表,以便能够稍后在跟踪中显示响应。您可以直接将其定义为 DynamicObjects,从而节省后续转换。 检查是否捆绑: 根据 BO 的响应,我们检查它是否是 Bundle 类型(我们将在以后的文章中解释)或者它是否只是一个 Resource。 创建动态对象: 我们将 BO 响应转换为 DynamicObject 并将其分配给临时上下文变量 (context.temporalDO)。用于转换的函数如下: ##class ( %DynamicAbstractObject ). %FromJSON (context.FHIRObject.Resource.GetAt( 1 )) FHIR 变换: 使用 DynamicObject 类型的临时变量,我们将其转换为HS.FHIR.DTL.vR4.Model.Resource.Patient类的对象。如果我们想寻找其他类型的资源,我们必须为每种类型定义特定的转换。让我们看看我们的转变: 这种转换使我们能够拥有 BS InteropService 可以解释的对象。我们将结果存储在变量context.PatientResponse中。 将资源分配给 Stream : 我们将FHIR变换中获得的变量context.PatientResponse转换为Stream。 转换为 QuickStream: 我们将必须返回给客户端的所有数据分配给响应变量: set qs= ##class (HS.SDA3.QuickStream). %New () set response.QuickStreamId = qs. %Id () set copyStatus = qs.CopyFrom(context.JSONPayloadStream) set response.Response.ResponseFormatCode= "JSON" set response.Response.Status= 200 set response.ContentType= "application/fhir+json" set response.CharSet = "utf8" 在这种情况下,我们总是返回 200 响应。在生产环境中,我们应该检查是否已正确恢复搜索到的资源,如果没有,请将响应状态从 200 修改为对应“未找到”的 404。正如您在此代码片段中看到的,对象HS.FHIR.DTL.vR4.Model.Resource.Patient转换为 Stream 并存储为HS.SDA3.QuickStream ,将所述对象的标识符添加到QuickStreamID属性,随后我们的 InteropService 服务将以 JSON 形式正确返回结果。 结论: 让我们总结一下我们所做的事情: 我们发送了一个 GET 类型的请求,以搜索具有定义 ID 的患者资源。 BS InteropService已将请求转发至配置的BP。 BP 调用了负责与 HIS 数据库交互的 BO。 已配置的 BO 已从 HIS 数据库检索患者数据。 业务处理程序将结果转换为默认互操作服务创建的 BS 可理解的对象。 BS已收到响应并将其转发给客户端。 如您所见,操作相对简单,如果我们想在服务器中添加更多类型的资源,只需在 BO 中添加对数据库中与要恢复的新资源相对应的表的查询,并在 BP 中将 BO 的结果转换为与之相对应的 HS.FHIR.DTL.vR4.Model.Resource.* 类型的对象。 在下一篇文章中,我们将回顾如何将患者类型的新 FHIR 资源添加到我们的 HIS 数据库中。 感谢大家的关注!