搜索​​​​

清除过滤器
文章
Kelly Huang · 三月 28, 2023

安装本地 FHIR 服务器的最快最简单的方法!

嗨大家好! 最近我需要使用 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 服务器真的很容易。 原文来自于 @ Evgeny Shvarov
公告
Michael Lei · 三月 22, 2023

Caelestinus 2023 孵化器活动正式启动!

大家好! 第二次数字健康互操作与FHIR创业孵化器——Caelestinus,今日启动! 今天,21 支选定的队伍将在 Caelestinus 开始为期八个月的旅程。在孵化期间,团队将数字健康互操作性引入到他们的互联医疗服务或医疗设备创新中,并添加对 FHIR、HL7、DICOM、CDA、X12 和其他数字健康标准的支持,并使用InterSystems IRIS for Health和FHIR Server进行转型在经验丰富的 InterSystems 团队的帮助下。 我很高兴邀请大家观看 Caelestinus 2023 启动活动直播,您可以在其中了解哪些团队被选中以及他们的创新想法。 请从欧洲中部时间下午 3 点开始通过www.caelestinus.tech观看流媒体。 很高兴在在线上与您相见。 祝 Caelestini 初创公司好运!
文章
Jingwei Wang · 五月 4, 2022

IntegratedML 演练

InterSystems IRIS IntegratedML功能用于使用AutoML技术获得机器学习的预测结果和概率。AutoML是一种机器学习技术,用于选择更好的机器学习算法/模型基于已有数据(用于训练AutoML模型的数据)来预测状态、数字和结果。你不需要一个数据科学家,因为AutoML会测试最常见的机器学习算法,并根据分析的数据特征选择更好的算法给你。在这篇文章中可以看到更多管乐IntegratedML的信息。 InterSystems IRIS有一个内置的AutoML引擎,但也允许你使用H2O和DataRobot。在这篇文章中,我将向你展示使用InterSystems AutoML引擎的每个步骤。 第1步 - 下载样例应用程序做练习 1. 转到 https://openexchange.intersystems.com/package/Health-Dataset 2. Clone/git 将 Repo拉到任何本地目录中 $ git clone https://github.com/yurimarx/automl-heart.git 3. 在同一个目录中打开一个Docker终端并运行 $ docker-compose build 4. 运行IRIS容器 $ docker-compose up -d 第2步--了解业务场景和可用数据 业务场景是利用过去的数据预测心脏疾病,数据如下: SELECT age, bp, chestPainType, cholesterol, ekgResults, exerciseAngina, fbsOver120, heartDisease, maxHr, numberOfVesselsFluro, sex, slopeOfSt, stDepression, thallium FROM dc_data_health.HeartDisease 心脏病表(heartDisease)的数据字典来源(https://data.world/informatics-edu/heart-disease-prediction/workspace/data-dictionary): Column name Type Description age Integer In years sex Integer (1 = male; 0 = female) chestPainType Integer Value 1: typical angina -- Value 2: atypical angina -- Value 3: non-anginal pain -- Value 4: asymptomatic bp Integer Resting blood pressure (in mm Hg on admission to the hospital) cholesterol Integer Serum cholestoral in mg/dl fbsOver120 Integer (fasting blood sugar > 120 mg/dl) (1 = true; 0 = false) ekgResults Integer Resting electrocardiographic results -- Value 0: normal -- Value 1: having ST-T wave abnormality (T wave inversions and/or ST elevation or depression of > 0.05 mV) -- Value 2: showing probable or definite left ventricular hypertrophy maxHr Integer Maximum heart rate achieved exerciseAngina Integer Exercise induced angina (1 = yes; 0 = no) stDepression Double ST depression induced by exercise relative to rest slopeOfSt Integer The slope of the peak exercise ST segment -- Value 1: upsloping -- Value 2: flat -- Value 3: downsloping numberOfVesselsFluro Integer Number of major vessels (0-3) colored by flourosopy thallium Integer 3 = normal; 6 = fixed defect; 7 = reversable defect heartDisease String Value 0: < 50% diameter narrowing -- Value 1: > 50% diameter narrowing 心脏病(heartDisease)是我们需要预测的属性 第3步--准备好训练数据 HeartDisease表有270行。我们将得到250行来训练我们的预测模型。为了做到这一点,我们需要创建VIEW ,通过 管理门户>系统资源管理器>SQL。 CREATE VIEW automl.HeartDiseaseTrainData AS SELECT * FROM dc_data_health.HeartDisease WHERE ID < 251 第4步 - 准备验证数据 我们将得到20行来验证预测的结果。 为了做到这一点,我们需要创建VIEW ,通过 管理门户>系统资源管理器>SQL。 CREATE VIEW automl.HeartDiseaseTestData AS SELECT * FROM dc_data_health.HeartDisease WHERE ID > 250 第5步--创建AutoML模型来预测心脏疾病 IntegratedML允许创建一个AutoML模型来做预测和概率(详见https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GIML_BASICS)。要做到这一点,需要创建以下模型,通过 管理门户>系统资源管理器>SQL。 CREATE MODEL HeartDiseaseModel PREDICTING (heartDisease) FROM automl.HeartDiseaseTrainData 这个模型将从automl.HeartDiseaseTrainData view中获得训练数据(学习)。 第6步 - 执行训练 执行训练,了做到这一点,执行下面训练SQL语句,通过 管理门户>系统资源管理器>SQL。 TRAIN MODEL HeartDiseaseModel 第7步 - 验证训练后的模型 为了验证训练结果,在 管理门户>系统资源管理器>SQL 中执行以下SQL指令。 VALIDATE MODEL HeartDiseaseModel FROM automl.HeartDiseaseTestData 使用automl.HeartDiseaseTestData view 中的测试数据验证了HeartDiseaseModel。 第8步 - 获取验证指标 为了查看验证过程中的验证指标,在 管理门户>系统资源管理器>SQL 中执行以下SQL 指令。 SELECT * FROM INFORMATION_SCHEMA_ML_VALIDATION_METRICS 要了解返回的结果,请见 https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GIML_VALIDATEMODEL. InterSystems IRIS 文件从验证结果中详细说明了以下内容。: 验证指标,可以在INFORMATION_SCHEMA_ML_VALIDATION_METRICS表中查看 对于回归模型,以下指标会被保存: 方差 R-squared 平均平方误差 均方根误差 对于分类模型,以下指标会被保存: Precision — 这是用真阳性数除以预测阳性数(真阳性与假阳性之和)计算出来的。 Recall — 这是用真阳性数除以实际阳性数(真阳性与假阴性之和)来计算的。 F-Measure — 这是由以下表达式计算的:F = 2 * (精度*召回率) / (精度+召回率) Accuracy — 这是用真阳性和真阴性的数量除以整个测试集的总行数(真阳性、假阳性、真阴性和假阴性之和)来计算的。 第9步 - 使用你的新AutoML模型执行预测 - 最后一步! 为了查看验证过程中的验证指标,在 管理门户>系统资源管理器>SQL 中执行以下SQL指令。 SELECT *, PREDICT(HeartDiseaseModel ) AS heartDiseasePrediction FROM automl.HeartDiseaseTestData 比较列 heartDisease(真实值)和 heartDiseasePrediction(预测值)。
文章
Claire Zheng · 三月 14, 2023

【视频】互联互通套件赋能数据利用与应用创新

数字化转型已经颠覆了很多行业,相信医疗卫生信息行业也不会例外。我们希望通过InterSystems IRIS医疗版互联互通套件,以互联互通为基础,让医院信息平台成为医疗卫生行业数字化转型的智能核心。
文章
Lilian Huang · 五月 26, 2022

在线用Demo服务器工具的重要性- 引自“Importance of the Online Demo Server facility”

#Open Exchange 您可能已经看到邀请分享您的 Open Exchange 应用程序的演示:Share a Demo of Your Open Exchange Application它背后的服务——InterSystems Online Demo Server (ODS)——这不是什么新事物 作为奖励积分,我在 21 年 3 月的 InterSystems 开发者工具大赛:InterSystems Developer Tools Contest 中第一次看到它。在后来的比赛中成为一个固定的奖励项目。实际是#24。到今天,我们已经看到 OEX 中列出了 80 个可在 ODS 上使用的软件包:80 packages listed in OEX as available on ODS 对我来说,开发人员的优势是显而易见的: 给予您的“客户”直接访问您产品的渠道。 视频也是一个很好的推广工具。 但是您知道使用自己的产品并没有那么令人印象深刻。 您的 Docker 容器是在“规范”安装中构建的。 毫无疑问,Docker 是一个令人印象深刻的工具。 在 Win、MAC 和 Linux 上有各种可能会让人头疼的版本。 我跳过关于特殊功能和设置的个人赘述。 您的“客户”可以节省时间来快速查看您提供的方案。 您可以确定他会看到您计划让他看到的内容。 您对容器的端口和其他“本地”变体没有任何问题 所以听听我的信息: 使用 ODS 配置您的方案以获得更好的可见性和更多奖励积分! 我敢肯定,你是赢家! 原文链接:https://community.intersystems.com/node/518386
文章
Nicky Zhu · 九月 22, 2021

IRIS 2021 技术文档 First Look 7 -- 技术概要: 数据转换

本文档将帮助您使用 InterSystems IRIS®数据平台集成产品转换数据。 要浏览所有的技术概要(First Look),包括可以在 InterSystems IRIS 免费的评估实例上执行的那些, 请参见 InterSystems First Looks(《InterSystems 技术概要》)。 数据转换和互操作性 数据转换是 InterSystems IRIS 互操作性的核心。您可以改变从一个系统传入的数据的格式和内容,以满足下游系统的要求,从而允许系统之间进行通信。简单地说,从一个系统发送的信息可以转换为另一个应用程序可以理解的信息。使用 InterSystems IRIS,可以很容易地进行数据转换的创建、测试和维护。 假设您有两个包含产品价格的零售系统。当系统 A 向其他系统发送数据时,包含了不加税的产品基准价格。但是,系统 B 需要在价格中包含地区税。InterSystems IRIS 互操作性产品中的数据转换可以在将数据发送到系统 B 之前将从系统 A 收到的价格转换为加税价格。一旦定义,数据转换将自动处理修改。 常见的转换包括: 将值(value)从源信息复制到目标信息。 根据源信息的(value)执行计算,并将结果复制到目标信息。 为目标信息分配新的值(literal value)。 重新排列数据的顺序。 探索 DTL 编辑器 您可以编写 DTL(数据转换语言)代码来创建数据转换,也可以使用 DTL 编辑器(DTL Editor)来创建。DTL 编辑器(DTL Editor)允许非技术用户无需编写代码就可以创建数据转换。例如,它的图形用户界面允许您通过拖放操作快速地将值从源信息映射到目标信息。下面的 DTL 编辑器(DTL Editor)之旅将通过在产品中创建数据转换来指导您了解其主要功能。有关 InterSystems IRIS 产品的介绍,请参见 First Look:Connecting Systems Using Interoperability Productions(《技术概要:使用互操作性产品连接系统》)。 在这个演示中,必须转换班级里学生的期末成绩数据,以便不同的应用程序可以使用这些数据。 想试试 InterSystems IRIS 互操作性功能的在线视频演示吗?请查看 Interoperability QuickStart(互操作性快速入门)! 用前须知 在开始使用 DTL 编辑器(DTL Editor)之前,您需要完成以下工作: 选择一个 InterSystems IRIS 实例。 从 GitHub 下载 InterSystems IRIS 产品和示例文件。 创建一个支持互操作性的命名空间。 将下载的产品导入命名空间. 选择 InterSystems IRIS 实例 要使用该程序,您需要一个正在运行的 InterSystems IRIS 实例。您的选择包括多种类型的已授权的和免费的评估实例;该实例不需要由您正在工作的系统托管(尽管它们必须相互具有网络访问权限)。有关如何部署每种类型的实例的信息(如果您还没有可使用的实例) 请参见 InterSystems IRIS Basics: Connecting an IDE(InterSystems IRIS 基础:连接一个 IDE)中的 Deploying InterSystems IRIS(部署 InterSystems IRIS)。 从 GitHub 下载 从 https://github.com/intersystems/FirstLook-Data- Transformations 中下载本演示所使用的产品和数据文件。XML 文件是即将部署在系统上的 InterSystems IRIS 产品的载体,您可以通过XML文件导入或导出Production代码。 实例必须可以访问技术概要-数据转换(FirstLook-DataTransformations) 源。下载文件的程序取决于您所使用的实例类型,如下所示: 如果您使用的是 ICM 部署的实例: 使用带有-machine 和 -interactive 选项的 icm ssh 命令,在托管实例的节点上打开默认 shell,例如: icm ssh -machine MYIRIS-AM-TEST-0004 -interactive 在 Linux 命令行上,使用以下命令之一将 repo 克隆到实例的数据存储卷(data storage volume)。例如,对于部署在 Azure 上的配置,数据卷的默认挂载点(default mount point)是 /dev/sdd,因此您可以使用如下命令: $ git clone https://github.com/intersystems/FirstLook-DataTransformations /dev/sdd/FirstLook-DataTransformations OR $ wget -qO- https://github.com/intersystems/FirstLook-DataTransformations/archive/master.tar.gz | tar xvz -C /dev/sdd 这些文件现在对容器文件系统上 /irissys/data/FirstLook-DataTransformations 中的 InterSystems IRIS 可用。 如果您正在使用通过其他方式部署的容器化实例(授权版或社区版[Community Edition]): 在主机上打开 Linux 命令行。(如果您在云节点上使用社区版[Community Edition]),请使用 SSH 连接该节点,如在 Deploy and Explore InterSystems IRIS[《部署和探索 InterSystems IRIS》] 中所述。) 在 Linux 命令行上,使用 git clone 或 wget 命令,如上所述,将 repo 克隆到容器中挂载为卷的存储位置。 - 对于社区版(Community Edition)实例,您可以克隆到实例的持久化 %SYS 目录 (存储特定于实例的配置数据的目录)。在 Linux 文件系统中,这个目录是 /opt/ISC/dur。这使得文件对容器文件系统上 /ISC/dur/FirstLook-DataTransformations 中的 InterSystems IRIS 可用。 - 对于已授权的容器化实例,选择容器中作为卷挂载的任何存储位置(如果使用它,包括持久化 %SYS 目录)。例如,如果您的 docker run 命令包含选项 -v /home/user1:/external, 并且您将 repo 克隆到 /home/user1,则文件对容器文件系统上 /external/FirstLook-DataTransformations 中的 InterSystems IRIS 可用。 如果您使用的是 InterSystems 学习实验室(Learning Labs)实例: 在集成 IDE 中打开命令行终端。 将目录更改为 /home/project/shared 并使用 git clone 命令克隆 repo: $ git clone https://github.com/intersystems/FirstLook-DataTransformations 该文件夹被添加到左边资源管理器(Explorer)面板的 Shared (共享)下,并且该目录对 /home/project/shared 中的 InterSystems IRIS 可用。 如果您使用的是已安装的实例: 如果实例的主机是安装了 GitHub 桌面(GitHub Desktop)和 GitHub 大文件存储(GitHub Large File Storage)的 Windows 系统: 在主机的 web 浏览器中进入 https://github.com/intersystems/FirstLook-DataTransformations。 选择 Clone or download(克隆或下载) 然后选择 Open in Desktop(在桌面上打开)。 这些文件对您的 GitHub 目录中的 InterSystems IRIS 可用,例如在 C:\Users\User1\Documents\GitHub\FirstLook-DataTransformations 中。 如果主机是 Linux 系统, 只需在 Linux 命令行上使用 git clone 命令或 wget 命令将 repo 克隆到您所选择的位置。 创建一个支持互操作性的命名空间 在导入从 GitHub 下载的产品之前,您必须创建一个支持互操作性的命名空间。如果您已经在实例上创建了一个支持互操作性的命名空间,您可以将它用于此产品。要创建一个新的支持互操作性的命名空间,请使用以下过程。(您首次安装 InterSystems IRIS 时创建的命名空间不支持互操作性)。 使用 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中URL described for your instance(实例适用的URL),在浏览器中打开您的实例的管理门户(Management Portal)。 选择 System Administration(系统管理) > Configuration(配置) > System Configuration(系统配置) > Namespaces(命名空间),进入 Namespaces(命名空间) 页面。 在 Namespaces (命名空间) 页面,选择 Create New Namespace(创建新的命名空间)。这将显示 New Namespace(新命名空间)页面; 按照 System Administration Guide(《系统管理指南》)中“Configuring InterSystems IRIS(配置 InterSystems IRIS)”章节中 “Create/Modify a Namespace(创建/修改命名空间)”该页的说明 , 确保选中了 Enable namespace for interoperability productions(为命名空间启用互操作性Production) 复选框。 选择靠近页面顶部的 Save(保存) ,然后在生成的日志末尾选择 Close(关闭)。 导入演示产品 要导入包含数据转换的演示Production,请使用此程序: 在管理门户(Management Portal)中,选择 Interoperability(互操作性) > Manage(管理) > Deployment Changes(部署变更) > Deploy(部署),进入 Deploy Production Changes(部署Production变更) 页面。 如果出现提示,请选择在完成此步骤之前创建的命名空间。 点击 Open Deployment(打开部署)。 进入您从 GitHub 下载文件的目录,选择 DTLStudentDemo.xml,然后点击 OK(确定)。 点击 Deploy(部署)。 点击 OK(確定)。 创建数据转换 InterSystems IRIS 提供了一个数据转换向导(Data Transformation Wizard),以加速和简化创建新数据转换的过程。在本演示中,您将创建一个数据转换,该数据转换连接与班级学生成绩相关的两个记录映射。要创建数据转换: 从管理门户(Management Portal)主页,选择 Interoperability(互操作性) > List(列表) > Data Transformations(数据转换)。 点击 New(新建)。数据转换向导(Data Transformation Wizard)打开。 在 Package(包)下拉列表中选择 Demo(演示)。 在 Name(名称) 字段中,输入一个独特的名称,如 DTLDemoTransform。 点击 Source Class(源类) 字段旁边的放大镜。 点击 Message Classes(信息类) > Demo(演示) > Complex Map(复杂映射) > StudentWCD > Record(记录)。 点击 Target Class(目标类) 字段旁边的放大镜。 点击 Message Classes(信息类) > Demo(演示) > Complex Map(复杂映射) > StudentPFFixed > Record(记录)。 点击 OK(确定)。新的数据转换会在 DTL 编辑器(DTL Editor)中打开。 转换数据 现在您已经创建了数据转换,使用 DTL编辑器(DTL Editor): 将数据从源(source)复制到目标(target),根据需要重新排列数据的顺序。 在课程编号的开头添加学院专用代码。 将最终成绩四舍五入为整数。 使用期末成绩来确定学生是通过还是不通过,并在目标文件中指出这个结果。 忽略目标中不需要的源数据。 复制数据 DTL 编辑器(DTL Editor)最强大、最省时的功能之一是能够将值从源(source)拖放到目标(target)的相应属性。您只需点击并按住源属性上的圆圈,并将其拖动到目标信息的属性。 要将值从源(source)复制到目标(target): 点击并按住源(source)的 ClassID 属性的圆圈(在编辑器[Editor]的左侧)。 将光标拖动到目标(target)的 ClassID 属性,直到它被高亮显示,然后释放鼠标按钮。 源(source)的 ClassID 的值将被复制到目标(target)的 ClassID 属性。 按照此程序,将下列源属性连接到相应的目标属性: 学生 ID(StudentID) 成绩(Grade) 姓氏(LastName) 名字(FirstName) 中间名(MiddleName) 编辑器(Editor)现在应该是这样的: 请注意,仅仅通过连接属性对(property pairs),您便已经更改了存储数据的顺序。 修改属性(Property)的值 在某些情况下,您希望在将源属性(source property)复制到相应的目标属性(target property)之前更改其值。在这个演示中,目标系统接受一个 ClassID,这个 ClassID 以两个字符的标识符开头,表示源(Source)的学院。源的信息不包括这个标识符,因此数据转换必须在将 ClassID 的值复制到目标信息之前修改它。 点击,连接源的 ClassID 属性和目标的 ClassID 属性的线上的圆圈。 请注意,编辑器(Editor)右侧的 Action(操作) 标签现在显示了连接两个 ClassID 属性时创建的 Assign 操作的信息。Property(属性) 字段被设置为 target.ClassID,Value(值)字段被设置为 source.ClassID。 将 Action(操作) 标签的 Value(值) 字段变更为: "UC."_source.ClassID。UC 是学院的标识符,它使用下划线添加到 ClassID 的开头,下划线是 InterSystems ObjectScript 编程语言中的连接操作符。这超出了本演示的范围,但它让您了解如何在转换中包含 ObjectScript 代码。 使用函数 在设置属性值时,您可以使用内置函数。在本演示中,使用 Round() 函数将最终成绩四舍五入为整数。 选择源的成绩(Grade)属性和目标的成绩(Grade)属性之间的连接器。 点击 Action(操作) 标签的 Value(值) 字段旁边的放大镜。 从 Function (函数) 下拉列表中选择 Round ( )。 点击 OK(确定定)。 将 Action(操作) 标签的 Value(值) 字段设置为:..Round(source.Grade) 使用操作表 请注意,当您将源属性(source property)映射到目标属性(target property)时,DTL 编辑器(DTL Editor)将 Set(设置)操作添加到图表下方的表格中。 虽然 DTL 编辑器(DTL Editor) 的图形化部分使可视化和快速执行操作变得容易,但有时使用图表下方的表格来进一步定义转换会更好。例如,在本演示中, 在源属性和目标属性之间单击图形连接是选择 Set(设置)操作的最快方法。然而,在更复杂的转换中,可能很难选择连接器。在这种情况下,从图表下方的表格中选择 Set(设置)操作会更容易些。 定义有条件的操作集 在转换数据时,只有在某些条件为真时,才能使用条件语句执行操作。在本演示中,您定义了一个转换,如果期末成绩大于或等于 65 分,则表示学生通过了该课程。要添加 If 语句来完成此操作: 确保最后一项是高亮显示的表格。If 语句位于高亮显示的操作之后。 从 Add Action(添加操作) 下拉列表中选择 If。 请注意,图表下方的表格中添加了一个 If 块。 在表格中选择 If 语句后, 在 Action(操作) 标签上定义 Condition(条件)字段为: target.Grade>=65。只有当目标的成绩(Grade) 属性值大于或等于 65 时,才会执行放在 If 块内的操作。 从 Add Action(添加操作)下拉列表中选择 Set(设置)。 在 Action(操作) 标签上,定义 Property(属性) 字段为:target.Pass。 定义 Value(值) 字段为 1。这是一个布尔值(boolean value),表示该学生通过了这门课程。 选择表格中的 else(其他) 操作。 从 Add Action(添加操作)下拉列表中选择 Set(设置)。 在 Action(操作) 标签上,定义 Property(属性) 字段为:target.Pass。 在 Action(操作) 标签上,定义 Value(值) 字段为 0。这是一个布尔值(boolean value),表示该学生没有通过这门课程。 if 块现在应该是这样的: 忽略来自源信息(Source Message)的数据 在演示中,请注意 Email、Phone 和 Phone1 属性没有连接到目标信息。不需要进一步的操作来防止源信息中的这些数据被复制到目标信息。 编译数据转换 您可以选择随时保存工作,但必须始终记住编译数据转换。在您点击 Compile(编译)之前,产品无法识别更改。 进行初步测试 DTL 编辑器(DTL Editor)使您能够快速测试数据转换,而不必在整个生产过程中运行信息。您只需输入测试信息,DTL 编辑器(DTL Editor)就会显示输出信息的样子。在本演示的这一点上,您将记录映射数据的 XML 表示(XML representation)粘贴到测试转换(Test Transform)工具中。 稍后,您将通过在产品中运行文本文件来测试这个转换。 记住在测试数据转换之前要编译它。 点击编辑器右侧的 Tools(工具) 标签。 点击 Test(测试)。 将以下数据复制并粘贴到 Input Message(输入信息)文本框中: <test> <Record> <ClassID>CS241</ClassID> <StudentID>930698</StudentID> <Grade>77.8</Grade> <LastName>Sutherland</LastName> <FirstName>David</FirstName> <MiddleName>Timothy</MiddleName> <Email>david.sutherland@mail.com</Email> <Phone>978-343-3940</Phone> <Phone1>978-343-0951</Phone1> </Record> </test> 点击 Test(测试)。 Output Message(输出信息)文本框现在应该是这样的: <Record> <StudentID>930698</StudentID> <ClassID>UC.CS241</ClassID> <Grade>78</Grade> <Pass>true</Pass> <FirstName>David</FirstName> <MiddleName>Timothy</MiddleName> <LastName>Sutherland</LastName> </Record> 提示: 在处理 HL7 或其他 EDI 信息时,您可以从示例信息中复制和粘贴原始文本来测试转换。您不需要信息的 XML 表示(XML representation)。 向产品添加转换 现在您已经创建并编译了数据转换,必须将其添加到产品中,以便将流经产品的源信息转换为发送到下游应用程序的信息。在本演示中,您将向与业务流程 DTLDemoRouter 关联的业务规则添加转换。 从管理门户(Management Portal)主页,进入 Interoperability(互操作性) > List(列表) > Productions(产品)。 选择 Demo.ComplexMap.SemesterProduction 并点击 Open(打开)。 选择 Processes(进程)下的 DTLDemoRouter。 在 Settings(设置)标签上,点击 Business Rule Name(业务规则名称)字段旁边的放大镜。 双击位于业务规则 send(发送)操作中的 transform(转换)形状。 在 Data Transform Selector(数据转换选择器) 对话框中,选择您为这个演示创建的数据转换。 点击 OK(確定)。 在业务规则编辑器(Business Rule Editor)中,点击 Save(保存)。 有关业务规则的更多信息,请参见 Developing Business Rules(《开发业务规则》)。 测试数据转换 现在您已经将数据转换添加到产品中,运行产品以查看您的演示如何运行。在这一步骤中: 创建产品接收和发送示例文件的目录。 启动产品。 将示例输入文件复制到正确的目录中。 比较目标文件和源文件的内容。 创建所需的目录 演示产品被定义为在实例的主机 c:\practice\in 中查找包含源数据的文件,并将目标文件编写到 c:\practice\out 中。如果您不能在主机的 c:\ drive 上创建目录,或者它不是 Windows 系统,您必须识别或创建替代目录,然后在继续之前修改产品的业务服务和业务操作。业务服务的 File Path(文件路径)设置定义了产品查找输入文件的位置,而业务操作的 File Path(文件路径)设置定义了发送目标文件的位置。 创建目录的方式这取决于使用的实例类型 ,如下所示: 对于由 ICM 部署的实例,可以使用带有 -machine 和 -interactive 选项的 icm exec 命令,在运行实例的容器中打开 bash shell,例如: icm exec -command bash -machine MYIRIS-AM-TEST-0004 -interactive 然后您可以在容器文件系统上创建目录。 对于任何容器化的实例, 无论是授权版还是社区版(Community Edition), 使用命令 docker exec -it container_name bash 在容器中打开 bash shell (社区版[Community Edition]容器的名称是 try-iris)。然后在容器文件系统上创建目录。 对于 InterSystems 学习实验室(Learning Labs),使用集成 IDE 中的命令行终端,在共享(Shared)文件夹中创建新文件夹;您可以在 /home/project/shared 下的管理门户(Management Portal)中浏览到这些。 对于已安装的实例,在本地文件系统上创建目录。 本练习的其余部分假设目录路径为 c:\practice\in 和 c:\practice\out;如果不同,请替换为正确的路径。 启动产品 要启动包含演示数据转换的产品: 从管理门户(Management Portal)主页,进入 Interoperability(互操作性) > List(列表) > Productions(产品)。 选择 Demo.ComplexMap.SemesterProduction 并点击 Open(打开)。 点击 Start(开始)。 复制 .CSV 文件到目录 产品被定义为接受一个 .CSV 文件,其中包含来自 c:\practice\in 的学生信息。将 input.csv 文件从包含 GitHub 文件的目录复制到输入目录,或者 c:\practice\in ,或者您创建并指定的其他目录。 只要产品在运行,该文件就应该在几秒钟内从目录中消失,这表明产品已经开始成功地处理该文件。 验证输出数据 演示产品使用复制到产品的输入目录中的 .Csv 文件,并使用数据转换将数据转换为具有新内容的不同格式。这个传出文件被复制到产品的输出目录中,要么是 c:\practice\out ,要么是您创建并指定的另一个目录,文件名为时间戳。 打开 input.csv 和输出文件并比较两者。 其他重要功能 本演示提供了开发和测试数据转换的基础知识。其他重要的、常用的功能包括: for each 语句遍历一个集合,对集合的每个成员执行相同的操作序列。这个集合可以是一个数组,在 HL7 或其他 EDI 信息的情况下,也可以是一个重复段。更多信息,请参见 Adding a For Each Action(添加 For Each 操作)。 子转换,它允许您模块化数据转换。数据转换可以使用子转换操作在操作流的任何点上运行另一个转换。您可以创建可重用转换的库, 这些库可以从其他转换调用,从而避免重复转换逻辑。例如,您可以针对HL7 V2消息中的段创建段转换,只要这些段出现在 EDI 信息中就可以重复使用。 支持 X12 和 EDIFACT 标准。当使用数据转换向导创建新的转换时,您可以指定信息类型是 X12 还是 EDIFACT。这允许您选择使用正确的模式填充 DTL 编辑器(DTL Editor)的文档类型。这些模式段的可视化表示在 DTL 编辑器(DTL Editor)中展开和折叠。 了解有关数据转换的更多信息 有关数据转换的更多细节,请参见: Developing DTL Transformations(《开发 DTL 转换》) Advanced Data Transformations(高级数据转换) (在线课程) Business Process and Data Transformation Language Reference(《业务流程和数据转换语言参考》)
文章
姚 鑫 · 二月 3, 2021

第二十三章 Caché 变量大全 $Y 变量

# 第二十三章 Caché 变量大全 $Y 变量 包含光标的当前垂直位置。 # 大纲 ```java $Y ``` # 描述 `$Y`包含光标的当前垂直位置。当字符写入设备时,Caché会更新`$Y`以反映垂直光标位置。 输出的每个换行符(换行符)(`ASCII 10`)将`$Y`递增1。换页符(`ASCII 12`)将`$Y`重置为0。 `$Y`是16位无符号整数。当其值达到65536时,`$Y`换行为0。换句话说,如果`$Y`为65535,则下一个输出字符将其重置为0。 可以使用`set`命令为`$X`和`$Y`赋值。例如,可以使用特殊的转义序列来改变物理游标位置,而不更新`$X`和`$Y`的值。在这种情况下,在使用转义序列之后,使用`set`将正确的值分配给`$X`和`$Y`。 # 注意 ## NLS字符映射 国家语言支持(NLS)实用程序`$X/$Y`选项卡定义当前区域设置的`$X`和`$Y`光标移动字符。 ## 带终端I/O的`$Y` 下表显示了不同字符对`$Y`的影响。 Echoed Character | ASCII Code |Effect on $X ---|---|--- `` |12| `$Y=0` `` |13| `$Y=$Y` `` |10| `$Y=$Y+1` `` |8| `$Y=$Y` `` |9| `$Y=$Y` 任何可打印的ASCII字符 |32-126| `$Y=$Y` `OPEN`和`USE`命令的S(ECRET)协议关闭回显。它还可以防止`$Y`在输入过程中被更改,因此它指示真实的光标位置。 更改垂直位置的`WRITE $CHAR()`也会更改`$Y`。更改垂直位置的`WRITE*`不会更改`$Y`。例如,`WRITE$Y,$CHAR(10),$Y`执行换行并递增`$Y`。相比之下,`WRITE$Y,*10,$Y`执行换行符,但不会递增`$Y`。 因为`WRITE*`不会改变`$Y`,所以可以向终端发送一个控制序列,而`$Y`仍将反映真实的光标位置。由于某些控制序列确实会移动光标,因此可以使用`SET`命令直接设置`$Y`。例如,以下命令将光标移动到VT100型端子上的列20和行10,并相应地设置`$X`和`$Y`: ```java SET dy=10,dx=20 WRITE *27,*91,dy+1,*59,dx+1,*72 SET $Y=dy,$X=dx ``` 设备执行但不输出的ANSI标准控制序列(如转义序列)可能会在`$X`和`$Y`值与真实光标位置之间产生差异。要避免此问题,请使用`WRITE*`语句并指定字符串中每个字符的ASCII值。例如,不使用以下代码: ```java WRITE $CHAR(27)_"[1m" ``` 使用此等效表: ```java WRITE *27,*91,*49,*109 ``` 通常,在显式移动光标的任何转义序列之后,应更新`$X`和`$Y`以反映实际光标位置。
文章
姚 鑫 · 十月 14, 2022

第十六章 CSP 中的 HTTP 请求 - %CSP.Request 对象

# 第十六章 CSP 中的 HTTP 请求 - %CSP.Request 对象 # %CSP.Request 对象 当 `CSP` 服务器响应 `HTTP` 请求时,它将有关传入请求的信息打包到对象中的 `%CSP.Request` 实例中。可以使用变量 `%request` 来引用此对象。 ## URL 属性 要查找传入 `HTTP` 请求的 `URL`(不包括查询字符串),对象中使用 `%CSP.Request` 的 `URL` 属性: ```java Write "URL: ", %request.URL ``` ## 数据属性和 `URL` 参数 `URL` 可能包含参数列表(也称为 `URL` 查询)对象中的 `%CSP.Request `通过其 `Data` 属性使这些可用。 例如,假设传入的 URL 包含: ```java /csp/user/MyPage.csp?A=10&a=20&B=30&B=40 ``` 可以使用以下命令在服务器上检索这些参数: ```java Write %request.Data("A",1) // this is 10 Write %request.Data("a",1) // this is 20 Write %request.Data("B",1) // this is 30 Write %request.Data("B",2) // this is 40 ``` **数据是一个多维属性,其中存储的每个值都有 `2` 个下标:参数的名称和参数的索引号(参数可以在 `URL` 中多次出现,如上面的 `B`)。请注意,参数名称区分大小写。** 另请注意,传入的 `HTTP` 请求是 `GET` 还是 `POST` 请求并不重要:`Data` 属性以完全相同的方式表示参数值。 可以使用` ObjectScript $Data ($D)` 函数来测试是否定义了给定的参数值: ```java If ($Data(%request.Data("parm",1))) { } ``` 如果您希望引用一个参数但不确定它是否已定义,可以使用 `ObjectScript $Get` 函数: ```java Write $Get(%request.Data("parm",1)) ``` 可以在对象中使用 `%CSP.Request`的 `Count` 方法找出为特定参数名称定义了多少值: ```java For i = 1:1:%request.Count("parm") { Write %request.Data("parm",i) } ``` ## CgiEnvs 属性和 CGI环境变量 `Web` 服务器提供一组值,称为 `CGI`(通用网关接口)环境变量,其中包含有关 `HTTP` 客户端和 `Web` 服务器的信息。可以使用多维属性 `CgiEnvs` 访问这些 `CGI` 环境值。可以按照与 `Data` 属性相同的方式使用它。 例如,要确定发出 `HTTP` 请求的浏览器类型,请查看 `CGI` 环境变量 `HTTP_USER_AGENT` 的值: ```java Write %request.CgiEnvs("HTTP_USER_AGENT") ``` ## Cookies 属性 如果 `HTTP` 请求包含任何 `cookie`,可以使用多维属性 `Cookies` 检索它们的值。可以按照与 `Data` 属性相同的方式使用它。 数据也可以保存在 `%session` 对象中。 **请参阅 `CSP` 示例数据库中 `cookie.csp` 中使用 `cookie` 的示例。** ## MIME 数据属性 **传入请求可能包含 `MIME`(多用途 `Internet` 邮件扩展)数据。这通常用于较大的信息,例如文件。可以在对象中使用 `%CSP.Request` 检索 `MIME` 数据。这将创建并返回一个 `Caché` 流对象的实例,然后可以使用该实例来读取 `MIME` 数据。** **有关使用 `MIME` 数据的示例,请参阅 `CSP` 示例中的 `upload.csp`。**
文章
Frank Ma · 六月 27, 2022

使用Python和仪表盘制作的一个欧洲水状况应用程序

比较不同的商业智能技术是非常有趣的。我很好奇它们在功能、开发工具、速度和可用性方面有什么不同。 在这个应用程序中,我选择了一个有欧洲各国水状况的数据集。这是一个开源的数据集,包含1991年到2017年的观测数据。 团队和我决定使用IRIS BI、Tableau、PowerBI和InterSystems Reports(由Logi Reports驱动)在这个BI数据集的基础上制作一个模型 对于前端,我们通过Embedded Python在PythonFlask中制作了一个网页界面。 顺便说一下,其结果可以在这个网页上看到:http://atscale.teccod.com:8080/ 你可以看看demo stand (演示台),因为从资源库部署一个容器可能需要多至20分钟的时间。大量的python包,后面会有更多的原因。 主页面 数据 事实上,数据似乎很小,期间只有17年 :) 因此,在现有的基础上,我想延续数据集,为此使用了一个神经网络。使用同样的嵌入式Python,使用了Tensorflow,这个包下载后占据了511MB,不要惊讶 实际上,这也是容器部署时间长的原因--为神经网络下载了很多包,相当多的相关包,安装时间很长。不过会有一篇关于神经网络和Integrated ML(一体化机器学习)的单独文章,我很快会发表。 我还要说的是,预测的结果被输入到同一个数据库,所以你可以通过BI工具看到数据集。但是预测只针对法国的一条河,请仔细看一下。因为我们只有足够的力量计算一件事。完整的预测会花很长的时间。 数据立方体 数据立方体是在IRIS中制作的,同时立方体也是在Adaptive Analytics(由AtScale驱动)中制作的。因此,IRIS的BI仪表盘是在IRIS上建立的,其余的工具(Logi、PowerBI、Tableau)从AtScale上获取数据。 仪表板 实际上商业智能系统是以多种形式呈现的。 这是在python中的Dash。 我们喜欢的IRIS BI InterSystems报告(由Logi报告提供)。 PowerBI Tableau 样例 完成 对于所介绍的所有BI系统,源文件都可以在资源库中找到。你可以看到报告和仪表盘是如何工作的,并在你未来的项目中使用它们。 通过它们,你可以直观地看到一个特定的系统是如何工作的,也可以了解一个特定的系统有哪些开发工具。 我们没时间来制作一个页面,让你可以输入各种参数和条件,使用神经网络的可能值进行计算。这里有一些先决条件,有一个实施神经网络的例子,以及在其帮助下所做的预测,这些都是在嵌入式Python中实现的。神经网络已被训练,启动脚本也是可用的,位于 https://github.com/teccod/water-conditions-Europe/blob/main/iris/src/PythonFlask/pages/ml/ml_run.py文件夹中。 谢谢你阅读这篇文章,我在等待评论和反馈。很快就会有一篇关于在嵌入式Python和IntegratedML(一体化机器学习)中比较神经网络的文章,我将把它附在这篇文章中。
公告
Claire Zheng · 四月 18, 2021

置顶--社区福利持续更新中!来Global Masters,赢取Apple AirPods,Amazon Echo Dot,解锁更多奖品

Hi 亲爱的社区开发者们,福利来了! 在Global Masters,我们为 Expert, Ambassador and VIP levels(专家级、大使级和VIP级)的用户提供了更多奖励! Apple AirPods 希望你们喜欢新奖品! 此外,你可以在奖励列表中看到"解锁获奖" 项目,根据提示完成相应目标后,便可解锁并申请奖品。 社区奖励兑换近期更新啦,有帽子,Amzon Echo Dot 等众多新礼品,欢迎大家多赚积分多兑换!!!更多更新还在路上,敬请期待! 关于Global Masters: 如何加入InterSystems Global Masters倡导中心? Global Masters等级及徽章说明(英文) 如果您还没有加入InterSystems Global Masters倡导中心 , 现在就加入吧! 如果您有任何疑问,欢迎跟帖回复! 👍👍 努力攒积分中 问问题,回答问题,发表文章,看帖子,做小测试。。。都可以获得点数,欢迎大家踊跃参与完成挑战! 详情请访问:https://globalmasters.intersystems.com/challenges
文章
Nicky Zhu · 九月 27, 2021

IRIS 2021 技术文档 First Look 17 Globals

html {overflow-x: initial !important;}:root { --bg-color: #ffffff; --text-color: #333333; --select-text-bg-color: #B5D6FC; --select-text-font-color: auto; --monospace: "Lucida Console",Consolas,"Courier",monospace; --title-bar-height: 20px; } .mac-os-11 { --title-bar-height: 28px; } html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; } body { margin: 0px; padding: 0px; height: auto; inset: 0px; font-size: 1rem; line-height: 1.42857143; overflow-x: hidden; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; tab-size: 4; background-position: inherit; background-repeat: inherit; } iframe { margin: auto; } a.url { word-break: break-all; } a:active, a:hover { outline: 0px; } .in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); } #write { margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; } #write.first-line-indent p { text-indent: 2em; } #write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; } #write.first-line-indent li { margin-left: 2em; } .for-image #write { padding-left: 8px; padding-right: 8px; } body.typora-export { padding-left: 30px; padding-right: 30px; } .typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; } .typora-export .task-list-item input { pointer-events: none; } @media screen and (max-width: 500px) { body.typora-export { padding-left: 0px; padding-right: 0px; } #write { padding-left: 20px; padding-right: 20px; } .CodeMirror-sizer { margin-left: 0px !important; } .CodeMirror-gutters { display: none !important; } } #write li > figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max-width: 100%; vertical-align: middle; image-orientation: from-image; } button, input, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; } input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; } *, ::after, ::before { box-sizing: border-box; } #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; } #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; } p { line-height: inherit; } h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; } p { orphans: 4; } h1 { font-size: 2rem; } h2 { font-size: 1.8rem; } h3 { font-size: 1.6rem; } h4 { font-size: 1.4rem; } h5 { font-size: 1.2rem; } h6 { font-size: 1rem; } .md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; } .hidden { display: none; } .md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; } a { cursor: pointer; } sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; cursor: pointer; } sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; } #write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; } figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; } figure > table { margin: 0px; } tr { break-inside: avoid; break-after: auto; } thead { display: table-header-group; } table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; } table.md-table td { min-width: 32px; } .CodeMirror-gutters { border-right-width: 0px; background-color: inherit; } .CodeMirror-linenumber { } .CodeMirror { text-align: left; } .CodeMirror-placeholder { opacity: 0.3; } .CodeMirror pre { padding: 0px 4px; } .CodeMirror-lines { padding: 0px; } div.hr:focus { cursor: none; } #write pre { white-space: pre-wrap; } #write.fences-no-line-wrapping pre { white-space: pre; } #write pre.ty-contain-cm { white-space: normal; } .CodeMirror-gutters { margin-right: 4px; } .md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; position: relative !important; background-position: inherit; background-repeat: inherit; } .md-fences-adv-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; } #write .md-fences.mock-cm { white-space: pre-wrap; } .md-fences.md-fences-with-lineno { padding-left: 0px; } #write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; } .md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; } .CodeMirror-line, twitterwidget { break-inside: avoid; } .footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; } .footnotes + .footnotes { margin-top: 0px; } .md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; background-position: 0px 0px; } li div { padding-top: 0px; } blockquote { margin: 1rem 0px; } li .mathjax-block, li p { margin: 0.5rem 0px; } li blockquote { margin: 1rem 0px; } li { margin: 0px; position: relative; } blockquote > :last-child { margin-bottom: 0px; } blockquote > :first-child, li > :first-child { margin-top: 0px; } .footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; } #write .footnote-line { white-space: pre-wrap; } @media print { body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; } #write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; } .typora-export * { -webkit-print-color-adjust: exact; } .typora-export #write { break-after: avoid; } .typora-export #write::after { height: 0px; } .is-mac table { break-inside: avoid; } .typora-export-show-outline .typora-export-sidebar { display: none; } } .footnote-line { margin-top: 0.714em; font-size: 0.7em; } a img, img a { cursor: pointer; } pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background-color: rgb(204, 204, 204); display: block; overflow-x: hidden; } p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; } #write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; } p > .md-image:only-child { display: inline-block; width: 100%; } #write .MathJax_Display { margin: 0.8em 0px 0px; } .md-math-block { width: 100%; } .md-math-block:not(:empty)::after { display: none; } .MathJax_ref { fill: currentcolor; } [contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; } .md-task-list-item { position: relative; list-style-type: none; } .task-list-item.md-task-list-item { padding-left: 0px; } .md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; } .math { font-size: 1rem; } .md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; } .md-toc-content { position: relative; margin-left: 0px; } .md-toc-content::after, .md-toc::after { display: none; } .md-toc-item { display: block; color: rgb(65, 131, 196); } .md-toc-item a { text-decoration: none; } .md-toc-inner:hover { text-decoration: underline; } .md-toc-inner { display: inline-block; cursor: pointer; } .md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; } .md-toc-h2 .md-toc-inner { margin-left: 2em; } .md-toc-h3 .md-toc-inner { margin-left: 4em; } .md-toc-h4 .md-toc-inner { margin-left: 6em; } .md-toc-h5 .md-toc-inner { margin-left: 8em; } .md-toc-h6 .md-toc-inner { margin-left: 10em; } @media screen and (max-width: 48em) { .md-toc-h3 .md-toc-inner { margin-left: 3.5em; } .md-toc-h4 .md-toc-inner { margin-left: 5em; } .md-toc-h5 .md-toc-inner { margin-left: 6.5em; } .md-toc-h6 .md-toc-inner { margin-left: 8em; } } a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; } .footnote-line a:not(.reversefootnote) { color: inherit; } .md-attr { display: none; } .md-fn-count::after { content: "."; } code, pre, samp, tt { font-family: var(--monospace); } kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background-color: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; } .md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); } code { text-align: left; } a.md-print-anchor { white-space: pre !important; border: none !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; text-shadow: initial !important; background-position: 0px 0px !important; } .os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; } .md-diagram-panel > svg { max-width: 100%; } [lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; } [lang="mermaid"] .node text { font-size: 1rem; } table tr th { border-bottom-width: 0px; } video { max-width: 100%; display: block; margin: 0px auto; } iframe { max-width: 100%; width: 100%; border: none; } .highlight td, .highlight tr { border: 0px; } mark { background-color: rgb(255, 255, 0); color: rgb(0, 0, 0); } .md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; } .md-expand mark .md-meta { opacity: 0.3 !important; } mark .md-meta { color: rgb(0, 0, 0); } @media print { .typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; } } .md-diagram-panel .messageText { stroke: none !important; } .md-diagram-panel .start-state { fill: var(--node-fill); } .md-diagram-panel .edgeLabel rect { opacity: 1 !important; } .md-require-zoom-fix { height: auto; margin-top: 16px; margin-bottom: 16px; } .md-require-zoom-fix foreignObject { font-size: var(--mermaid-font-zoom); } .md-fences.md-fences-math { font-size: 1em; } .md-fences-advanced:not(.md-focus) { padding: 0px; white-space: nowrap; border: 0px; } .md-fences-advanced:not(.md-focus) { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit; background-repeat: inherit; } .typora-export-show-outline .typora-export-content { max-width: 1440px; margin: auto; display: flex; flex-direction: row; } .typora-export-sidebar { width: 300px; font-size: 0.8rem; margin-top: 80px; margin-right: 18px; } .typora-export-show-outline #write { --webkit-flex: 2; flex: 2 1 0%; } .typora-export-sidebar .outline-content { position: fixed; top: 0px; max-height: 100%; overflow: hidden auto; padding-bottom: 30px; padding-top: 60px; width: 300px; } @media screen and (max-width: 1024px) { .typora-export-sidebar, .typora-export-sidebar .outline-content { width: 240px; } } @media screen and (max-width: 800px) { .typora-export-sidebar { display: none; } } .outline-content li, .outline-content ul { margin-left: 0px; margin-right: 0px; padding-left: 0px; padding-right: 0px; list-style: none; } .outline-content ul { margin-top: 0px; margin-bottom: 0px; } .outline-content strong { font-weight: 400; } .outline-expander { width: 1rem; height: 1.428571429rem; position: relative; display: table-cell; vertical-align: middle; cursor: pointer; padding-left: 4px; } .outline-expander::before { content: ''; position: relative; font-family: Ionicons; display: inline-block; font-size: 8px; vertical-align: middle; } .outline-item { padding-top: 3px; padding-bottom: 3px; cursor: pointer; } .outline-expander:hover::before { content: ''; } .outline-h1 > .outline-item { padding-left: 0px; } .outline-h2 > .outline-item { padding-left: 1em; } .outline-h3 > .outline-item { padding-left: 2em; } .outline-h4 > .outline-item { padding-left: 3em; } .outline-h5 > .outline-item { padding-left: 4em; } .outline-h6 > .outline-item { padding-left: 5em; } .outline-label { cursor: pointer; display: table-cell; vertical-align: middle; text-decoration: none; color: inherit; } .outline-label:hover { text-decoration: underline; } .outline-item:hover { border-color: rgb(245, 245, 245); background-color: var(--item-hover-bg-color); } .outline-item:hover { margin-left: -28px; margin-right: -28px; border-left-width: 28px; border-left-style: solid; border-left-color: transparent; border-right-width: 28px; border-right-style: solid; border-right-color: transparent; } .outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before { display: none; } .outline-item-open > .outline-item > .outline-expander::before { content: ''; } .outline-children { display: none; } .info-panel-tab-wrapper { display: none; } .outline-item-open > .outline-children { display: block; } .typora-export .outline-item { padding-top: 1px; padding-bottom: 1px; } .typora-export .outline-item:hover { margin-right: -8px; border-right-width: 8px; border-right-style: solid; border-right-color: transparent; } .typora-export .outline-expander::before { content: "+"; font-family: inherit; top: -1px; } .typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before { content: '−'; } .typora-export-collapse-outline .outline-children { display: none; } .typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children { display: block; } .typora-export-no-collapse-outline .outline-expander::before { content: "" !important; } .typora-export-show-outline .outline-item-active > .outline-item .outline-label { font-weight: 700; } .md-inline-math-container mjx-container { zoom: 0.95; } :root { --side-bar-bg-color: #fafafa; --control-text-color: #777; } @include-when-export url(https://fonts.loli.net/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext); /* open-sans-regular - latin-ext_latin */ /* open-sans-italic - latin-ext_latin */ /* open-sans-700 - latin-ext_latin */ /* open-sans-700italic - latin-ext_latin */ html { font-size: 16px; -webkit-font-smoothing: antialiased; } body { font-family: "Open Sans","Clear Sans", "Helvetica Neue", Helvetica, Arial, 'Segoe UI Emoji', sans-serif; color: rgb(51, 51, 51); line-height: 1.6; } #write { max-width: 860px; margin: 0 auto; padding: 30px; padding-bottom: 100px; } @media only screen and (min-width: 1400px) { #write { max-width: 1024px; } } @media only screen and (min-width: 1800px) { #write { max-width: 1200px; } } #write > ul:first-child, #write > ol:first-child{ margin-top: 30px; } a { color: #4183C4; } h1, h2, h3, h4, h5, h6 { position: relative; margin-top: 1rem; margin-bottom: 1rem; font-weight: bold; line-height: 1.4; cursor: text; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { text-decoration: none; } h1 tt, h1 code { font-size: inherit; } h2 tt, h2 code { font-size: inherit; } h3 tt, h3 code { font-size: inherit; } h4 tt, h4 code { font-size: inherit; } h5 tt, h5 code { font-size: inherit; } h6 tt, h6 code { font-size: inherit; } h1 { font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid #eee; } h2 { font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid #eee; } /*@media print { .typora-export h1, .typora-export h2 { border-bottom: none; padding-bottom: initial; } .typora-export h1::after, .typora-export h2::after { content: ""; display: block; height: 100px; margin-top: -96px; border-top: 1px solid #eee; } }*/ h3 { font-size: 1.5em; line-height: 1.43; } h4 { font-size: 1.25em; } h5 { font-size: 1em; } h6 { font-size: 1em; color: #777; } p, blockquote, ul, ol, dl, table{ margin: 0.8em 0; } li>ol, li>ul { margin: 0 0; } hr { height: 2px; padding: 0; margin: 16px 0; background-color: #e7e7e7; border: 0 none; overflow: hidden; box-sizing: content-box; } li p.first { display: inline-block; } ul, ol { padding-left: 30px; } ul:first-child, ol:first-child { margin-top: 0; } ul:last-child, ol:last-child { margin-bottom: 0; } blockquote { border-left: 4px solid #dfe2e5; padding: 0 15px; color: #777777; } blockquote blockquote { padding-right: 0; } table { padding: 0; word-break: initial; } table tr { border: 1px solid #dfe2e5; margin: 0; padding: 0; } table tr:nth-child(2n), thead { background-color: #f8f8f8; } table th { font-weight: bold; border: 1px solid #dfe2e5; border-bottom: 0; margin: 0; padding: 6px 13px; } table td { border: 1px solid #dfe2e5; margin: 0; padding: 6px 13px; } table th:first-child, table td:first-child { margin-top: 0; } table th:last-child, table td:last-child { margin-bottom: 0; } .CodeMirror-lines { padding-left: 4px; } .code-tooltip { box-shadow: 0 1px 1px 0 rgba(0,28,36,.3); border-top: 1px solid #eef2f2; } .md-fences, code, tt { border: 1px solid #e7eaed; background-color: #f8f8f8; border-radius: 3px; padding: 0; padding: 2px 4px 0px 4px; font-size: 0.9em; } code { background-color: #f3f4f4; padding: 0 2px 0 2px; } .md-fences { margin-bottom: 15px; margin-top: 15px; padding-top: 8px; padding-bottom: 6px; } .md-task-list-item > input { margin-left: -1.3em; } @media print { html { font-size: 13px; } table, pre { page-break-inside: avoid; } pre { word-wrap: break-word; } } .md-fences { background-color: #f8f8f8; } #write pre.md-meta-block { padding: 1rem; font-size: 85%; line-height: 1.45; background-color: #f7f7f7; border: 0; border-radius: 3px; color: #777777; margin-top: 0 !important; } .mathjax-block>.code-tooltip { bottom: .375rem; } .md-mathjax-midline { background: #fafafa; } #write>h3.md-focus:before{ left: -1.5625rem; top: .375rem; } #write>h4.md-focus:before{ left: -1.5625rem; top: .285714286rem; } #write>h5.md-focus:before{ left: -1.5625rem; top: .285714286rem; } #write>h6.md-focus:before{ left: -1.5625rem; top: .285714286rem; } .md-image>.md-meta { /*border: 1px solid #ddd;*/ border-radius: 3px; padding: 2px 0px 0px 4px; font-size: 0.9em; color: inherit; } .md-tag { color: #a7a7a7; opacity: 1; } .md-toc { margin-top:20px; padding-bottom:20px; } .sidebar-tabs { border-bottom: none; } #typora-quick-open { border: 1px solid #ddd; background-color: #f8f8f8; } #typora-quick-open-item { background-color: #FAFAFA; border-color: #FEFEFE #e5e5e5 #e5e5e5 #eee; border-style: solid; border-width: 1px; } /** focus mode */ .on-focus-mode blockquote { border-left-color: rgba(85, 85, 85, 0.12); } header, .context-menu, .megamenu-content, footer{ font-family: "Segoe UI", "Arial", sans-serif; } .file-node-content:hover .file-node-icon, .file-node-content:hover .file-node-open-state{ visibility: visible; } .mac-seamless-mode #typora-sidebar { background-color: #fafafa; background-color: var(--side-bar-bg-color); } .md-lang { color: #b4654d; } /*.html-for-mac { --item-hover-bg-color: #E6F0FE; }*/ #md-notification .btn { border: 0; } .dropdown-menu .divider { border-color: #e5e5e5; opacity: 0.4; } .ty-preferences .window-content { background-color: #fafafa; } .ty-preferences .nav-group-item.active { color: white; background: #999; } .menu-item-container a.menu-style-btn { background-color: #f5f8fa; background-image: linear-gradient( 180deg , hsla(0, 0%, 100%, 0.8), hsla(0, 0%, 100%, 0)); } :root {--mermaid-font-zoom:1em ;} @media print { @page {margin: 0 0 0 0;} body.typora-export {padding-left: 0; padding-right: 0;} #write {padding:0;}} 目录 技术概要: Globals 1 什么是 Globals? 1 为什么要学习 Globals? 1 试一试: 访问 Globals 的三种方式 2 用前须知 2 导入和检查类定义 2 导入示例数据并检查 Globals 3 关系访问 Globals(Accessing Globals Relationaly) 5 将 Globals 作为对象访问(Accessing Globals as Objects) 6 直接访问 Globals(Accessing Globals Directly) 7 有关 Globals 的更多信息 8 使用 InterSystems IRIS API 访问 Globals 9 了解有关 Globals 的更多信息 10 Globals 及其结构 10 多模型开发 10 InterSystems Native API 10 技术概要: Globals 本文档向您介绍了 globals 的概念,globals是 InterSystems IRIS®数据平台的底层存储结构。我们将向您展示如何使用关系模型和对象模型访问 globals,以及如何直接访问 globals。 要浏览所有的技术概要(First Look),包括可以在 InterSystems IRIS 免费的评估实例上执行的那些 ,请参见 InterSystems First Looks(《InterSystems 技术概要》)。 什么是 Globals? InterSystems IRIS 数据平台的特点之一是它能够一次性存储数据,并允许您使用多个范式(paradigm)来访问它。例如,您可以使用 InterSystems SQL 将数据可视化为行和列,或者您可以使用 ObjectScript 将数据视为具有属性和方法的对象。您的应用程序甚至可以混合使用这两种数据模型,对于给定的任务使用最简单和更有效的模型。但是无论您如何访问数据,InterSystems IRIS 都将其存储在被称为 globals 的底层数据结构中。 Globals 可以被认为是持久化多维稀疏数组(persistent multidimensional sparse arrays): 持久化(Persistent)------Globals 存储在数据库中,可以在任何时候被任何可以访问该数据库的进程(process)检索到。 多维(Multidimensional)------global 节点可以有任意数量的下标。这些下标可以是整数、小数,或字符串。 稀疏(Sparse)------节点下标不必是连续的,这意味着没有存储值的下标不会使用任何存储。 Global 节点可以存储多种类型的数据,包括: 字符串 数字数据 字符或二进制数据流 数据集合,如列表或数组 对其他存储位置的引用 即使是您编写的服务器端代码,最终也存储在 globals 中! 为什么要学习 Globals? 在了解很少或几乎不了解 globals 的情况下,虽然也可以在 InterSystems IRIS 平台上编写应用程序,但出于以下几个原因,您可能想了解有关它们的更多信息: 如果您直接访问 globals,有些操作可能会更容易或更有效。 您可能希望为不符合关系或对象数据模型的数据创建自定义数据结构。 试一试: 访问 Globals 的三种方式 有些系统管理任务是在 global 层面完成的,了解 globals 将使这些任务对您更有意义。 试一试:访问 Globals 的三种方式 在本文档中,您将检查用于存储 U.S. 州类对象的数据的 globals。该类的属性包括州名、双字母邮政缩写、首府、建州年份和面积(单位:平方英里)。然后,您将使用关系和对象技术,以及直接操作 globals 来访问和存储这个类的对象。 用前须知 要使用这个技术概要(First Look),您需要一个正在运行的 InterSystems IRIS 实例。您的选择包括几种类型的已授权的和免费的评估实例;该实例不需要由您正在工作的系统托管(尽管您的系统必须能够通过网络访问该实例)。关于如何部署每种类型的实例的信息(如果您还没有可使用的实例),请参见 InterSystems IRIS Basics: Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中的 Deploying InterSystems IRIS(部署 InterSystems IRIS)。 您也需要知道: 实例的基于 web 的管理门户(Management Portal)的 URL,这是 InterSystems IRIS 的系统管理用户界面。 如何访问终端(Terminal),InterSystems IRIS 命令行工具。 实例的用户名和密码(InterSystems Labs 上的 web 实例不需要)。 您还需要从 InterSystems GitHub repo :https://github.com/intersystems/First- Look-Globals 下载两个示例文件。 FirstLookGlobals.xml 包含 State 类的类定义。 FirstLookGlobals.gof 包含了 U.S. 最初 13 个州的一些 global 示例数据。 关于如何访问管理门户(Management Portal )或终端(Terminal)的更多信息,请参见 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中的"InterSystems IRIS Connection Information(InterSystems IRIS 连接信息)"。您实际上并不需要一个 IDE 来做这些练习。 导入和检查类(Class)定义 首先,将 State 类定义导入 InterSystems IRIS: 从管理门户(Management Portal)的主页,选择 System Explorer(系统资源管理器) > Classes(类)。 在 Classes 页面上,查看左栏,确保您在 USER 命名空间。您可以把命名空间看作是工作空间或目录。 点击 Import(导入)。 在 Import Classes 的对话框中: a. 如果您的 InterSystems IRIS 实例在远程服务器上运行,请指定是将示例文件下载到远程服务器还是下载到您的本地计算机。 b. 在 File 或 Directory 的 Import(导入)区域,点击 File(文件)。 c. 浏览您从 GitHub 下载的 FirstLookGlobals.xml 文件。 试一试: 访问 Globals 的三种方式 d. 选择 Compile Imported Items(编译导入项)。 e. 对于 Compile Flags(编译标志),指定 cuk。 f. 点击 Next(下一步)。 g. 点击 Import(导入)。 h. 当出现加载成功的消息时,点击 Done(完成)。 现在,在 Classes 页面,您应该看到 FirstLook.State.cls 在类的列表中。在 InterSystems IRIS 中,包含类的包名称(FirstLook)附加有类的名称(State)。扩展名 .cls 用来表示类文件。 注意: 如果您的命名空间包含大量的类,可以在页面左栏的 Class Name(类名) 框中输入 F*.cls 来过滤列表。 在 FirstLook.State.cls 类的右侧,点击 Documentation(文档) 来查看为该类生成的文档。 您会注意到的第一件事是 FirstLook.State 类扩展了 %Persistent 类,这意味着该类的数据将存储在数据库中 (系统定义的类和方法通常以 % 开头) 。 persistent class FirstLook.State extends %Persistent 扩展 %Persistent 还提供了一些方法,您可以使用这些方法在该类上执行操作。例如,它允许您创建该类的新对象或从数据库访问对象并将其加载到内存中。 再往下看,您可以看到这个类有五个属性:Area、Capital、Established、Name 和 PostalAbbr。 property Area as %Integer; property Capital as %String; property Established as %Integer; property Name as %String [ Required ]; property PostalAbbr as %String; 这个类还有两个索引,CapitalIndex 和 PostalAbbrIndex,这两个索引可以加快 SQL 查询的速度,并允许您通过首府和邮政缩写快速查找州。 index (CapitalIndex on Capital) [Unique]; index (PostalAbbrIndex on PostalAbbr) [Unique]; 导入示例数据并检查 Globals 要了解存储 State 类对象的 globals,首先要导入一些数据: 从管理门户(Management Portal)的主页,选择 System Explorer(系统资源管理器) > Globals。(或从 Classes 页面,点击 Globals 按钮。) 在 Globals 页面上,查看左栏,确保您在 USER 命名空间。 点击 Import(导入)。 在 Import Globals 对话框中: a. 如果您的 InterSystems IRIS 实例在远程服务器上运行,请指定是将示例文件下载到远程服务器还是下载到您的本地计算机。 b. 浏览您从 GitHub 下载的 FirstLookGlobals.gof 文件。 c. 点击 Next(下一步)。 d. 点击 Import(导入)。 试一试: 访问 Globals 的三种方式 e. 当出现加载成功的消息时,点击 Done(完成)。 现在,在 Globals 页面上,您应该看到 FirstLook.StateD 和 FirstLook.StateI 这两个 globals 在列表中。默认情况下,类(class)的数据存储在名称后面加 Dappended 的 global 中,索引存储在名称后面加 Iappended 的 global 中。最常见的情况是,您会看到 globals 名称前有一个插入符号(\^)。 注意: 如果您的命名空间包含大量的 globals,可以在页面左栏的 Global Name(Global 名称) 框中输入 F* 来过滤这个列表。 在 FirstLook.StateD global 的右边,点击 View(查看) 来显示 global 内容的列表。 \^FirstLook.StateD = 13 \^FirstLook.StateD(1) = $lb("","Delaware","DE","Dover",1787,2489) \^FirstLook.StateD(2) = $lb("","Pennsylvania","PA","Harrisburg",1787,46054) \^FirstLook.StateD(3) = $lb("","New Jersey","NJ","Trenton",1787,8723) \^FirstLook.StateD(4) = $lb("","Georgia","GA","Atlanta",1788,59425) \^FirstLook.StateD(5) = $lb("","Connecticut","CT","Hartford",1788,5543) \^FirstLook.StateD(6) = $lb("","Massachusetts","MA","Boston",1788,10554) \^FirstLook.StateD(7) = $lb("","Maryland","MD","Annapolis",1788,12406) \^FirstLook.StateD(8) = $lb("","South Carolina","SC","Columbia",1788,32020) \^FirstLook.StateD(9) = $lb("","New Hampshire","NH","Concord",1788,9349) \^FirstLook.StateD(10) = $lb("","Virginia","VA","Richmond",1788,42775) \^FirstLook.StateD(11) = $lb("","New York","NY","Albany",1788,54555) \^FirstLook.StateD(12) = $lb("","North Carolina","NC","Raleigh",1789,53819) \^FirstLook.StateD(13) = $lb("","Rhode Island","RI","Providence",1790,1545) 您可以看到,每个状态的节点都有一个整数的下标,称为对象 ID(或简称 ID),它是在您存储这个类的新对象时由系统生成的。Global 的根节点,没有下标,包含一个计数器,该计数器递增以生成下一个 ID。 每个节点的数据按照在类定义中指定的顺序存储为属性列表。如果查看 \^FirstLook.StateD(3),您可以看到州名是新泽西州(New Jersey),邮政缩写是 NJ,首府是特伦顿(Trenton),该州于 1787 年加入联邦(Union),面积为 8723 平方英里。 点击 Cancel(取消) 返回 globals 列表,然后点击 global FirstLook.StateI 旁边的 View(查看) 查看 State 类的索引。 \^FirstLook.StateI("CapitalIndex"," ALBANY",11) = "" \^FirstLook.StateI("CapitalIndex"," ANNAPOLIS",7) = "" \^FirstLook.StateI("CapitalIndex"," ATLANTA",4) = "" \^FirstLook.StateI("CapitalIndex"," BOSTON",6) = "" \^FirstLook.StateI("CapitalIndex"," COLUMBIA",8) = "" \^FirstLook.StateI("CapitalIndex"," CONCORD",9) = "" \^FirstLook.StateI("CapitalIndex"," DOVER",1) = "" \^FirstLook.StateI("CapitalIndex"," HARRISBURG",2) = "" \^FirstLook.StateI("CapitalIndex"," HARTFORD",5) = "" \^FirstLook.StateI("CapitalIndex"," PROVIDENCE",13) = "" \^FirstLook.StateI("CapitalIndex"," RALEIGH",12) = "" \^FirstLook.StateI("CapitalIndex"," RICHMOND",10) = "" \^FirstLook.StateI("CapitalIndex"," TRENTON",3) = "" \^FirstLook.StateI("PostalAbbrIndex"," CT",5) = "" \^FirstLook.StateI("PostalAbbrIndex"," DE",1) = "" \^FirstLook.StateI("PostalAbbrIndex"," GA",4) = "" \^FirstLook.StateI("PostalAbbrIndex"," MA",6) = "" \^FirstLook.StateI("PostalAbbrIndex"," MD",7) = "" \^FirstLook.StateI("PostalAbbrIndex"," NC",12) = "" \^FirstLook.StateI("PostalAbbrIndex"," NH",9) = "" \^FirstLook.StateI("PostalAbbrIndex"," NJ",3) = "" \^FirstLook.StateI("PostalAbbrIndex"," NY",11) = "" \^FirstLook.StateI("PostalAbbrIndex"," PA",2) = "" \^FirstLook.StateI("PostalAbbrIndex"," RI",13) = "" \^FirstLook.StateI("PostalAbbrIndex"," SC",8) = "" \^FirstLook.StateI("PostalAbbrIndex"," VA",10) = "" 仔细看看 global \^FirstLook.StateI 中的第一个节点。这里,第一个下标("CapitalIndex")是索引的名称,第二个下标是被索引的属性的值("ALBANY"),第三个下标是以奥尔巴尼(Albany)为首府的州的 ID(11)。如果您回顾一下 global 数据,您会发现 \^FirstLook.StateD(11) 是纽约州(New York)。 Globals 使用数组下标自动按排序顺序存储。 试一试: 访问 Globals 的三种方式 关系访问 Globals (Accessing Globals Relationally) 现在,看看为 State 类生成的 InterSystems IRIS 表: 从管理门户(Management Portal)的主页,选择 System Explorer(系统资源管理器) > SQL。 在 SQL 页面上,查看页面的顶部,确保您在 USER 名称空间。 如果不是,请点击 Switch(切换)来改更改命名空间。 在左栏中,展开 Tables(表)部分来查看命名空间中的表。 在 Tables 下,点击 FirstLook.State 表。 在 Catalog Details(目录详情) 标签上,点击 Fields(字段),您将看到为 State 类的每个属性生成的字段,以及称为 ID(有时称为 RowID) 的额外字段。 这个字段类似于您在类的 globals 中看到的对象 ID。 注意: 如果您的命名空间包含大量的表,可以在页面左栏的 Filter(过滤) 框中输入 F* 来过滤列表。 点击 Execute Query(执行查询) 标签,打开一个文本区,您可以在这里编写针对 FirstLook.State 表运行的查询。 输入以下查询: SELECT * FROM FirstLook.State WHERE ID = 6 并点击 Execute(执行)。该查询返回您请求的马萨诸塞州(Massachusetts )的行。 输入以下查询: INSERT INTO FirstLook.State(Area, Capital, Established, Name, PostalAbbr) VALUES (9616, 'Montpelier', 1791, 'Vermont', 'VT') 并点击 Execute(执行),将一行插入第 14 个州佛蒙特州(Vermont )的表中。 要查看在 FirstLook.State 表中插入一行的效果,请返回到命名空间 USER 的 Globals 页面,并再次查看 globals。 从管理门户(Management Portal)的主页,选择 System Explorer(系统资源管理器) > Globals。 在 Globals 页面上,查看左栏,确保您在 USER 命名空间。 查看数据 global,\^FirstLook.StateD,您可以看到 ID 计数器已经增加: \^FirstLook.StateD = 14 并且一个新的节点被添加到 global: \^FirstLook.StateD(14) = $lb("","Vermont","VT","Montpelier",1791,9616) 查看索引 global,\^FirstLook.StateI,可以看到索引已经被更新为两个新节点: \^FirstLook.StateI("CapitalIndex"," MONTPELIER",14) = "" 和 \^FirstLook.StateI("PostalAbbrIndex"," VT",14) = "" 试一试: 访问 Globals 的三种方式 将 Globals 作为对象访问(Accesing Globals as Objects) 请记住,当您创建 State 类时,扩展了类 %Persistent,这使您可以访问一些有用的方法,这些方法使您可以在类的 globals 中存储数据并再次检索它。接下来,通过在 InterSystems 终端(Terminal)中编写一些 ObjectScript 来测试其中一些方法。如果您以前没有使用过终端(Terminal),请参见 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中的"InterSystems IRIS Connection Information(InterSystems IRIS 连接信息"。 在您启动 Terminal session (终端会话)后,您应该看到一个提示符,指示您所处的名称空间。如果您不在 USER 命名空间,执行以下命令: set $namespace = "USER" 首先,将您刚刚用 SQL 查询添加的佛蒙特州(Vermont)的数据加载到内存中。调用 FirstLook.State 类的 %OpenId() 方法,并将返回值赋给变量 vt。%OpenId() 返回对象的"句柄(handle)",更正式地称为对象引用或 OREF。 USER>set vt = ##class(FirstLook.State).%OpenId(14) 您可以通过访问对象的 Name 属性来查看刚刚加载的状态的名称: USER>write vt.Name Vermont 您可以使用 zwrite 命令获取所有对象属性的摘要。该命令提供的其他信息超出了本文档的范围。 USER>zwrite vt vt=2@FirstLook.State ; <OREF> +----------------- general information --------------- | oref value: 2 | class name: FirstLook.State | %%OID: $lb("14","FirstLook.State") | reference count: 2 +----------------- attribute values ------------------ | %Concurrency = 1 <Set> | Area = 9616 | Capital = "Montpelier" | Established = 1791 | Name = "Vermont" | PostalAbbr = "VT" +----------------------------------------------------- 要创建一个新的 State 对象,请使用 %New() 方法,该方法将一个 OREF 返回给新对象。 USER>set newstate = ##class(FirstLook.State).%New() 现在,设置第 15 个州肯塔基州(Kentucky)的属性。USER>set newstate.Name = "Kentucky" USER>set newstate.PostalAbbr = "KY" USER>set newstate.Capital = "Frankfort" USER>set newstate.Established = 1792 USER>set newstate.Area = 40408 检查所有属性。 试一试: 访问 Globals 的三种方式 USER>zwrite newstate newstate=4@FirstLook.State ; <OREF> +----------------- general information --------------- | oref value: 4 | class name: FirstLook.State | reference count: 2 +----------------- attribute values ------------------ | %Concurrency = 1 <Set> | Area = 40408 | Capital = "Frankfort" | Established = 1792 | Name = "Kentucky" | PostalAbbr = "KY" +----------------------------------------------------- 如果您对一切看起来很满意,通过调用新对象的 %Save() 方法将对象保存到磁盘。%Save() 方法返回一个状态,如果保存成功,该状态的值为 1。 USER>set status = newstate.%Save() USER>write status 1 再一次,通过进入管理门户(Management Portal)中的 Globals 页面来检查您的工作。查看数据 global, \^FirstLook.StateD,您可以看到 ID 计数器再次增加: \^FirstLook.StateD = 15 并且一个新的节点被添加到 global: \^FirstLook.StateD(15) = $lb("","Kentucky","KY","Frankfort",1792,40408) 查看索引 global,\^FirstLook.StateI,可以看到索引已经被更新为两个新节点: \^FirstLook.StateI("CapitalIndex"," FRANKFORT",15) = "" 和 \^FirstLook.StateI("PostalAbbrIndex"," KY",15) = "" 直接访问 Globals(Accessing Globals Directly) 虽然 InterSystems IRIS 中的数据最常见的是通过 SQL 或使用对象层来访问,但您也可以直接访问扩展 %Persistent 的类的 globals。这种方法比较棘手,因为您需要知道 global 的结构。 首先,找到 ID 为 15 的州名称。 在终端(Terminal)中,用下标 15 将变量 ky 赋给数据 global 中的节点。 USER>set ky = \^FirstLook.StateD(15) 您可以使用 zwrite 检查存储在这个节点上的值: USER>zwrite ky ky=$lb("","Kentucky","KY","Frankfort",1792,40408) 接下来,使用 $list() 函数来获取列表中的第二项: USER>write $list(ky, 2) Kentucky 根据您在使用 SQL 或对象方法添加状态后检查 globals 所学到的内容,编写一些代码来添加新状态。 首先,准备数据,将每个属性(从对象的角度考虑)或字段(从 SQL 的角度考虑)放入不同的变量。 试一试: 访问 Globals 的三种方式 USER>set name = "Tennessee" USER>set postalabbr = "TN" USER>set capital = "Nashville" USER>set established = 1796 USER>set area = 42144 然后使用 $listbuild() 函数构建可以存储的属性列表。 USER>set properties = $listbuild("", name, postalabbr, capital, established, area) USER>zwrite properties properties=$lb("","Tennessee","TN","Nashville",1796,42144) 使用一个 ObjectScript 语句,增加 \^FirstLook.StateD global 的 ID 计数器,并将新值赋给变量 id。 USER>set id = $increment(\^FirstLook.StateD) USER>write \^FirstLook.StateD 16 USER>write id 16 现在,将数据存储在数据 global 中。 USER>set \^FirstLook.StateD(id) = properties USER>zwrite \^FirstLook.StateD(id) \^FirstLook.StateD(16)=$lb("","Tennessee","TN","Nashville",1796,42144) 现在我们需要手动更新索引,否则在首府(Capital )或邮政缩写(PostalAbbr)上,带有 WHERE 子句的 SQL 查询将不包括田纳西州(Tennessee)。这个过程比存储数据要复杂一些。 对于字符串值(string value)的索引,InterSystems IRIS 将字符串转换为大写字母,并在前面添加一个空格字符,以便于排序。使用 _运算符将一个空格连接到大写字母的前面,然后使用 $zconvert() 函数将其转换为大写字母。然后对邮政缩写执行相同操作。 USER>set capital = $zconvert(" "_capital, "U") USER>set postalabbr = $zconvert(" "_postalabbr, "U") 最后,将索引条目存储在索引 global 中。 USER>set \^FirstLook.StateI("CapitalIndex", capital, id) = "" USER>set \^FirstLook.StateI("PostalAbbrIndex", postalabbr, id) = "" 为确保您正确完成工作,请进入管理门户(Management Portal)中的 Globals 页面,并查看 \^FirstLook.StateD 和 \^FirstLook.StateI globals。您也可以使用 zwrite \^FirstLook.StateD 和 zwrite \^FirstLook.StateI 从终端(Terminal)显示每个 global 的完整内容。 有关 Globals 的更多信息 使用 SQL 创建 Globals 在本文档中,您所看到的 globals 是通过存储使用类定义(class definition)指定的类的对象(object)创建的。您可以通过使用 SQL 创建表和表的索引来创建结构非常相似的 globals。然后,InterSystems IRIS 将根据您创建的表为您生成一个类。 作为练习,进入管理门户(Management Portal)中 USER 命名空间的 SQL 页面,并使用 Execute Query(执行查询)标签执行下列语句。 使用 InterSystems IRIS API 访问 Globals CREATE TABLE FirstLook.SQL (%CLASSPARAMETER USEEXTENTSET 0, %CLASSPARAMETER DEFAULTGLOBAL = '\^FirstLook.SQL', Name CHAR(30) NOT NULL, PostalAbbr CHAR(2), Capital CHAR(30), Established INT, Area INT) CREATE UNIQUE INDEX CapitalIndex ON FirstLook.SQL (Capital) CREATE UNIQUE INDEX PostalAbbrIndex ON FirstLook.SQL (PostalAbbr) INSERT INTO FirstLook.SQL (Name, PostalAbbr, Capital, Established, Area) VALUES ('Maine', 'ME', 'Augusta', 1820, 35380) 在 SQL 页面的左栏中,您现在应该看到 FirstLook.SQL 表。 进入 Classes 页面,找到类 FirstLook.SQL.cls 并查看其文档。您注意到有什么不同吗?这个类有一个额外的索引,称为位图扩展索引(Bitmap Extent Index)。然后进入 Globals 页面,找到 \^FirstLook.SQLD 和 \^FirstLook.SQLI globals。看看 \^FirstLook.SQLI,并看看您是否能找到额外的索引。 创建自定义 Globals 到目前为止,您已经看到了扩展 %Persistent 类时创建的 globals。但是,globals 可用于存储无模式的数据,这些数据可能不适合类或关系范式。例如,使用终端(Terminal)或管理门户(Management Portal),切换到 %SYS 命名空间,并检查 \^CONFIGglobal,它存储了一些 InterSystems IRIS 配置设置。下面是 \^CONFIGglobal 示例的一部分: \^CONFIG("Cluster","CommIPAddress") = "" \^CONFIG("Cluster","JoinCluster") = 0 \^CONFIG("ConfigFile","Version") = "2018.20" \^CONFIG("Conversions","LastConvertTime") = "2019-03-13 08:39:45" \^CONFIG("Databases","ENSLIB") = "/usr/irissys/mgr/enslib/" \^CONFIG("Databases","IRISAUDIT") = "/usr/irissys/mgr/irisaudit/" \^CONFIG("Databases","IRISLIB") = "/usr/irissys/mgr/irislib/" \^CONFIG("Databases","IRISLOCALDATA") = "/usr/irissys/mgr/irislocaldata/" \^CONFIG("Databases","IRISSYS") = "/usr/irissys/mgr/" \^CONFIG("Databases","IRISTEMP") = "/usr/irissys/mgr/iristemp/" \^CONFIG("Databases","USER") = "/usr/irissys/mgr/user/" 如果您想创建和存储自己的自定义数据结构,您可以使用 ObjectScript 轻松做到。使用下面的示例,您可以编写几行代码定义一个有向图来存储机场之间的机票价格: USER>set \^Fares("BOS", "ORD") = 87 USER>set \^Fares("ORD", "BOS") = 63 USER>set \^Fares("BOS", "LAX") = 143 USER>set \^Fares("LAX", "BOS") = 143 USER>set \^Fares("ORD", "LAX") = 57 USER>set \^Fares("LAX", "ORD") = 94 USER>zwrite \^Fares \^Fares("BOS","LAX")=143 \^Fares("BOS","ORD")=87 \^Fares("LAX","BOS")=143 \^Fares("LAX","ORD")=94 \^Fares("ORD","BOS")=63 \^Fares("ORD","LAX")=57 使用 InterSystems IRIS API 访问 Globals 如果您正在用 Java、.NET、Node.js 或 Python 编写应用程序,InterSystems IRIS 提供的 API 允许您使用本文中讨论的三种模型来操作您的数据库: 通过 JDBC、ADO.NET 或 PyODBC API 进行关系访问 通过 InterSystems XEP API 访问对象 通过 InterSystems Native API 直接访问 globals 了解有关 Globals 的更多信息 现在您知道了,无论您决定如何存储或访问数据,您所做的就是使用 globals。 注意: 并非所有语言都支持所有形式的访问。 了解有关 Globals 的更多信息 使用下面列出的参考资料来了解更多有关 globals 和如何访问它们的信息。 Globals 及其结构 Globals QuickStart(Globals 快速入门)------提供 global 结构的可视化视图,并给出在自定义 global 结构中存储数据的示例。 Using Globals(《使用 Globals》)------讨论 Globals 的结构、如何管理它们以及如何使用 SQL 或 ObjectScript 访问它们。 Globals------Defining and Using Classes(定义和使用类)这部分解释了为扩展 %Persistent 类的类创建的 globals 的命名约定。 多模型开发 Multi-Model QuickStart(多模型快速入门)------描述了 InterSystems IRIS 如何允许您用各种不同的语言(包括 Java、.NET 和 ObjectScript)使用您选择的数据模型。 Java QuickStart(Java 快速入门)------向您展示如何使用 Java API 对 InterSystems IRIS 数据库进行关系、对象和直接访问。 .NET QuickStart(.NET 快速入门)------向您展示如何使用 .NET API 对 InterSystems IRIS 数据库进行关系、对象和直接访问。 Python QuickStart(Python 快速入门)------向您展示如何使用 Python API 对 InterSystems IRIS 数据库进行关系、对象和直接访问。 InterSystems Native API Using the Native API for Java(《使用 Native API for Java》) (交互式课程)------向您展示如何使用 Native API for Java 访问 globals 以及调用类方法(call class method)和例程。 Using the Native API for Java(《使用 Native API for Java 》)(书籍)------向您展示如何使用 Native API for Java 访问 globals 以及调用类方法(call class method)和例程。 First Look: InterSystems IRIS Native API for Java(《技术概要:InterSystems IRIS Native API for Java》) --- 展示如何从 Java 应用程序访问 InterSystems IRIS globals。 Using the Native API for .NET(《使用 Native API for .NET》 )(交互式课程)------向您展示如何使用 Native API for .NET 访问 globals 以及调用类方法(call class method)和例程。 Using the InterSystems Native API for .NET(《使用 InterSystems Native API for .NET》)(书籍)------向您展示如何使用 Native API for .NET 访问 globals 以及调用类方法(call class method)和例程。 First Look: InterSystems IRIS Native API for .NET(《技术概要:InterSystems IRIS Native API for .NET》) ------展示如何从 .NET 应用程序访问 InterSystems IRIS globals。 了解有关 Globals 的更多信息 Node.js QuickStart(Node.js 快速入门)------向您展示如何使用 Native API for Node.js 访问 globals 以及调用类方法(call class method)和例程。 Using the Native API for Node.js(《使用 Native API for Node.js》)------向您展示如何使用 Native API for Python 访问 globals 以及调用类方法(call class method)和例程。 First Look: InterSystems IRIS Native API for Node.js(《技术概要:InterSystems IRIS Native API for Node.js》)-展示如何从 Node.js 应用程序访问 InterSystems IRIS globals。 Using the Native API for Python(《使用 Native API for Python》) (交互式课程)------向您展示如何使用 Native API for Python 访问 globals 以及调用类方法(call class method)和例程。 Using the Native API for Python(《使用 Native API for Python》) (书籍)------向您展示如何使用 Native API for Python 访问 globals 以及调用类方法(call class method)和例程。 First Look: InterSystems IRIS Native API for Python(《技术概要:InterSystems IRIS Native API for Python》)------展示如何从 Python 应用程序访问 InterSystems IRIS globals。
文章
Tete Zhang · 二月 20, 2023

OpenAPI-Suite(从 OpenAPI 3.0 生成 ObjectScript 代码的工具集):介绍 InterSystems 开发人员工具大赛 2023 获奖者

开发者您好! 这里向介绍@Lorenzo Scalese的OpenAPI-Suite (一个用于从OpenAPI 3.0生成 ObjectScript 代码的工具集)。这个工具集在 2023 年 InterSystems 开发工具大赛的21 个参赛作品中获得专家提名第三名。 目前 IRIS 最高支持OpenAPI 2.0 ,但是这个工具支持 OpenAPI 3.0 ! 提供的功能如下。 在服务器端创建类(与 OpenAPI 2.0相同,首先创建使用 API First理念创建的 REST 调度类所需的类。) 创建客户端 HTTP 类 创建客户端Production(业务服务、业务流程、业务操作、Ens.Request、Ens.Response) 一个 Web 界面,允许您指定要从此工具生成哪些功能 从 OpenAPI 1.x、2.x 到 3.0 版的转换工具 关于各个功能的详细介绍,请参考@Lorenzo Scales撰写的文章《 OpenAPI Suite - Part 1 》和《 OpenAPI Suite - Part 2 》。 在本文中,我尝试了 1 个功能。其中,以下的应对方案非常好。 根据OpenAPI 3.0新增的Components对象的内容自动生成类的定义(在指定包下创建一个模型包,在那里创建可以实例化的类) 在POST或PUT的情况下,为了较为轻松地使用实施类(impl.cls)处理HTTP请求中传递的信息,我将Body中接收到的JSON数据设为了1中生成的类的实例, 目前,虽然需要进行一些手动更改,但是仅使用按原样创建的实例在 impl.cls 中叫 %Save() 方法也可以保存成功。 ) IRIS 提供了一种根据 OpenAPI 2.0 规范创建 REST 调度类的方法,但实际使用中它只创建要使用的类和根URL。 仅作为参考,这里是使用 IRIS 支持的 OpenAPI 2.0 创建的内容。 (以下示例使用了根据 OpenAPI2.0 规范创建的 JSON 示例。) 在下面的示例中,/crud 是根 URL,类是在 crud 包下创建的。​​​​​​ 生成的类如下(左:impl.cls,右:spec.cls) 由于调度类(disp.cls)是一个不需要改动的类,所以这里展示了studio的这部分代码。 接下来介绍一下@Lorenzo Scalese的OpenAPI-Suite的成果。 使用它的过程非常简单。 从管理门户或Studio导入IPM (InterSystems Package Manager,以前称为 ZPM)客户端工具后,您只需运行以下命令,工具就可以使用了。 客户端工具导入可以导入到任意命名空间中。 从管理门户导入时,使用以下菜单: 管理门户 -> 系统资源管理器 -> 类 -> 选择要导入的命名空间 -> 单击导入按钮 转到您希望 REST 调度类存在的命名空间,并使用 ZPM 命令安装工具。 zpm "install openapi-suite" 安装过程中的画面显示 USER>zpm “安装 openapi-suite” [USER|sslclient] 重新加载开始 (/usr/irissys/mgr/.modules/USER/sslclient/1.0.4/)[用户|sslclient] 重新加载成功[sslclient] 模块对象已刷新。[USER|sslclient] 验证开始[USER|sslclient] 验证成功[USER|sslclient] 编译开始[用户|sslclient] 编译成功[USER|sslclient] 激活开始[USER|sslclient] 配置开始[用户|sslclient] 配置成功[USER|sslclient] 激活成功[USER|yaml-utils] 重新加载开始 (/usr/irissys/mgr/.modules/USER/yaml-utils/0.1.2/)[USER|yaml-utils] 重新加载成功[yaml-utils] 模块对象已刷新。[USER|yaml-utils] 验证开始[USER|yaml-utils] 验证成功[USER|yaml-utils] 编译开始[USER|yaml-utils] 编译成功[USER|yaml-utils] 激活开始[USER|yaml-utils] 配置开始[USER|yaml-utils] 配置成功[USER|yaml-utils] 激活成功[USER|swagger-validator-cli] 重新加载开始 (/usr/irissys/mgr/.modules/USER/swagger-validator-cli/0.0.1/)[USER|swagger-validator-cli] 重新加载成功[swagger-validator-cli] 模块对象已刷新。[USER | swagger-validator-cli] 验证开始[USER|swagger-validator-cli] 验证成功[USER|swagger-validator-cli] 编译开始[USER|swagger-validator-cli] 编译成功[USER|swagger-validator-cli] 激活 START[USER|swagger-validator-cli] 配置开始[USER|swagger-validator-cli] 配置成功[USER|swagger-validator-cli] 激活成功[USER|swagger-converter-cli] 重新加载开始 (/usr/irissys/mgr/.modules/USER/swagger-converter-cli/0.0.2/)[USER|swagger-converter-cli] 重新加载成功[swagger-converter-cli] 模块对象已刷新。[USER | swagger-converter-cli] 验证开始[USER|swagger-converter-cli] 验证成功[USER|swagger-converter-cli] 编译开始[USER|swagger-converter-cli] 编译成功[USER|swagger-converter-cli] 激活开始[USER|swagger-converter-cli] 配置开始[USER|swagger-converter-cli] 配置成功[USER|swagger-converter-cli] 激活成功[USER|objectscript-openapi-definition] 重新加载开始 (/usr/irissys/mgr/.modules/USER/objectscript-openapi-definition/1.3.1/)[USER|objectscript-openapi-definition] 重新加载成功[objectscript-openapi-definition] 模块对象已刷新。[USER|objectscript-openapi-definition] 验证开始[USER|objectscript-openapi-definition] 验证成功[USER|objectscript-openapi-definition] 编译开始[USER|objectscript-openapi-definition] 编译成功[USER|objectscript-openapi-definition] 激活开始[USER|objectscript-openapi-definition] 配置开始[USER|objectscript-openapi-definition] 配置成功[USER|objectscript-openapi-definition] 激活成功[USER|io-redirect] 重新加载开始 (/usr/irissys/mgr/.modules/USER/io-redirect/1.0.2/)[USER|io-redirect] 重新加载成功[io-redirect] 模块对象已刷新。[USER|io-redirect] 验证开始[USER|io-redirect] 验证成功[USER|io-redirect] 编译开始[USER|io-redirect] 编译成功[USER|io-redirect] 激活开始[USER|io-redirect] 配置开始[USER|io-redirect] 配置成功[USER|io-redirect] 激活成功[USER|openapi-common-lib] 重新加载开始 (/usr/irissys/mgr/.modules/USER/openapi-common-lib/1.0.0/)[用户|openapi-common-lib] 重新加载成功[openapi-common-lib] 模块对象已刷新。[USER|openapi-common-lib] 验证开始[USER|openapi-common-lib] 验证成功[USER|openapi-common-lib] 编译开始[USER|openapi-common-lib] 编译成功[USER|openapi-common-lib] 激活开始[USER|openapi-common-lib] 配置开始[USER|openapi-common-lib] 配置成功[USER|openapi-common-lib] 激活成功[USER|openapi-server-gen] 重新加载开始 (/usr/irissys/mgr/.modules/USER/openapi-server-gen/1.0.0/)[USER|openapi-server-gen] 重新加载成功[openapi-server-gen] 模块对象已刷新。[USER|openapi-server-gen] 验证开始[USER|openapi-server-gen] 验证成功[USER|openapi-server-gen] 开始编译[USER|openapi-server-gen] 编译成功[USER|openapi-server-gen] 激活开始[USER|openapi-server-gen] 配置开始[USER|openapi-server-gen] 配置成功[USER|openapi-server-gen] 激活成功[USER|openapi-client-gen] 重新加载开始 (/usr/irissys/mgr/.modules/USER/openapi-client-gen/2.1.0/)[USER|openapi-client-gen] 重新加载成功[openapi-client-gen] 模块对象已刷新。[USER|openapi-client-gen] 验证开始[USER|openapi-client-gen] 验证成功[USER|openapi-client-gen] 编译开始[USER|openapi-client-gen] 编译成功[USER|openapi-client-gen] 激活开始[USER|openapi-client-gen] 配置开始[USER|openapi-client-gen] 配置成功[USER|openapi-client-gen] 激活成功[USER|openapi-suite] 重新加载开始 (/usr/irissys/mgr/.modules/USER/openapi-suite/1.0.0/)[用户|openapi-suite] 重新加载成功[openapi-suite] 模块对象已刷新。[USER | openapi-suite] 验证开始[USER|openapi-suite] 验证成功[USER|openapi-suite] 编译开始[USER|openapi-suite] 编译成功[USER | openapi-suite] 激活开始[USER|openapi-suite] 配置开始[USER|openapi-suite] 配置成功[USER|openapi-suite] 激活成功用户> 安装后,您可以通过以下 URL 访问该工具的相关信息。 http://localhost:端口号/openapisuite/ui/index.csp 示例)http://localhost:52773/openapisuite/ui/index.csp 在初始阶段,屏幕右下方的“Install On Server”按钮无法按下。似乎可以通过将值设置为以下全局变量来按下按钮。 (请在你安装工具的命名空间中用ZPM命令设置) Set ^openapisuite .config( "web" , "enable-install-onserver" ) = 1 准备工作完成后,进行以下设置。 对于“Application package name”,选择类定义的包名称(示例中的 PetStore);对于“What do you want to generate?”问题,选择“REST Server”;对于“NameSpace”,选择要注册 REST 调度类的命名空间;对于“Web 应用程序名称”,指定已定义的根 URL(Web 应用程序路径)(示例中的 /pet1)。 之后,只需指定根据OpenAPI规范创建的JSON文件即可。示例中默认指定https://petstore3.swagger.io/api/v3/openapi.json ,我们可以直接使用这个文件路径。 最后,单击 Install On Server 按钮。 日志如下图所示,确认正常结束后点击关闭按钮。 通过该工具,将创建一个 Web 应用程序路径:/pet1。 从管理门户 -> 系统管理 -> 安全 -> 应用程序 -> Web 应用程序检查 /pet1 是否存在。 定义完成! 现在,让我们检查是否已经创建了记载输入路径对应的方法的disp(调度类)和实施代码的impl类。 类定义已经在 PetStore 包下创建完成! 与IRIS提供的OpenAPI 2.0的类不同的是,这里包含了model包和requests包。 在这个工具中,OpenAPI 3.0的Components对象中指定的信息被创建为可以生成实例的类定义。 (它继承了 %RegisteredObject 类) Components对象Pet的信息可以在下方展开查看。 Components:Pet的规格 "Pet":{ "required":[ "name", "photoUrls" ], "type":"object", "properties":{ "id":{ "type":"integer", "format":"int64", "example":10 }, "name":{ "type":"string", "example":"doggie" }, "category":{ "$ref":"#/components/schemas/Category" }, "photoUrls":{ "type":"array", "xml":{ "wrapped":true }, "items":{ "type":"string", "xml":{ "name":"photoUrl" } } }, "tags":{ "type":"array", "xml":{ "wrapped":true }, "items":{ "$ref":"#/components/schemas/Tag" } }, "status":{ "type":"string", "description":"pet status in the store", "enum":[ "available", "pending", "sold" ] } }, "xml":{ "name":"pet" } }, 根据此信息创建的类如下: 它在可以实例化的类中。 如果将super class从 %RegisteredObject 更改为 %Persistent 并编译,则可以将其用作可以在数据库中持久化储存的类。 此外,POST 请求将发送以下格式的 JSON 对象。 { "id": 0, "category": { "id": 0, "name": "Dog" }, "name": "Hachi", "photoUrls": [ "https://x.gd/1pbYK" ], "tags": [ { "id": 0, "name": "Middle" } ], "status": "available" } 能够将此 JSON 直接作为 Pet、Tag 和 Category 类下的实例会很好,因此又追加继承了 %JSON.Adaptor 。 另外,如果我要修改 Pet、Tag 和 Category,最好将super class的配置从 %RegisteredObject 更改为 %Persistent 和 %JSON.Adaptor 的多重继承。 在此之后,需要将接收到的Body信息更新到数据库中。 Request包下的类描述了这个过程的概要。以下示例显示了在向 /pet 发出 POST 请求时运行的类 (PetStore.requests.addPet.cls) 的内容。 如果你注意LoadFromRequest()方法,你会发现它在把可以处理HTTP请求的%request传递给参数request(在IRIS的REST调度类内部处理时,HTTP请求存储在%CSP.Request的一个实例中)。 request.Content 上面的执行可以得到Body中指定的JSON对象。 Do ..PetNewObject (). %JSONImport (request.Content) 这个类中虽然调用了以上方法,但由于该类中实际上并没有PetNewObject()方法,所以做了如下修改(生成一个Pet实例,将其设置为属性Pet,然后将接收到的JSON分配给实例处理)。 set ..Pet = ##class (PetStore.model.Pet). %New () do ..Pet . %JSONImport (request.Content) 这样就完成了接收到 HTTP 请求时的处理。剩下的就是impl.cls的实现了。 在初始状态下,以下方法没有任何描述。 ClassMethod addPet(messageRequest As PetStore.requests.addPet) As %Status { ; Implement your service here. ; Return {} $$$ThrowStatus ( $$$ERROR ( $$$NotImplemented )) } 参数 messageRequest 指定了 PetStore.requests.addPet 类的一个实例,该实例在之前的流程中得到确认(根据 HTTP 请求中收到的 JSON 对象创建的实例在该实例的 Pet 属性中设置。) 改写如下,编译,大功告成! ClassMethod addPet(messageRequest As PetStore.requests.addPet) As %Status { ;Implement your service here. ; Return {} //$$$ThrowStatus($$$ERROR($$$NotImplemented)) set status= $$$OK set status=messageRequest.Pet. %Save () return status } 让我们来测试 POST 请求。 Pet、Category、和Tag都注册并添加数据成功了! 这个用例还是需要一些手动修改,但当我发现类定义是通过 OpenAPI 3.0 Components 对象自动生成的,让我觉得很便利! 大家也请试用一下。
文章
姚 鑫 · 一月 22, 2022

第三十一章 SQL函数 CONVERT

# 第三十一章 SQL函数 CONVERT 将给定表达式转换为指定数据类型的函数。 ```java CONVERT(datatype,expression[,format-code]) {fn CONVERT(expression,datatype)} ``` # 参数 - `expression` - 要转换的表达式。 - `datatype` - 要将表达式转换为的数据类型。 - `format` - 可选-指定日期和时间格式的整数代码,用于在日期/时间/时间戳数据类型和字符数据类型之间进行转换。 此参数仅用于通用标量语法形式。 # 描述 这里描述了`CONVERT`函数的两种不同实现。 两者都将一种数据类型中的表达式转换为另一种数据类型中的相应值。 两者都执行日期和时间转换。 注意:这两个`CONVERT`实现中的参数以不同的顺序表示。 第一个是与MS SQL Server兼容的通用 IRIS标量函数,它接受三个参数。 第二个是带有两个参数的 ODBC标量函数。 下面的文本将分别处理这两种形式的`CONVERT`。 - `CONVERT(datatype,expression)`支持流数据的转换。 例如,可以将字符流字段的内容转换为数据类型为`VARCHAR`的字符串。 - `{fn CONVERT(expression,datatype)}`不支持流数据的转换; 指定要表达的流字段将导致`SQLCODE -37`错误。 为两个版本的`CONVERT`指定一个无效值将导致`SQLCODE -141`。 如果表达式没有定义的数据类型(例如ObjectScript提供的主机变量),则其数据类型默认为字符串数据类型。 # CONVERT(datatype,expression,format-code) 可以通过执行`VARCHAR-to-VARCHAR`转换来截断字符串,指定输出字符串长度小于表达式字符串长度。 在使用`CONVERT`(或`CAST`)时,如果字符数据类型(如`CHAR`或`VARCHAR`)没有指定长度,则默认的最大长度为`30`个字符。 如果二进制数据类型(如`binary`或`VARBINARY`)没有指定长度,则默认的最大长度为`30`个字符。 否则,这些没有指定长度的数据类型将被映射到一个`1`个字符的`MAXLEN`,如`data types`表所示。 可以执行`BIT`数据类型转换。 允许的值为`1`、`0`或`NULL`。 如果指定任何其他值,IRIS将发出`SQLCODE -141`错误。 在下面的嵌入式SQL示例中,两者都是一个`NULL`的`BIT`转换: ```java ClassMethod Convert() { s a="" &sql( SELECT CONVERT(BIT,:a), CONVERT(BIT,NULL) INTO :x,:y) w !,"SQLCODE=",SQLCODE w !,"the host variable is:",x w !,"the NULL keyword is:",y } ``` 可选的`format-code`参数指定日期、`datetime`或时间格式。 该格式既可用于定义从日期/时间/时间戳数据类型转换为字符串时的输出,也可用于定义从字符串转换为日期/时间/时间戳数据类型时的输入。 支持以下格式代码; 输出两位数年份的格式代码列在第一列; 输出四位数年或不输出年的格式列在第二列: Two-digit year codes| Four-digit year codes| Format ---|---|--- |0 or 100 |Mon dd yyyy hh:mmAM (or PM) 1| 101 |mm/dd/yy 2| 102 |yy.dd.mm 3| 103 |dd/mm/yy 4| 104 |dd.mm.yy 5| 105 |dd-mm-yy 6| 106 |dd Mon yy 7| 107 |Mon dd, yy (no leading zero when dd < 10) | 8 or 108| hh:mm:ss | 9 or 109| Mon dd yyyy hh:mm:ss:nnnAM (or PM) 10| 110 |mm-dd-yy 11| 111 |yy.mm.dd 12| 112 |yymmdd |13 or 113| dd Mon yyyy hh:mm:ss:nnn (24 hour) |14 or 114| hh:mm:ss.nnn (24 hour) |20 or 120| yyyy-mm-dd hh:mm:ss (24 hour) |21 or 121| yyyy-mm-dd hh:mm:ss.nnnn (24 hour) |126| yyyy-mm-ddThh:mm:ss,nnnn (24 hour) |130| dd Mon yyyy hh:mm:ss:nnnAM (or PM) |131| dd/mm/yyyy hh:mm:ss:nnnAM (or PM) 以下是日期和时间转换的特性: - 取值范围:允许的日期范围为`0001-01-01 ~ 9999-12-31`。 - 默认值: - 将时间值转换为`TIMESTAMP`、`POSIXTIME`、`DATETIME`或`SMALLDATETIME`时,日期默认为`1900-01-01`。 注意,对于`{fn CONVERT()}`,日期默认为`1841-01-01`。 - 将日期值转换为`TIMESTAMP`、`POSIXTIME`、`DATETIME`或`SMALLDATETIME`时,时间默认为`00:00:00`。 - `Default Format`:如果没有指定`Format -code`, `CONVERT`将尝试从指定的值确定格式。 如果不能,则默认为格式代码`100`。 - 两位数年份:从00到49的两位数年份转换为21世纪的日期(2000到2049); 从50到99的两位数年份转换为20世纪的日期(1950到1999)。 - 分数秒:分数秒前可以加句号(`.`)或冒号(`:`)。 这些符号有不同的含义: - 句点是默认值,可用于所有格式代码。 句号表示标准分数; 因此,`12:00:00.4`表示十分之四秒,而`12:00:00.004`表示千分之四秒。 分数精度的位数没有限制。 - 冒号只能用于以下格式代码值:`9/109`、`13/113`、`14/114`、`130和131`。 冒号表示后面的数字是千分之一秒; 因此`12:00:00:4`表示四万分之一秒(`12:00:00.004`)。 冒号后面的数字限制为3位。 当指定表达式的格式无效或格式与格式代码不匹配时,将产生`SQLCODE -141`错误。 指定一个不存在的格式代码将返回`1900-01-01 00:00:00`。 # {fn CONVERT(expression,datatype)} 这是ODBC标量函数。 它支持以下ODBC显式数据类型转换。 必须使用“SQL_”关键字指定这种形式的`CONVERT`的数据类型转换。 在下表中,有两组转换数据类型,第一组转换数据值和数据类型,第二组转换数据类型,但不转换数据值: Source | Conversion ---|--- Any numeric data type| SQL_VARCHAR, SQL_DOUBLE, SQL_DATE, SQL_TIME %String |SQL_DATE, SQL_TIME, SQL_TIMESTAMP %Date| SQL_VARCHAR, SQL_POSIXTIME, SQL_TIMESTAMPSQL_INTEGER, SQL_BIGINT, SQL_SMALLINT, SQL_TINYINT, SQL_DATE %Time| SQL_VARCHAR, SQL_POSIXTIME, SQL_TIMESTAMP SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT,SQL_SMALLINT, SQL_TINYINT, SQL_TIME %PosixTime| SQL_TIMESTAMP, SQL_DATE, SQL_TIME SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT, SQL_SMALLINT, SQL_TINYINT %TimeStamp |SQL_POSIXTIME, SQL_DATE, SQL_TIME SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT, SQL_SMALLINT, SQL_TINYINT Any non-stream data type| SQL_INTEGER, SQL_BIGINT, SQL_SMALLINT, SQL_TINYINT Any non-stream data type| SQL_DOUBLE `SQL_VARCHAR`是标准的ODBC表示。 在转换为`SQL_VARCHAR`时,日期和时间被转换为相应的ODBC表示; 数字数据类型值转换为字符串表示。 从`SQL_VARCHAR`转换时,该值必须是有效的ODBC `Time`、`Timestamp`或`Date`表示。 - 当将时间值转换为`SQL_TIMESTAMP`或`SQL_POSIXTIME`时,未指定的日期默认为`1841-01-01`。 注意,对于`CONVERT()`,日期默认为`1900-01-01`。 - 将`date`值转换为`SQL_TIMESTAMP`或`SQL_POSIXTIME`时,时间默认为`00:00:00`。 在这种语法形式中,小数秒前面可以加句号(`.`)或冒号(`:`)。 这些符号有不同的含义。 句号表示标准分数; 因此,`12:00:00.4`表示十分之四秒,而`12:00:00.004`表示千分之四秒。 冒号表示接下来的是千分之一秒; 因此`12:00:00:4`表示千分之四秒。 冒号后面的数字限制为3位。 在转换为整数数据类型或`SQL_DOUBLE`数据类型时,数据值(包括日期和时间)将转换为数字表示。 对于`SQL_DATE`,这是自1841年1月1日以来的天数。 对于`SQL_TIME`,这是自午夜以来的秒数。 当遇到非数字字符时,输入字符串将被截断。 整数数据类型还截断十进制数字,返回数字的整数部分。 `{fn CONVERT(expression,datatype)}`不支持流数据的转换; 指定要表达的流字段将导致`SQLCODE -37`错误。 转换成任何数据类型的`NULL`仍然是`NULL`。 空字符串(`"`),或任何非数字字符串值转换如下: - `SQL_VARCHAR`和`SQL_TIMESTAMP`返回提供的值。 - 数字数据类型转换为`0`(零)。 - `SQL_DATE`和`SQL_TIME`转换为`NULL`。 # CONVERT 类方法 还可以使用`CONVERT()`方法调用执行数据类型转换,使用" `SQL_ `"关键字指定数据类型: ```java $SYSTEM.SQL.Functions.CONVERT(expression,convert-to-type,convert-from-type) ``` 如下示例所示: ```java WRITE $SYSTEM.SQL.CONVERT(60945,"SQL_VARCHAR","SQL_DATE") 2007-11-11 ``` # 示例 ## CONVERT() 示例 下面的示例使用标量语法形式的`CONVERT`。 下面的示例比较了使用`DECIMAL`和`DOUBLE`数据类型对小数的转换: ```sql SELECT CONVERT(DECIMAL,-123456789.0000123456789) AS DecimalVal, CONVERT(DOUBLE,-123456789.0000123456789) AS DoubleVal ``` 下面的示例将字符流字段转换为`VARCHAR`文本字符串。 它还使用`CHAR_LENGTH`显示字符流字段的长度: ```sql SELECT Notes,CONVERT(VARCHAR(80),Notes) AS NoteText,CHAR_LENGTH(Notes) AS TextLen FROM Sample.Employee WHERE Notes IS NOT NULL ``` 下面的例子展示了几种将出生日期字段(`DOB`)转换为格式化字符串的方法: ```sql SELECT DOB, CONVERT(VARCHAR(20),DOB) AS DOBDefault, CONVERT(VARCHAR(20),DOB,100) AS DOB100, CONVERT(VARCHAR(20),DOB,107) AS DOB107, CONVERT(VARCHAR(20),DOB,114) AS DOB114, CONVERT(VARCHAR(20),DOB,126) AS DOB126 FROM Sample.Person ``` 默认格式和代码`100`格式是相同的。 因为`DOB`字段不包含时间值,所以显示时间的格式(这里包括默认值`10`0、`114`和`126`)提供一个零值,它表示`12:00AM`(午夜)。 代码`126`格式提供了一个不包含空格的日期和时间字符串。 ## {fn CONVERT()} 示例 下面的示例使用了`ODBC`语法形式的`CONVERT`。 下面的嵌入式SQL示例将混合字符串转换为整数。 IRIS在第一个非数字字符处截断字符串,然后将结果数字转换为规范形式: ```java ClassMethod Convert1() { s a="007 James Bond" &sql(SELECT {fn CONVERT(:a, SQL_INTEGER)} INTO :x) w !,"SQLCODE=",SQLCODE w !,"the host variable is:",x } ``` ```java DHC-APP>d ##class(PHA.TEST.SQLCommand).Convert1() SQLCODE=0 the host variable is:7 ``` 下面的示例将`“DOB”`(出生日期)列中的日期转换为`SQL_TIMESTAMP`数据类型。 ```sql SELECT DOB,{fn CONVERT(DOB,SQL_TIMESTAMP)} AS DOBtoTstamp FROM Sample.Person ``` 生成的时间戳格式为`“yyyy-mm-dd hh:mm:ss”`。 下面的示例将`“DOB”`(出生日期)列中的日期转换为`SQL_INTEGER`数据类型。 ```sql SELECT DOB,{fn CONVERT(DOB,SQL_INTEGER)} AS DOBtoInt FROM Sample.Person ``` 下面的示例将`“DOB”`(出生日期)列中的日期转换为`SQL_VARCHAR`数据类型。 ```sql SELECT DOB,{fn CONVERT(DOB,SQL_VARCHAR)} AS DOBtoVChar FROM Sample.Person ``` 生成的字符串格式为:`yyyy-mm-dd`。
文章
Michael Lei · 八月 19, 2022

IRIS 医疗版docker 容器初体验

我很高兴与大家分享我第一次使用docker容器版本的IRIS for Health的经验,以探索你对使用或试用的兴趣,利用docker容器的优势,它是轻量级的,易于部署。本文将通过使用Renan Lourenco编写的名为ENSDEMO的GitHub仓库的实施步骤。 设置IRIS for Health社区版docker容器环境的步骤: 启动运行Docker 下载docker 镜像image docker pull containers.intersystems.com/intersystems/irishealth-community:2022.2.0.304.0 从GitHub 克隆源repository git clone https://github.com/OneLastTry/irishealth-ensdemo 改一下文件目录. 从docker-compose.yml建立容器镜像 docker-compose build 运行你的容器 docker-compose up -d 在我最初的尝试中,我无法下载irishealth community:2022.2.0.304.0的确切版本,因为它在ENSDEMO的最初发布中已经发生了变化。修复方法是,当试图从InterSystems容器注册表拉出docker镜像时,在注册表中拉出最新的可用标签。 我遇到的另一个错误是在执行docker-compose build命令后显示"=>ERROR[internal]load metadata for docker pull containers.intersystems.com/intersystems/irishealth-community:2022.2.0.293.0" 。这是因为我下载的docker镜像的版本和Dockerfile中指定的容器镜像版本之间有冲突。 登录IRIS医疗版: 管理门户: http://localhost:9092/csp/sys/%25CSP.Portal.Home.zen 用户名: SuperUser 密码: SYS SuperServer 端口: 9091 Web 端口: 9092 命名空间: ENSDEMO 启动 IRIS 终端 session: docker exec -it ensdemo iris session iris 启动 bash session: docker exec -it ensdemo /bin/bash 视频: https://www.loom.com/share/36bd8c63db724eebae65debf0d89c821 参考: https://github.com/OneLastTry/irishealth-ensdemo by Renan Lourenco (Renan.Lourenco@intersystems.com) https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ACLOUD 咨询下,启动出现下边错误,是什么原因呢? [root@elite ~]# docker logs irishealth[INFO] Executing command /home/irisowner/irissys/startISCAgent.sh 2188...[INFO] Writing status to file: /home/irisowner/irissys/iscagent.statusReading configuration from file: /home/irisowner/irissys/iscagent.confISCAgent[18]: StartingISCAgent[19]: Starting ApplicationServer on *:2188[INFO] ...executed command /home/irisowner/irissys/startISCAgent.sh 2188[ERROR] Required Linux capability cap_setuid is missing.[ERROR] Required Linux capability cap_dac_override is missing.[ERROR] Required Linux capability cap_fowner is missing.[ERROR] Required Linux capability cap_setgid is missing.[ERROR] Required Linux capability cap_kill is missing.[FATAL] Your IRIS container is missing one or more required Linux capabilities.[INFO] Executing command /home/irisowner/irissys/startISCAgent.sh 2188... 最新docker引擎做了变化,运行IRIS的2022.2之前的版本,要增加一个参数--check-caps false,例如: docker run --name test2 --publish 1972:1972 --publish 52773:52773 docker.iscinternal.com/intersystems/irishealth:2021.1.0.215.0 --check-caps false --key <keyfile-path>
文章
Lilian Huang · 五月 10, 2022

关于自适应分析Adaptive Analytics 示例模式操作!

InterSystems IRIS 2021.1 的发布引入了自适应分析(Adaptive Analytics)的介绍。 为了开始使用和熟悉 InterSystems IRIS BI cube示例,我们创建了一个用于自适应分析的 HoleFoods 应用程序示例模版。 此示例应用程序可在 Open Exchange 上获得, 还有一个学习服务课程learning services course 可用于了解有关自适应分析的更多信息。 首先,前往 Open Exchange 并点击下载按钮。您将会被引至发布页面,该页面包含最新版本的应用程序示例, 下载 ZIP 文件开始创建示例样本。 加载示例样本前准备 IRIS 确保你已经在IRIS 命名空间中已经有要导入的样本MySample 模式被定义 如果未定义上述1模式,请在 SMP 中运行以下 SQL 创建表 MySample.Dummy (P1 INT NOT NULL) 如果您还想设置一些 global mappings, 请至少插入 1 行,以便找出需要映射的global hash 插入MySample.Dummy (P1) 值 (1) 在 AtScale 中,登录并转到 PROJECTS 选项卡 点击 hamburger 菜单 并选择 "Use a sample" 选择您的DWH,the MySample 模式,和zip 文件 可以使用默认权限 您现在该期待IRIS中的新Table和AtScale中的新Project了! 安装示例应用程序后,您可以开始使用 Excel、Tableau 或 Power BI 等第三方工具发现和探索数据功能。 查看已发布的多维数据集时,您可以查看有关如何连接到不同第三方工具的详细信息。 相比发现和探索数据功能,您可能首先会探索这个模式与现有的 HoleFoods InterSystems IRIS BI Cube做比较。