清除过滤器
文章
姚 鑫 · 七月 28, 2021
# 第三十三章 类关键字 - SoapBodyUse
指定此类中定义的任何`web method`的编码。此关键字仅适用于`web服务`和`web客户端`类。
# 用法
要指定此类的`web method`的输入和输出所使用的编码,请使用以下语法:
```java
Class MyApp.MyClass [ SoapBodyUse = soapbodyuse ] { //class members }
```
其中`soapbodyuse`是下列之一:
- `literal` 文字(默认)—默认情况下,此类中的`web method`使用文字数据。也就是说,`SOAP`消息的``中的`XML`与`WSDL`中给出的模式完全匹配。
- `encoded` 编码—默认情况下,此类中的`web method`使用`SOAP`编码的数据。也就是说,`SOAP`消息的``中的`XML`使用了适合所使用的`SOAP`版本的`SOAP`编码,如以下规范所要求的:
- `SOAP 1.1` (https://www.w3.org/TR/2000/NOTE-SOAP-20000508/Opens in a new window)
- `SOAP 1.2` (https://www.w3.org/TR/soap12-part2/Opens in a new window)
重要提示:对于手动创建的`web服务`,该关键字的默认值通常是合适的。当使用`SOAP`向导从WSDL生成`web`客户端或服务时,InterSystems IRIS会将此关键字设置为适合该`WSDL`;如果修改该值,web客户端或服务可能不再工作。
# 详解
此关键字指定此类中定义的任何`web method`使用的默认编码。它还控制这个类的`ELEMENTQUALIFIED`和`XMLELEMENT`参数的默认值,这将在本主题的一个小节中讨论。
可以通过使用`SoapBodyUse`方法关键字或`SoapBodyUse`查询关键字,为单个方法重写此关键字。
# 对子类的影响
此关键字不是继承的。
# 默认
默认值为文字。(`SOAP`标准V1.1指定`web method`应该使用`SOAP`编码。但是,大多数`SOAP`客户端(包括`.NET`)都使用文字样式。)
# WSDL的关系
`SoapBodyUse`关键字指定了`WSDL`的``部分中``元素的`Use`属性的值。例如,如果`SoapBodyUse`是字面意思,则`WSDL`可能如下所示:
```xml
...
文章
Jingwei Wang · 七月 7, 2023
本篇文章主要介绍互联互通套件的一些基础问题:
基于互联互通套件通过互联互通成熟的测评的实施工作量
电子病历共享文档部分:需要客户将业务系统数据灌入CCH套件SQL模型中
服务部分:在平台做消息改造,或者直接做业务系统接口改造
基于互联互通套件通过电子病例五级+互联互通成熟度测评四级需要的最低人员配备和项目总耗时
需要了医院现有业务系统和人员配备,做进一步评估及分析
目标只是通过互联互通成熟度测评需不需要FHIR
不需要,如果只是过测评,只需要互联互通套件基础版就够了
BI相关功能如何实现
可以使用DeepSee,基于Cubes做数据分析及钻取
如何使用Java进行快速开发
可以使用PEX,支持Java开发,但是如果使用Production,推荐使用内置开发语言ObjectScript,学习成本更低,未来开发新特性能力更强大
有没有自带的ETL工具
InterSystems 互联互通套件中没有ETL工具,但是支持所有ETL工具的连接
发送失败消息是否有记录
所有错误消息都能够在平台监控到,且可以进行转发或者重发
有没有按照单个服务流程进行整个业务流程的修改和查看
平台内所有服务都可以按照类别区分,也可以按照服务查看业务流程,但是没有按照单个服务修改整个业务流程的界面
文章
Michael Lei · 八月 26, 2021
# SAM - 设置和添加非 IRIS 目标指标的技巧和提示
SAM(系统警报和监视)以“功能齐全”的 docker-compose 容器集的形式提供,只要启动就可以开始以默认的仪表板监视 IRIS 实例。 使用初始配置就可以很好地了解 SAM 功能并开始对 IRIS 系统进行基本监视。 但是,当开始监视多个系统并收集大量指标数据时,需要更改一些默认设置。 为了从 SAM 获取更多价值,您还会想要添加来自其他数据源(目标)的指标。 以下技巧将帮助您在生产环境中部署 SAM,从多个目标收集指标并将这些指标组合到您自己的仪表板和图表中。 此外,您还将看到一些可能有助于探索 SAM 容器和应用程序的命令。
> *注意:*我应该指出,其中一些技巧和提示可能不是最佳做法;这更像是一个日志,记录了我第一次如何配置 SAM 来监视相同系统上的多个服务器和非 IRIS 目标的基准。 如果您有建议,请在评论中指教 ;) 所以,记住本帖可能会随着时间的推移而有所变化,让我们开始吧;
---
在下面的技巧中,有重启 docker 以及启动和停止 SAM 的操作。 请通读这些技巧,确定哪些适合您,然后按照下面的相同顺序执行。
## 1. 确保有足够的空间用于 SAM 数据库
默认情况下,docker 容器将文件存储在根 (/) 文件系统。 SAM 不需要很多 CPU 或内存资源;但是,指标收集将占用空间。
> 指标需要的存储容量“视情况而定”。 虽然在开始监视之前可能无法明确数据库大小,但大致上,在抓取周期为 15 秒的情况下,监视 10 个 IRIS 虚拟机以及操作系统指标大约消耗 50GB 存储。
策略包括:增加监视实例的根存储,或更改数据库的卷位置。 我使用了以下命令来更改运行 docker 的虚拟机上的 docker 目录。 也许是杀鸡用了牛刀,但很管用。
- 停止 docker 并将 docker 文件复制到空间充足的文件系统(本例中为 /data/docker/data)。 见下面的示例:
```other
[root@mysamserver lib]# sudo systemctl stop docker
[root@mysamserver lib]# pwd
/var/lib
[root@mysamserver lib]# cp -rp docker /data/docker/data
[root@mysamserver lib]#
[root@mysamserver lib]# rm -rf docker
```
- 在 docker 配置文件中更新卷路径。 注意此文件还有一个网络设置“bip”(请参见注释:...)
```swift
cat /etc/docker/daemon.json
{
"data-root": "/data/docker/data",
"bip": "192.168.0.1/24"
}
```
- 重启 docker
```swift
sudo systemctl daemon-reload
sudo systemctl restart docker
systemctl status docker.service
```
## 2. 设置 SAM
我假定您已在测试系统上设置 SAM,并熟悉它的基本操作:添加集群和实例,以及查看系统指标。 建议您花 20 分钟时间查看我在虚拟全球峰会 2020 上的展示,以了解安装步骤的概述,以及添加多个目标的运行指标时 SAM 的外观。 要观看此会议,请使用以下链接(您需要使用您的电子邮件注册):
[DEV007 系统警报和监视](https://intersystems.6connex.com/event/virtual-summit/en-us/contents/434680/share?rid=Lobby&nid=804450)
登录到 SAM 门户并配置一些 IRIS 实例。 这会填充配置文件并提供向导。
`http://mysamserver:8080/api/sam/app/index.csp#/`
> 注意:如果要添加多个实例,或者希望用脚本执行此步骤,可以通过 API 添加实例。 请参见文档。
## 3. 升级到生产许可证
SAM 随附了一个 IRIS 社区版许可证。 有几个限制,包括 IRIS.DAT 限制为 10GB。 10GB 不足以长时间从多个目标收集数据。 请联系您的 InterSystems 联系人以获取生产许可证。 在没有编辑器的情况下,在精简的容器中更新许可证可能很棘手,我只是在 IRIS 容器上登录一个交互式会话,然后使用以下命令更新许可证密钥:
- 打开 shell,切换目录至 mgr 文件夹(iris.key 文件的默认位置)
```swift
docker exec -it sam_iris_1 bash
cd /dur/iconfig/mgr
```
- 使用 unix“here 文档”更新密钥。 在“>”后面粘贴密钥文本。 在密钥文本后面,输入“>EOF”以提交命令。 然后输入“exit”退出 shell。
```other
cat
[ConfigFile]
FileType=InterSystems License Rev-A.1
LicenseID=999999
[License]
LicenseCapacity=InterSystems IRIS 2020.2 Server for SAM:etc etc, the key you were sent by your InterSystems contact.
>EOF
exit
```
- 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
- 可以通过访问系统管理门户或登录到 iris 实例并检查 messages.log 来检查许可证是否一切正常。
```shell
docker exec -it sam_iris_1 bash
cd /dur/iconfig/mgr
cat messages.log
```
## 4. 在目标上安装其他 prometheus 导出程序
例如,prometheus 节点导出程序可显示各种硬件和内核相关的指标。
[节点导出程序文档](https://prometheus.io/docs/guides/node-exporter/)
通过请求(抓取)实例端点的指标,测试节点导出程序是否正常工作:
```swift
curl my_target_server_name:9100/metrics
```
您应该看到类似下面的信息:
```swift
mylaptop:~ mo$ my_target_server_name:9100/metrics | more
HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 4.8862e-05
go_gc_duration_seconds{quantile="0.25"} 7.5898e-05
go_gc_duration_seconds{quantile="0.5"} 9.2974e-05
go_gc_duration_seconds{quantile="0.75"} 0.000130664
go_gc_duration_seconds{quantile="1"} 0.000358762
go_gc_duration_seconds_sum 303.291715258
go_gc_duration_seconds_count 2.572586e+06
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 9
:
: many many metrics will be displayed
```
注意您可以对您的 IRIS 实例执行同样操作:
```swift
mylaptop:~ mo$ curl my_target_server_name:52776/api/monitor/metrics | more
iris_cpu_pct{id="AUXWD"} 0
iris_cpu_pct{id="CSPDMN"} 0
iris_cpu_pct{id="CSPSRV"} 0
iris_cpu_pct{id="ECPCliR"} 0
iris_cpu_pct{id="ECPCliW"} 0
iris_cpu_pct{id="ECPSrvR"} 0
iris_cpu_pct{id="ECPSrvW"} 0
:
: many many metrics will be displayed
```
## 5. 编辑配置文件以添加对新目标的抓取
例如,前一个技巧中的 node-exporter 实例。 配置文件将位于 SAM 的安装位置。 如下所示,可以看到 grafana 和 prometheus `yml` 配置文件。
```plaintext
[root@mysamserver sam-1.0.0.115-unix]# ls
config docker-compose.yml readme.txt start.sh stop.sh
[root@mysamserver sam-1.0.0.115-unix]# tree -x config
config
├── alertmanager
│ └── isc_alertmanager.yml
├── grafana
│ ├── dashboard.json
│ ├── dashboard-provider.yml
│ ├── datasource.yml
│ └── grafana.ini
├── nginx
│ └── nginx.conf
└── prometheus
├── isc_alert_rules.yml
└── isc_prometheus.yml
4 directories, 8 files
```
## 5.1 添加目标到 prometheus
以下示例是使用 SAM 中的配置 GUI 屏幕创建的 `isc_prometheus.yml` 文件。 该文件包含两个集群。 一个集群监视 sam 实例本身,另一个集群监视五个 IRIS 实例。
```yaml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
global:
evaluation_interval: 15s
scrape_interval: 15s
remote_read:
- url: http://iris:52773/api/sam/private/db/read
remote_write:
- url: http://iris:52773/api/sam/private/db/write
rule_files:
- ./isc_alert_rules.yml
scrape_configs:
- job_name: SAM
metrics_path: /api/monitor/metrics
scheme: http
static_configs:
- labels:
cluster: "1"
targets:
- mysaminstance.mycompany.com:8080
- labels:
cluster: "2"
targets:
- myiristarget1:52776
- myiristarget2:52776
- myiristarget3:52776
- myiristarget4:52776
- myiristarget5:52776
```
- 要添加对其他运行 node-exporter 的目标的抓取,请将以下内容添加到 `isc_prometheus.yml` 文件的底部。 注意 API `metrics_path` 与 IRIS 不同。
```yaml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
global:
evaluation_interval: 15s
scrape_interval: 15s
remote_read:
- url: http://iris:52773/api/sam/private/db/read
remote_write:
- url: http://iris:52773/api/sam/private/db/write
rule_files:
- ./isc_alert_rules.yml
scrape_configs:
- job_name: SAM
metrics_path: /api/monitor/metrics
scheme: http
static_configs:
- labels:
cluster: "1"
targets:
- iscsydsam.iscinternal.com:8080
- labels:
cluster: "2"
targets:
- myiristarget1:52776
- myiristarget2:52776
- myiristarget3:52776
- myiristarget4:52776
- myiristarget5:52776
- job_name: node_shard1
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget1:9100
- job_name: node_shard2
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget2:9100
- job_name: node_shard3
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget3:9100
- job_name: node_shard4
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget4:9100
- job_name: node_shard5
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget5:9100
```
- 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
SAM 现在从您通过 GUI 添加的 IRIS 实例以及相同实例上的 node-exporter 中收集指标。
# 6. 增加 Prometheus 收集指标的天数
在 SAM 的第一版中,您可以在 GUI 中更改收集指标的天数。 但是,我在显示所有指标时遇到一个问题。 在我弄清楚发生了什么之前,我更改了 Prometheus 中的保留天数,否则 SAM 将收集数据,但是您在 Grafana 的 Prometheus 查询中看不到指标。
在文件 `docker-compose.yml` 中用来安装 SAM 的层,更改 Prometheus 启动时设置的保留天数,例如在 `prometheus` 部分中,更新 `storage.tsdb.retention.time` 参数以匹配所需的保留天数:
```swift
prometheus:
command:
- --web.enable-lifecycle
- --config.file=/config/isc_prometheus.yml
- --storage.tsdb.retention.time=30d
```
> 注意:在 SAM 的第一版中,最长保留天数为 30 天。 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
## 7. 创建您自己的仪表板
您可以向现有仪表板添加面板,也可以创建新的仪表板以满足您的监视需求。 这是一个很大的主题,所以留到下一个帖子再说。 不过,这里先帮助您上手。
在 SAM 屏幕上使用 `View in Grafana`(在 Grafana 中查看)按钮切换到 Grafana。

打开 Grafana 后,可以创建或编辑仪表板;

网上有许多查询导出程序(如 node-exporter)的示例。
> 当可以显示 IRIS 系统指标(SAM 中的默认设置)、IRIS 应用程序指标(您需要将这些指标构建到应用程序中)以及其他指标(如 node-exporter 或由供应商创建的任何数量的指标)时,真正强大的功能才体现出来。 例如,[使用 SAM 和 cAdvisor 监视 Docker 容器](https://community.intersystems.com/post/monitor-docker-containers-using-sam-and-cadvisor)
文章
姚 鑫 · 六月 30, 2021
# 第二十三章 执行XSLT转换概述
XSLT(Extensible StyleSheet Language Transformations,可扩展样式表语言转换)是一种基于XML的语言,用于描述如何将给定的XML文档转换为另一个XML或其他“人类可读”的文档。可以使用`%XML.XSLT`和`%XML.XSLT2`包中的类来执行`XSLT 1.0`和`2.0`转换。
注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码, IRIS将使用本书前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。
# 在IRIS中执行XSLT转换概述
IRIS提供两个XSLT处理器,每个处理器都有自己的API:
- `Xalan`处理器支持`XSLT 1.0`。`XML.XSLT`包为该处理器提供API。
- `Saxon`处理器支持`XSLT 2.0`。`%XML.XSLT2`程序包为该处理器提供API。
`XML.XSLT2` API通过到`XSLT 2.0`网关的连接向`Saxon`发送请求。网关允许多个连接。这意味着,例如,可以将两个独立的 IRIS进程连接到网关,每个进程都有自己的一组编译样式表,同时发送转换请求。
使用Saxon处理器,编译的样式表和`isc:Evaluate`缓存是特定于连接的;必须管理自己的连接才能利用这两个特性。如果打开连接并创建编译样式表或计算填充`isc:Evaluate`缓存的转换,则在该连接上计算的所有其他转换都将访问编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。
这两个处理器的API相似,不同之处在于`%XML.XSLT2`中的方法使用另一个参数来指定要使用的网关连接。
要执行`XSLT`转换,请执行以下操作:
1. 如果使用的是`Saxon`处理器,请按照下一节所述配置`XSLT`网关服务器。或使用默认配置。
如果使用的是`Xalan`处理器,则不需要网关。
系统会在需要时自动启动网关。或者也可以手动启动它。
2. 如果使用的是`Saxon`处理器,则可以选择创建`%Net.Remote.Gateway`的实例,表示到`XSLT`网关的单个连接。
请注意,当使用`Saxon`处理器时,要利用已编译的样式表和`isc:Evaluate`缓存,这一步是必需的。
3. 可以选择创建已编译的样式表并将其加载到内存中。请参阅本章后面的“创建编译样式表”。如果使用的是`Saxon`处理器,请确保在创建编译后的样式表时指定网关参数。
如果打算重复使用同一样式表,则此步骤非常有用。然而,此步骤也会消耗内存。当不再需要编译的样式表时,请务必将其删除。
4. 调用适用API的转换方法之一。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数。
5. 可以选择调用其他转换方法。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数;这使能够使用相同的连接计算另一个转换。此转换将访问与此连接相关联的所有编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。
Studio还提供了一个向导,可以使用该向导测试XSLT转换;本章稍后将对此进行介绍。
# 配置、启动和停止XSLT 2.0网关
当使用`Saxon`处理器(执行`XSLT 2.0`转换)时, IRIS使用`XSLT 2.0`网关(后者使用Java)。要配置此网关,请执行以下操作:
1. 在管理门户中,选择 System Administration > Configuration > Connectivity > XSLT 2.0 Gateway Server.
2. 选择Go。

系统将显示XSLT网关服务器页面。
左侧区域显示配置详细信息,右侧区域显示最近的活动。

3. 在左侧区域中,可以选择指定以下设置:
- Port Number -`XSLT 2.0`网关独占使用的TCP端口号。此端口号不得与服务器上的任何其他本地TCP端口冲突。
默认值为 IRIS SuperServer端口号加`3000`。如果此数字大于`65535`,则系统使用`54773`。
- Java Version - 使用的Java版本。
- Log File - 日志文件的路径名。如果忽略此设置,则不执行日志记录。如果指定了文件名但忽略了目录,则将日志文件写入系统管理器的目录。
- Java Home Directory -包含Java bin目录的目录路径。如果服务器上没有默认Java,或者如果想使用不同的Java,请指定此选项。
要查看默认Java,请在服务器上的Shell中执行以下命令:
```
java -version
```
- JVM Arguments - Java虚拟机要使用的任何其他参数。
此区域还显示`JAVA_HOME`环境变量的当前值。
请注意,在网关运行时,不能编辑这些值中的任何一个。
4. 如果已进行更改,请选择保存以保存更改。或选择重置以。
5. (可选)选择测试以测试更改。
在此页面上,还可以执行以下操作:
- 启动网关。要执行此操作,请选择右侧区域中的Start。
请注意, IRIS会在需要时自动启动网关。不需要手动启动网关。
- 关闭网关。要执行此操作,请选择右侧区域中的Stop(停止)。
# 重用XSLT网关服务器连接(XSLT 2.0)
如果使用的是`Saxon`处理器,InterSystems IRIS将使用之前配置的`XSLT 2.0`网关。为了与此网关通信,InterSystems IRIS在内部创建一个`XSLT`网关连接(`%Net.Remote.Gateway`的实例)。默认情况下,系统创建一个连接,将其用于转换,然后丢弃该连接。打开新连接会产生开销,因此为多个转换维护一个连接可提供最佳性能。此外,必须维护自己的连接,以便利用已编译的样式表和`isc:Evaluate`缓存。
要重用XSLT网关连接,请执行以下操作:
1. 调用`%XML.XSLT2.Transformer`的`StartGateway()`方法:
```
set status=##class(%XML.XSLT2.Transformer).StartGateway(.gateway)
```
此方法启动XSLT 2.0网关(如果它尚未运行),并返回`%Net.Remote.Gateway`的实例作为输出。请注意,该方法还返回状态。
在`%Net.Remote.Gateway`实例表示与网关的连接。
`StartGateway()`有一个可选的第二个参数`useSharedMemory`。如果此参数为真(缺省值),则与`localhost`或`127.0.0.1`的连接将使用共享内存(如果可能)。要强制连接仅使用`TCP/IP`,请将此参数设置为False。
2. 检查上一步返回的状态:
```java
if $$$ISERR(status) {
quit
}
```
3. 创建任何已编译的样式表。执行此操作时,请将网关参数指定为`%Net.Remote.GatewayInstance`的实例在步骤1中创建。
4. 根据需要调用`%XML.XSLT2.Transformer`的`Transform`方法(`TransformFile()`、`TransformFileWithCompiledXSL()`、`TransformStream()`和`TransformStreamWithCompiledXSL()`)。执行此操作时,请将网关参数指定为在步骤1中创建的`%Net.Remote.Gateway`的实例。
5. 如果不再需要给定的编译样式表,请在调用`%XML.XSLT2.CompiledStyleSheet`的`ReleaseFromServer()`方法:
```java
Set status=##class(%XML.XSLT2.CompiledStyleSheet).ReleaseFromServer(compiledStyleSheet,,gateway)
```
重要提示:当不再需要已编译的样式表时,请务必使用此方法。
6. 当不再需要XSLT网关连接时,调用`%XML.XSLT2.Transformer`的`StopGateway()`方法,并将网关连接作为参数传递:
```java
set status=##class(%XML.XSLT2.Transformer).StopGateway(gateway)
```
此方法丢弃连接并重置当前设备。它不会停止`XSLT 2.0`网关。
重要提示:当不再需要连接时,请务必使用此方法。
有关示例,请参见XSLT2中的`Example10()`方法。`Samples`命名空间中的`Examples`。
# 排除XSLT 2.0网关服务器连接故障
当XSLT 2.0网关打开时,InterSystems IRIS和网关服务器之间的连接可能会变得无效。例如,如果出现网络错误或在InterSystems IRIS连接到网关服务器后重新启动网关服务器,则连接可能无法正常关闭。因此,可能会遇到错误。
可以通过连续调用XSLT网关连接对象的`%LostConnectionCleanup()`方法和`%reconnect`方法,尝试将InterSystems IRIS重新连接到网关服务器。
如果希望在断开连接时自动重新连接到网关服务器,请将网关连接对象的`AttemptReconnect`属性设置为true。
# 创建编译的样式表
如果打算重复使用同一样式表,则可能需要编译该样式表以提高速度。请注意,此步骤会消耗内存。当不再需要编译的样式表时,请务必将其删除。
要创建编译的样式表,请执行以下操作:
- 如果使用的是`Xalan`处理器(对于`XSLT 1.0`),请使用`%XML.XSLT.CompiledStyleSheet`的以下类方法之一:
- `CreateFromFile()`
- `CreateFromStream()`
- 如果使用的是`Saxon`处理器(用于`XSLT 2.0`),请在使用`%XML.XSLT2.CompiledStyleSheet`的以下类方法之一:
- `CreateFromFile()`
- `CreateFromStream()`
另请注意,将需要创建一个XSLT网关连接;请参阅“重用XSLT网关服务器连接(`XSLT 2.0`)”。
对于所有这些方法,完整的参数列表按顺序如下:
1. source - 样式表。
对于`CreateFromFile()`,此参数是文件名。对于`CreateFromStream()`,此参数是一个流。
2. compiledStyleSheet - 编译后的样式表,作为输出参数返回。
这是样式表类(`%XML.XSLT.CompiledStyleSheet`或`%XL.XSLT2.CompiledStyleSheet`,视情况而定)的实例。
3. errorHandler - 编译样式表时使用的可选自定义错误处理程序。
对于这两个类中的方法,这是`%XML.XSLT.ErrorHandler`实例。
4. (仅适用于`%XML.XSLT2.CompiledStyleSheet`)网关-`%Net.Remote.Gateway`的实例
```
//将tXSL设置为等于适当流的OREF
Set tSC=##class(%XML.XSLT.CompiledStyleSheet).CreateFromStream(tXSL,.tCompiledStyleSheet)
If $$$ISERR(tSC) Quit
```
文章
姚 鑫 · 三月 9, 2021
# 第六章 SQL定义和使用视图
视图是一种虚拟表,由执行时通过`SELECT`语句或几个`SELECT`语句的`UNION`从一个或多个物理表中检索到的数据组成。 `SELECT`可以通过指定表或其他视图的任意组合来访问数据。因此,存储了视图的视图提供了物理表的所有灵活性和安全性特权。
InterSystemsIRIS®数据平台上的InterSystems SQL支持在视图上定义和执行查询的功能。
注意:不能对以只读方式安装的数据库中存储的数据创建视图。
无法在通过ODBC或JDBC网关连接链接的`Informix`表中存储的数据上创建视图。这是因为InterSystems IRIS查询转换对这种类型的查询使用FROM子句中的子查询。 `Informix`不支持`FROM`子句子查询。
# 创建一个视图
可以通过几种方式定义视图:
- 使用SQL `CREATE VIEW`命令(在DDL脚本中或通过JDBC或ODBC)。
- 使用管理门户的“创建视图”界面。
视图名称:不合格的视图名称是一个简单的标识符:`MyView`。合格的视图名称由两个简单的标识符组成,即模式名称和视图名称,以句点分隔:`MySchema.MyView`。视图名称和表名称遵循相同的命名约定,并对不合格的名称执行相同的架构名称解析。同一模式中的视图和表不能具有相同的名称。
可以使用`$SYSTEM.SQL.ViewExists()`方法确定视图名称是否已存在。此方法还返回投影视图的类名称。可以使用`$SYSTEM.SQL.TableExists()`方法确定表名是否已存在。
视图可用于创建表的受限子集。以下嵌入式SQL示例创建一个视图,该视图限制了可以通过该视图访问的原始表的行(通过`WHERE`子句)和列(假设`Sample.Person`包含两个以上的列):
```java
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQL).View()
创建一个视图
```
以下嵌入式SQL示例基于`SalesPeople`表创建一个视图,并创建一个新的计算值列`TotalPay`:
```java
/// d ##class(PHA.TEST.SQL).View1()
ClassMethod View1()
{
&sql(CREATE VIEW Sample.VSalesPay AS
SELECT Name,(Salary + Commission) AS TotalPay
FROM Sample.SalesPeople)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
## 管理门户创建视图界面
可以从管理门户创建视图。转到InterSystems IRIS管理门户。在系统资源管理器中,选择SQL。使用页面顶部的Switch选项选择一个名称空间;这将显示可用名称空间的列表。选择名称空间后,单击“操作”下拉列表,然后选择“创建视图”。
这将显示“创建视图”窗口,其中包含以下字段:
- 模式:可以决定将视图包含在现有模式中,也可以创建一个新模式。如果选择选择现有模式,则会提供一个现有模式的下拉列表。如果选择创建新架构,请输入架构名称。在这两种情况下,如果省略模式,则InterSystems IRIS都会使用系统范围内的默认模式名称。
- 视图名称:有效的视图名称。不能对同一模式中的表和视图使用相同的名称。
- 使用`Check Option`:选项为`READONLY`,`LOCAL`,`CASCADED`。
- 将视图的所有特权授予`_PUBLIC`:如果选中,则此选项为该视图授予所有用户执行特权。默认设置是不授予所有用户访问该视图的权限。
- 查看文字:可以通过以下三种方式中的任意一种来指定查看文字:
- 在“查看文本”区域中键入SELECT语句。
- 使用查询生成器创建`SELECT`语句,然后按OK将此查询提供给“查看文本”区域。
- 如果在Management Portal SQL界面的左侧选择了一个缓存查询名称(例如`%sqlcq.USER.cls4`),然后调用`Create View`,则该缓存查询将提供给“视图文本”区域。请注意,在保存视图文本之前,必须在“视图文本”区域中用实际值替换主机变量引用。
## 视图和相应的类
定义视图时,InterSystems IRIS会生成一个相应的类。按照名称转换规则,SQL视图名称用于生成相应的唯一类名称。 Management Portal SQL界面显示现有视图的“目录详细信息”,包括此类名称。
# 修改视图
在Management Portal SQL界面中,可以选择一个现有视图以显示该视图的“目录详细信息”。 “目录详细信息视图信息”选项显示“编辑视图”链接,该链接提供了用于编辑视图文本(视图的`SELECT`语句)的界面。它还提供了一个下拉列表,以将“带检查选项”选择为无,`READONLY`,`LOCAL`或`CASCADED`。
# 可更新的视图
可更新的视图是可以在其上执行`INSERT`,`UPDATE`和`DELETE`操作的视图。仅当满足以下条件时,才认为视图是可更新的:
- 视图查询的`FROM`子句仅包含一个表引用。该表引用必须标识可更新的基表或可更新的视图。
- 视图查询的`SELECT`列表中的值表达式必须全部是列引用。
- 视图的查询中不得指定`GROUP BY`,`HAVING`或`SELECT DISTINCT`。
- 该视图不是投影为视图的类查询。
- 视图的类不包含类参数`READONLY = 1`(如果视图定义包含`WITH READ ONLY`子句,则为`true`)。
## WITH CHECK选项
为了防止在视图上执行`INSERT`或`UPDATE`操作,而该操作会导致基础基表中的行不属于派生视图表的一部分,InterSystems SQL在视图定义中支持`WITH CHECK OPTION`子句。此子句只能与可更新视图一起使用。
`WITH CHECK OPTION`子句指定可更新视图上的任何`INSERT`或`UPDATE`操作必须对照视图定义的WHERE子句验证结果行,以确保插入或修改的行将成为派生视图表的一部分。
例如,以下DDL语句定义了一个可更新的`GoodStudent`视图,其中包含所有具有高`GPA`(平均绩点)的学生:
```java
CREATE VIEW GoodStudent AS
SELECT Name, GPA
FROM Student
WHERE GPA > 3.0
WITH CHECK OPTION
```
由于视图包含`WITH CHECK OPTION`,因此任何尝试在`GPA`值小于或等于3.0的`GoodStudent`视图中插入或更新行都将失败(此类行将不表示“好学生”)。
有两种类型的`WITH CHECK`选项:
- `WITH LOCAL CHECK`选项意味着只检查`INSERT`或`UPDATE`语句中指定的视图的`WHERE`子句。
- 与级联检查选项(和级联检查选项)意味着视图的`WHERE`子句中指定的`INSERT`或`UPDATE`语句以及所有视图检查基于这一观点,无论外表或与当地检查没有其他选项在这些视图定义条款。
如果指定了`just WITH CHECK`选项,默认值是级联的。
在更新或插入期间,在为基础表的字段计算了所有默认值和触发的计算字段之后,并在常规表验证(必需字段、数据类型验证、约束等)之前,检查`WITH CHECK`选项条件。
在`WITH CHECK`选项验证通过后,插入或更新操作继续进行,就像在基表本身上执行插入或更新一样。
检查所有约束,拉出触发器,等等。
如果在`INSERT`或`UPDATE`语句中指定了`%NOCHECK`选项,则不检查`WITH CHECK`选项的有效性。
有两个与`WITH CHECK`选项验证相关的`SQLCODE`值(插入/更新会导致派生视图表中不存在一行):
- `SQLCODE -136`-`INSERT`中视图的`WITH CHECK OPTION`验证失败。
- `SQLCODE -137`-视图的`WITH CHECK OPTION`验证在`UPDATE`中失败。
# 只读视图
只读视图是不能在其上执行`INSERT`,`UPDATE`和`DELETE`操作的视图。任何不符合可更新视图标准的视图都是只读视图。
视图定义可以指定`WITH READ ONLY`子句,以强制其成为只读视图。
如果尝试针对只读视图编译/准备`INSERT`,`UPDATE`或`DELETE`语句,则会生成`SQLCODE -35`错误。
# 查看ID:%VID
InterSystems IRIS为视图或`FROM`子句子查询返回的每一行分配一个整数视图`ID`(`%VID`)。与表行`ID`号一样,这些视图行`ID`号是系统分配的,唯一的,非空的,非零的和不可修改的。该`%VID`通常对用户不可见,并且仅在明确指定时返回。它以数据类型`INTEGER`返回。因为`%VID`值是顺序整数,所以如果视图返回有序数据,它们将更有意义。视图与TOP子句配对时,只能使用`ORDER BY`子句。以下嵌入式SQL示例创建一个名为`VSrStaff`的视图:
```java
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
下面的示例返回`VSrStaff`视图定义的所有数据(使用`SELECT *`),并且还指定应返回每一行的视图`ID`。与表行`ID`不同,使用星号语法时不显示视图行`ID`。仅当在`SELECT`中明确指定时才显示:
```java
SELECT *,%VID AS ViewID FROM Sample.VSrStaff
```
`%VID`可用于进一步限制`SELECT`从视图返回的行数,如以下示例所示:
```java
SELECT *,%VID AS ViewID FROM Sample.VSrStaff WHERE %VID BETWEEN 5 AND 10
```
**因此,可以使用`%VID`代替`TOP`(或除`TOP`之外)来限制查询返回的行数。通常,`TOP`子句用于返回数据记录的一小部分。 `%VID`用于返回大多数或所有数据记录,以小的子集返回记录。此功能可能很有用,尤其是对于移植Oracle查询(`%VID`轻松映射到Oracle ROWNUM)而言。但是,与`TOP`相比,用户应了解使用`%VID`时的一些性能限制:**
- `%VID`不执行第一行时间优化。 `TOP`优化为尽快返回第一行数据。 `%VID`优化以尽快返回完整的数据集。
- 如果查询指定排序的结果,则`%VID`不会执行有限的排序(这是`TOP`进行的特殊优化)。该查询首先对完整的数据集进行排序,然后使用`%VID`限制返回数据集。 `TOP`是在排序之前应用的,因此`SELECT`只能执行有限的排序,仅涉及有限的行子集。
为了节省第一行优化和有限排序优化的时间,可以将`FROM`子句子查询与`TOP`和`%VID`结合使用。在`FROM`子查询中指定上限(在本例中为10)作为`TOP`的值,而不是使用`TOP ALL`。使用`%VID`在`WHERE`子句中指定下限(在这种情况下,`> 4`)。以下示例使用此策略返回与上一个视图查询相同的结果:
```sql
SELECT *,%VID AS SubQueryID
FROM (SELECT TOP 10 Name,Age
FROM Sample.Person
WHERE Age > 75
ORDER BY Name)
WHERE %VID > 4
```
即使显式指定了`%PARALLEL`关键字,也无法对指定`%VID`的查询执行并行执行。
# List视图属性
`INFORMATION.SCHEMA.VIEWS`持久类显示有关当前名称空间中所有视图的信息。它提供了许多属性,包括视图定义,视图的所有者以及创建和最后修改视图时的时间戳。这些属性还包括视图是否可更新,如果可更新,是否使用检查选项定义。
在嵌入式SQL中指定时,`INFORMATION.SCHEMA.VIEWS`需要`#include%occInclude`宏预处理程序指令。 `Dynamic SQL`不需要此伪指令。
`VIEWDEFINITION`属性(`SqlFieldName = VIEW_DEFINITION`)以字符串形式返回当前名称空间中所有视图的视图字段名称和视图查询表达式。例如,
```sql
SELECT View_Definition FROM INFORMATION_SCHEMA.VIEWS
```
返回诸如`“(vName,vAge)SELECT Name,Age FROM Sample.Person WHERE Age> 21”`的字符串。当从Management Portal SQL执行查询界面发出时,此字符串的显示仅限于前100个字符,其中不包括空格和换行符,并且(如有必要)附加表示省略号的省略号(`...`)。否则,发出此查询将为每个视图返回最多`1048576`个字符的字符串,在视图字段列表和查询文本之间有一个换行符,并保留了视图查询表达式中指定的空格,并(如有必要)附加了省略号(`...`)表示内容被截断。
以下示例返回当前名称空间中所有视图的视图名称(Table_Name字段)和所有者名称:
```sql
SELECT Table_Name,Owner FROM INFORMATION_SCHEMA.VIEWS
```
以下示例返回当前名称空间中所有非系统视图的所有信息:
```sql
SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE Owner != '_SYSTEM'
```
`INFORMATION.SCHEMA.VIEWCOLUMNUSAGE`持久性类显示当前名称空间中每个视图的源表字段的名称:
```sql
SELECT * FROM INFORMATION_SCHEMA.VIEW_COLUMN_USAGE WHERE View_Name='VSrStaff'
```
可以使用管理门户网站SQL界面中的“目录详细信息”选项卡为单个视图显示与`INFORMATION.SCHEMA.VIEWS`相同的信息。视图的“目录详细信息”包括每个视图字段的定义(数据类型,最大长度,最小值/最大值等),以及`INFORMATION.SCHEMA`视图类未提供的详细信息。 “目录详细信息”视图信息显示还提供了用于编辑视图定义的选项。
# 列出视图依赖
`INFORMATION.SCHEMA.VIEWTABLEUSAGE`持久类显示当前名称空间中的所有视图及其依赖的表。在下面的示例中显示:
```sql
SELECT View_Schema,View_Name,Table_Schema,Table_Name FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
```
可以调用`%Library.SQLCatalog.SQLViewDependsOn`类查询以列出指定视图所依赖的表。可以为此类查询指定`schema.viewname`。如果仅指定视图名称,则它将使用系统范围的默认架构名称。调用者必须具有指定视图的特权才能执行此类查询。在下面的示例中显示:
```java
/// d ##class(PHA.TEST.SQL).View3()
ClassMethod View3()
{
SET statemt=##class(%SQL.Statement).%New()
SET cqStatus=statemt.%PrepareClassQuery("%Library.SQLCatalog","SQLViewDependsOn")
IF cqStatus'=1 {
WRITE "%PrepareClassQuery failed:" DO $System.Status.DisplayError(cqStatus) QUIT
}
SET rset=statemt.%Execute("vschema.vname")
DO rset.%Display()
}
```
```sql
DHC-APP>d ##class(PHA.TEST.SQL).View3()
Dumping result #1
SCHEMA TABLE_NAME
0 Rows(s) Affected
```
此`SQLViewDependsOn`查询列出了视图所依赖的表,并列出了表架构和表名。如果调用者没有该视图所依赖的表的特权,则该表及其模式将列为``。这允许没有表特权的调用者确定视图所依赖的表数量,而不是表的名称。
文章
Claire Zheng · 三月 22, 2022
最在第一期“极客聊吧”中,InterSystems销售工程师们聊了聊这些话题:为什么有些医院和某些商保之间可以直接结算,有些又不能?医院和保险之间的结算难在哪儿?在InterSystems 2021全球线上峰会中提到的医保结算案例对国内实践有哪些借鉴意义?FHIR又能起到什么关键作用?医疗数据实现互联互通的关键是什么?以下是文字版。
点击查看视频。
#从商保结算谈起#
菁伟 (@Jingwei.Wang ):大家好,我是InterSystems的销售工程师王菁伟,这是我的同事祝麟和刘皆良(Jeff)。今天我们一块来聊聊HIT行业里的数据交互那点事。去医院就诊的话,我们会发现有些医院可以和某些商业保险直接结算,有的医院或者某些保险产品又不能。为什么直结这个流程没有全面开通呢?
祝麟 ( @Lin.Zhu ):我们虽然平时看病都基本实现了医保直连, 但实际上背后医院的信息科和供应商付出了大量的努力,比如供应商就需要要适应各地医保结算流程和政策的差异,这个过程的数字化还是有很大难度的,也没法一蹴而就。
Jeff ( @Jieliang.Liu ):到商保这一侧,可以观察到很多商保产品的直结清单是逐年递增。那么保险公司的产品是一家一家和医院对接的,难度恐怕更大。
菁伟 (@Jingwei.Wang ):医院和保险之间的结算过程到底为什么落地困难呢?
祝麟 ( @Lin.Zhu ):原因很多,既有政策层面的,也有技术层面的。比如医院和院外机构间通信的安全性保障就是问题,如果没有安全的公共平台进行数据交换,哪家医院也不能独立承担数据流出医院的安全风险,这在政策的制定和技术的实现方面都有挑战。
Jeff ( @Jieliang.Liu ):医院和保险之间的接口也是问题,不同的医院会采用不同厂家提供的系统,不同保险公司采用的数据接口肯定也不一样,是个典型的多对多集成的问题,工作量会比较大,实施周期也很长。
#借鉴国际成功案例#
菁伟 (@Jingwei.Wang ):去年InterSystems的全球峰会上HealthShare的分论坛里是不是就谈到了医保结算的场景?这个案例对实现直接结算有没有借鉴意义呢?
祝麟 ( @Lin.Zhu ):是的。本身医保结算这个事是个全球性的挑战。除了我们国家以外,即使是商保比较发达的欧美国家,在打通流程方面也是处于进行中的状态。这次峰会上HealthShare发布解决方案,实现了CMS,也就是美国医保局所定义的医疗服务提供方和支付方的交互规范。这个方案覆盖的正是医疗机构、支付方以及患者三者之间结算和信息交互流程。
菁伟 (@Jingwei.Wang ):也就是说满足了政策要求?
Jeff ( @Jieliang.Liu ):也包含技术要求。CMS定义的交互流程和数据模型是以FHIR为载体的。
祝麟 ( @Lin.Zhu ):是的。CMS定义的交互规约既包含流程规范,也包含接口和数据规范,目前是以FHIR R4规定的,所以必须以FHIR API的形式实现。
#如何准确理解FHIR能力#
菁伟 (@Jingwei.Wang ):那么,现在有没有实际的案例使用FHIR来完成业务功能呢?
Jeff ( @Jieliang.Liu ):有的。我们在国际上已经看到不少基于FHIR的业务出现。比如我们和UC Davis Health以及Centene合作进行了医保预授权的自动化项目,就是基于FHIR的。在这个项目里,UC Davis Health的角色是医疗机构,Centene是保险的支付方,采用HealthShare作为平台来支撑不同角色间的实时交互。
祝麟 ( @Lin.Zhu ):UC Davis Health的医生在Epic的电子病历系统里下达医嘱,系统把患者和医嘱信息按自定义接口发到HealthShare;HealthShare将请求转为FHIR标准再通过FHIR接口与Centene的系统交互,检查这些医嘱能不能被Centene的保险产品覆盖,再把结果通过HealthShare转回到医生那儿。这样就可以在下达医嘱时实时地通过预授权的检验,杜绝医保拒付的情况。先不说杜绝拒付问题能节省的开支,光是将预授权自动化这一项,和人工处理相比,就能把每一单预授权的处理成本从3.68美金降到0.04美金,那每处理一百万次预授权就能省下几百万美金了。
菁伟 (@Jingwei.Wang ):那么,假设我们有一个集成平台,通过平台实现FHIR API接口,不同的系统通过FHIR API与集成平台对接,是不是就能解决数据交互问题呢?
祝麟 ( @Lin.Zhu ):这是个非常好的问题。FHIR在设计之初就声明采用了剃刀原理,它大概只能覆盖80%常见的交互需求。因此,对于差异化的需求或者是新技术引入的新的数据交互需求,FHIR要借助除了API之外的额外机制来解决这个问题。在医疗行业,我们现在经常遇到医疗文档共享或者跨机构流程这样的业务场景,除了API。Jeff,你认为平台这个层面还需要什么样的一些能力来支撑这些场景呢?
Jeff ( @Jieliang.Liu ):Profile。针对患者健康档案共享和支付方之间的数据交换两个不同的场景,需要分别遵循USCore profile和PDex Profile的规约。也就是说在可预见的未来,对于一家医院或者一个区域级的数据交换中心来说,需要能够支持不同的Profile以应对不同的场景。
菁伟 (@Jingwei.Wang ):这些不同的Profile之间有什么差别吗?
Jeff ( @Jieliang.Liu ):首先我们需要明白Profile立意于使用FHIR支持差异化的用例或场景。因此,一个合法的Profile就只覆盖这个场景所需要使用的模型而不会涉及到其他用例的内容。
US Core和PDex 这两个Profile首先在定位上不太一样。US Core面向患者就诊过程的信息交换,对就诊中的涉及例如治疗计划、体征和检验结果这样的临床信息进行了定义;而PDex是面向医保结算的用例,就会包含报销范围,支付方的组织机构信息这样一些和医保报销相关的信息,由CPCDS这个数据集定义。当然PDex也会引用US Core中定义的内容,比如患者的身份、病史、体征、检验结果,在PDex里这些临床信息是直接引用US Core里的定义的。
祝麟 ( @Lin.Zhu ):没错,正如同我们在医院信息互联互通标准化成熟度测评过程中可以体会到文档交换和服务调用是面向不同用例的交互手段,两者的信息构造有差异。那么使用FHIR进行交互时,面对不同的应用场景时完全可能需要套用不同的Profile,甚至是借助Profile套用特定的术语。因此,Profile之间会有很多差异。
如果FHIR在中国落地,可以想象到,由于医疗技术上我们包含中医,医疗福利上我们有医保和商保,还有很多其他差异,我们也需要有中国自己定义的多个Profile去投入使用。
因此,对FHIR的支持不能仅仅体现在支持HL7官网发布的协议结构上。支持多Profile,能够根据地区、应用场景的不同导入并套用Profile对于医疗行业的集成引擎、数据平台这样的产品是一项至关重要的FHIR能力。
Jeff ( @Jieliang.Liu ):除了遵循协议之外,还有数据架构。在HealthShare的解决方案里包含了一个整合好的数据存储。
祝麟 ( @Lin.Zhu ):是的,有一份在各业务系统之上,经过整合与泛化统一存储的数据能够极大简化应用标准协议的成本。大家可以想象一下,对于使用FHIR来说,在多Profile模式下运行的一个体系,如果没有一份整合的数据,那么每次要支持一个新的Profile,特别是和上一次应用的Profile所需的资源不一样,术语可能也不一样的时候,实施方需要再一次挨个把和各个业务系统的映射再做一遍,这个代价和周期可想而知。
菁伟 (@Jingwei.Wang ):梳理和整合数据存储的话,这样一套方案就不是单纯的集成平台方案了。
祝麟 ( @Lin.Zhu ):没错,这是因为采用集成平台,和采用集成加数据整合的医院信息平台,要解决的问题是不一样的。
当单纯应用集成平台整合流程时,要解决是打破烟囱的问题,但还谈不上整合数据与数据利用。对于这样的场景,即使点对点地两两集成,也能解决问题,坦率说除非每个应用系统都能支持某个标准协议通信,否则采不采用协议进行集成并不关键。但如果要上线统一患者档案这样的业务,就需要整合和泛化数据并进行存储,如何利用这份数据就是协议可以发挥作用的地方了。
Jeff ( @Jieliang.Liu ):日本群马大学医学部附属医院就用我们的产品作为信息平台使用。应用InterSystems IRIS作为信息交换引擎从HIS、检验这样的系统里通过实时和批量数据同步接口获取数据,转换为FHIR并存储在InterSystems IRIS的FHIR存储库里。这个FHIR存储库所承担的就是临床数据中心的角色。它们的科研系统REDCap则通过FHIR对这个存储库进行查询并获得患者档案。现在这个项目也还在扩展,通过和Apple的技术融合实现患者端对自己的临床档案的访问。
祝麟 ( @Lin.Zhu ):是的,FHIR API本身就能支持数据利用和数据共享。院里要做科研的话也可以通过FHIR API查询符合条件的患者集合,比如查2021年11月到12月间就诊的低密度脂蛋白低于100的II型糖尿病患者,这是个典型的数据利用问题。如果不借助一份整合好的数据,只凭借单纯的集成平台,那就需要把这样的请求解析并分解到不同的业务系统,再把结果整合起来,才能获得结果。实施难度大,业务压力大不说,效率还没有保障。直接从支持FHIR的存储库里获取数据要高效得多。
Jeff ( @Jieliang.Liu ):使用FHIR资源仓库还有一大好处是,FHIR资源仓库并不意味着中心化的存储,而是由一系列物理上分布的资源仓库组成。这些离散的仓库各自保存特定的数据,通过资源间的相互引用形成逻辑上的统一。由于这种引用本质上松耦合,因此能够形成一个逻辑上整合的数据中心。也因为物理离散而逻辑统一,FHIR存储库非常适合用在微服务架构中。当然无论如何,物理上分布的数据也仍然需要通过FHIR统一逻辑概念和语意,以便在异构的系统间和组织机构间进行共享。
因此在应用FHIR相关的技术方面,FHIR接口是个基本的合规要求,多Profile的支持和FHIR存储库则更加关键,这是两个会直接影响FHIR是否能落地的重要特性。
#小谈互联互通#
菁伟 (@Jingwei.Wang ):标准接口和整合数据存储,这个概念听着很耳熟。
Jeff ( @Jieliang.Liu ):当然。一是互联互通的推荐架构里,是包含临床数据中心的,也是对整合应用数据提出了要求。另外,InterSystems在介绍方案时,通常也是把集成平台、数据中心看作是一个解决方案中的两个组成部分来看的。
祝麟 ( @Lin.Zhu ):没错,随着互联互通这项工作的逐渐推广,相信各家医院和区域数据中心都会收到越来越多数据开放和应用的需求。基于FHIR的数据交换和数据利用会经历越来越多的讨论,我们也会见到大量的交互场景通过FHIR实现的案例,以及基于FHIR特性的智能应用的出现。
菁伟 (@Jingwei.Wang ):感谢两位工程师与大家分享FHIR的案例和FHIR协议落地时所需要的平台能力。FHIR除了资源和接口的定义之外,还有许多特性能够帮助医疗机构打通数据流程。作为一个面向互操作性的协议,相信未来我们还会见到更多通过FHIR支撑的业务场景。
文章
Michael Lei · 五月 1, 2022
临床研究必须与健康数据相连
就在不久以前,临床科研人员还需要依靠三联的纸质NCR表格,手工收集从堆积如山的手写电子病历中提炼出来的病人数据。从又大又重的《医师案头参考》(PDR)撕下几页,通过传真机发送给FDA,用于药物安全报告。业内专业人士接受了大量的培训,以确保数据经过源文件验证、双键处理,并在经过看似无休止的查询以纠正错误之后,保证其符合目的。
值得庆幸的是,随着电子健康档案的广泛采用,健康数据的数字化,这一过程得到了极大的改善。但是,鉴于临床研究进展缓慢,特别是精美的Excel表格仍由人工数据摘要完成,该领域早该有更多的技术变革,特别是围绕释放医疗互操作性的全部好处。如果我们能做到这一点,生命科学公司将有机会利用宝贵的健康数据来确保病人的安全,优化新药的疗效,并使临床开发过程更加高效,减少错误。
我们可能会比你想象的更快地将临床研究与健康数据联系起来。为什么?火神计划(Project Vulcan)正在进行中。这个项目组是最近在HL7的FHIR加速器项目中创建的,它已经召集了来自医疗、技术和生命科学领域的30多个利益相关的组织个和机构,利用FHIR这个医疗专用互操作性标准来进行临床和转化研究。自从我们在去年年初加入后,我们高兴的看到火神计划成员制定的早期想法越来越接近于功能现实。
但是,医疗互操作性究竟如何能使同时用药跟踪(在同一时间段内给予两种或多种药物)或不良事件报告(捕捉可能与药物有关的疾病)以及其他临床研究领域受益?这些答案让我们看到了未来。
互操作性彻底改变了不良事件报告
每个新药的批准都是从安全开始的。如果研究人员不能完成临床试验的第一和第二阶段,他们甚至没有机会在更大的人群中研究其药物的疗效。但要证明一种治疗方法是安全的,这就提出了严峻的挑战。
几十年来,业内人士已经知道,一些不良事件在临床试验中被忽略了。比方说,一个研究对象在其心脏病专家的照料下测试一种新的心脏候选药物时,出现了皮疹并去看皮肤科医生。一个月后,当该受试者来到他们的下一次研究访问时,他们可能忘记告知研究团队他们最近的诊断--由正在测试的研究药物引起的新皮疹。
现在,太多时候,故事就在这里结束。这条信息--以及与之相关的、可能说明药物安全性的所有信息--已经消失。其他真实世界的数据也是如此,比如病人服用的额外药物,但由未参与研究的护理团队成员开出。或者仅仅是网络外的访问和程序。
然而,如果火神计划成功,研究人员将有更好的机会通过参与者的电子病历健康档案和临床研究数据记录之间的联系来捕捉这些关键信息。
基于FHIR的互操作性还可以简化不良事件报告,使患者的完整快照可以向关键利益相关者提供重要数据。任何人--患者、研究人员或监管机构--都不会再担心出现问题,而这些问题本可以通过与真实世界的数据建立可靠的联系而轻松避免。
互操作性支持表型数据共享Phenopackets(开放的可计算的生物信息Phenopackets.org)和临床实验方案日程
除了电子病历数据可以为临床试验提供信息外,火神项目的目标之一是,希望借助于FHIR,临床试验中收集的数据可以被更广泛地访问, 而且可以用于采取行动。全球基因组学与健康联盟(GA4GH)的表型数据交换标准有望使业界分享脱敏后(去掉身份识别)的病例级病人信息,以用于登记册、知识库出版物和期刊。
任何从事临床试验的人都知道,尽管对实现研究目标至关重要,但临床试验的分步指南,很容易出现疏忽和偏离计划的情况。主要的问题是什么?就是人为失误。但通过 "火神计划",基于FHIR的分步指南活动安排表很快就能实现调度自动化,减少对手工数据输入的需求,并提高研究程序的一致性。
我们已准备好将FHIR引入临床研究
FHIR已经在推进互操作性和消除障碍。在InterSystems,我们每天都能看到FHIR对互操作性的影响,无论是通过创建用于临床决策支持的移动端APP,还是通过医院不同部门和医疗机构之间的数据无缝流动。这就是我们将FHIR纳入我们的技术栈的原因。
当火神项目实现其目标时,InterSystems将准备好立即为临床研究带来快速、无缝的数据交换。我们没有任何理由推迟更安全、更有效的药物的到来。
作者是:InterSystems公司生命科学顾问Matthew Stannard
原文--https://www.intersystems.com/pulse-blog/unlocking-benefits-of-healthcare-interoperability
文章
姚 鑫 · 八月 7, 2021
# 第七十三章 方法关键字 - Requires
指定用户或进程调用此方法必须拥有的权限列表。
# 用法
要指定此方法应限于具有指定权限的用户或进程,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ Requires = privilegelist ]
{ //implementation }
```
其中,`privilegelist` 要么是单个特权,要么是用引号括起来的以逗号分隔的特权列表。
每个权限都采用`resource:permission`的形式,其中`permission`是`Use`、`Read`或`Write`(或单字母缩写`U`、`R`或`W`)。
若要为一个资源`resource`指定多个权限,请使用单字母缩写。
# 详情
用户或进程必须拥有权限列表中的所有权限才能调用该方法。
调用没有指定权限的方法会导致``错误。
如果方法从超类继承了`Requires`关键字,则可以通过设置关键字的新值将其添加到所需特权的列表中。
不能以这种方式删除所需的特权。
# 默认
如果忽略此关键字,则调用此方法不需要特殊权限。
# 示例
下面的方法需要对`Sales`数据库的读权限和对`Marketing`数据库的写权限。
(注意,如果一个数据库有写权限,它会自动有读权限。)
```java
ClassMethod UpdateTotalSales() [ Requires = "%DB_SALES: Read, %DB_MARKETING: Write" ]
{
set newSales = ^["SALES"]Orders
set totalSales = ^["MARKETING"]Orders
set totalSales = totalSales + newSales
set ^["MARKETING"]Orders = totalSales
}
```
若要为一个资源指定多个权限,请使用单字母缩写。
以下两种方法在功能上是等价的:
```java
ClassMethod TestMethod() [ Requires = "MyResource: RW" ]
{
write "You have permission to run this method"
}
ClassMethod TestMethodTwo() [ Requires = "MyResource: Read, MyResource: Write" ]
{
write "You have permission to run this method"
}
```
# 第七十四章 方法关键字 - ReturnResultsets
指定此方法是否返回结果集(以便`ODBC`和`JDBC`客户机能够检索它们)。
# 用法
要指定该方法返回至少一个结果集,请使用以下语法:
```java
ClassMethod name(formal_spec) As returnclass [ ReturnResultsets, SqlName = CustomSets, SqlProc ]
{ //implementation }
```
否则,忽略此关键字或将单词`Not`紧接在关键字之前。
# 详解
此关键字指定该方法至少返回一个结果集。如果方法可能返回一个或多个结果集,则将此关键字设置为`true`。如果没有,`xDBC`客户端将无法检索结果集。
# 默认
如果省略此关键字,`xDBC`客户端将无法检索结果集。
# 第七十五章 方法关键字 - ServerOnly
指定此方法是否将被投影到Java客户端。
# 用法
将方法投影到`Java`客户端,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ ServerOnly=n ]
{ //implementation }
```
其中`n`为下列其中之一:
- `0`表示该方法可以映射。
- `1`表示该方法不会被映射。
# 详解
该关键字指定方法不会被投影到`Java`客户机。
# 提示
要查看类的哪些方法是`server-only`的,请在终端中使用以下实用程序:
```java
do dumpMethods^%occLGUtil("Sample.Person")
```
参数是完全限定类名。
该实用程序生成一个报告,该报告指出关于每个方法的基本信息:该方法是否为存根,该方法是否仅为服务器,以及(如果该方法是从某个属性派生的)派生该方法的属性。
# 默认
如果忽略这个关键字,这个方法如果是存根方法就不会被投影(但是如果不是存根方法就会被投影)。
```java
DHC-APP>do dumpMethods^%occLGUtil("Sample.Person")
Method=%%OIDGet UseStub=0 serveronly=1
Method=%%OIDIsValid UseStub=1 serveronly=0 PropName=%%OID MethodName=IsValid
Method=%%OIDSet UseStub=1 serveronly=1 PropName=%%OID MethodName=Set
Method=%1Check UseStub=0 serveronly=1
Method=%AcquireLock UseStub=0 serveronly=1
Method=%AddJrnObjToSyncSet UseStub=0 serveronly=1
Method=%AddToSaveSet UseStub=0 serveronly=1
```
# 第七十六章 方法关键字 - SoapAction
指定当通过HTTP将此方法作为`web方法`调用时,要在`HTTP`头中使用的`SOAP`操作。仅适用于定义为`web服务`或`web客户端`的类。
# 用法
要指定将此方法用作`web方法`时在HTTP头中使用的`SOAP`操作,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ WebMethod, SoapAction = soapaction ]
{ //implementation }
```
其中`soapaction`是下列之一:
- `“[default]”—SOAP`操作的默认值,即`NAMESPACE/Package.Class.Method`
- `"customValue"` -使用`customValue`作为`SOAP`操作。
该值应该是标识`SOAP`请求意图的`URI`。
如果指定了一个自定义的值,它必须在`web服务`的每个`web方法`中是唯一的,或者你必须为每个`web方法`指定`SoapRequestMessage`关键字(并且为该关键字使用唯一的值)。
- "" -使用空值作为`SOAP`操作。这种情况很少见。
# 详情
`web方法`的`SOAP`动作通常用于路由请求`SOAP消息`。
例如,防火墙可以使用它来适当地过滤`SOAP请求消息`。
InterSystems IRIS `web服务`使用`SOAP操作`(与消息本身结合)来确定如何处理请求消息。
该关键字允许指定在作为`web方法`调用此方法时使用的HTTP `SOAP`动作。
对于`SOAP 1.1`, `SOAP`动作包含在`SOAPAction HTTP`报头中。
对于`SOAP 1.2`,它包含在`Content-Type` HTTP报头中。
# 默认
如果忽略`SoapAction`关键字,`SOAP`动作的形式如下:
```java
NAMESPACE/Package.Class.Method
```
其中`NAMESPACE`是`web服务`的`NAMESPACE`参数的值,`Package.Class`是`web服务`类的名称,`Method`是`web方法`的名称。
# WSDL的关系
`SoapAction`关键字影响`web服务`的`WSDL`中`的`部分。
例如,以下web方法:
```java
Method Add(a as %Numeric,b as %Numeric) As %Numeric [ SoapAction = MySoapAction,WebMethod ]
{
Quit a + b
}
```
对于这个`web服务`,`WSDL`的``部分如下所示:
```xml
```
默认情况下,如果方法没有指定`SoapAction`关键字,``元素可能会像下面这样:
```xml
```
如果使用`SOAP`向导从`WSDL`生成 `web服务`服务或客户端,将此关键字设置为适合于该`WSDL`的关键字。
# 对消息的影响
对于前面显示的`web方法`,`web服务`期望收到以下形式的请求消息(对于SOAP 1.1):
```xml
POST /csp/gsop/ROBJDemo.BasicWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
SOAPAction: MySoapAction
Content-Length: 379
Content-Type: text/xml; charset=UTF-8
...
```
默认情况下,如果方法没有指定`SoapAction`关键字,`SoapAction`行可能会像下面这样:
```xml
SOAPAction: http://www.mynamespace.org/ROBJDemo.BasicWS.Add
```
注意,对于`SOAP 1.2`,细节略有不同。
在这种情况下,`web服务`期望收到如下形式的请求消息:
```xml
POST /csp/gsop/ROBJDemo.BasicWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
Content-Length: 377
Content-Type: application/soap+xml; charset=UTF-8; action="MySoapAction"
...
```
文章
Michael Lei · 二月 9, 2023
嗨,大家好
在本文中,我列出了 5 个有用的 SQL 函数,并附有解释和查询示例👇🏻这5个功能是
COALESCE合并
RANK排序
DENSE_RANK密集排序
ROW_NUMBER行号
SUM()获取运行总计的函数
那么让我们从 COALESCE 函数开始
#合并
COALESCE 函数按从左到右的顺序计算表达式列表,并返回第一个非 NULL 表达式的值。如果所有表达式的计算结果为 NULL,则返回 NULL。
以下语句将首先返回非空值,即“intersystems”
SELECT COALESCE ( NULL , NULL , NULL , 'intersystems' , NULL , 'sql' )
让我们创建下表以获取更多示例
CREATE TABLE EXPENSES( TDATE DATE NOT NULL , EXPENSE1 NUMBER NULL , EXPENSE2 NUMBER NULL , EXPENSE3 NUMBER NULL , TTYPE CHAR ( 30 ) NULL )
现在让我们插入一些虚拟数据来测试我们的功能
INSERT INTO sqluser.expenses (tdate, expense1,expense2,expense3,ttype ) SELECT {d '2023-01-01' }, 500 , 400 , NULL , 'Present' UNION ALL SELECT {d '2023-01-01' }, NULL , 50 , 30 , 'SuperMarket' UNION ALL SELECT {d '2023-01-01' }, NULL , NULL , 30 , 'Clothes' UNION ALL SELECT {d '2023-01-02' }, NULL , 50 , 30 , 'Present' UNION ALL SELECT {d '2023-01-02' }, 300 , 500 , NULL , 'SuperMarket' UNION ALL SELECT {d '2023-01-02' }, NULL , 400 , NULL , 'Clothes' UNION ALL SELECT {d '2023-01-03' }, NULL , NULL , 350 , 'Present' UNION ALL SELECT {d '2023-01-03' }, 500 , NULL , NULL , 'SuperMarket' UNION ALL SELECT {d '2023-01-04' }, 200 , 100 , NULL , 'Clothes' UNION ALL SELECT {d '2023-01-06' }, NULL , NULL , 100 , 'SuperMarket' UNION ALL SELECT {d '2023-01-06' }, NULL , 100 , NULL , 'Clothes'
选择数据
现在通过使用 COALESCE 函数,我们将首先从 expense1、expense2 和 expense 3 列中检索非 NULL 值
SELECT TDATE, COALESCE (EXPENSE1,EXPENSE2,EXPENSE3), TTYPE FROM sqluser.expenses ORDER BY 2
#RANK vs DENSE_RANK vs ROW_NUMBER 函数
RANK() — 为同一窗口框架内的每一行分配一个排序整数,从 1 开始。如果多行包含相同的窗口函数字段值,则排序整数可以包含重复值。
ROW_NUMBER() — 为同一窗口框架内的每一行分配一个唯一的顺序整数,从 1 开始。如果多行包含相同的窗口函数字段值,则每一行都分配一个唯一的顺序整数。
DENSE_RANK() 离开 重复排名后没有间隙。
在 SQL 中,您可以通过多种方式为行分配排名,我们将通过示例深入探讨。再次考虑与之前相同的示例,但现在我们想知道最高费用是多少。
我们想知道我在哪里花的钱最多。有不同的方法可以做到这一点。我们可以使用所有 ROW_NUMBER() , RANK() 和 DENSE_RANK() 三个函数 。我们将使用所有三个函数对上一个表进行排序,并使用以下查询查看它们之间的主要区别是什么:
下面是我们的查询:
这三个功能之间的主要区别在于它们处理相同值的方式。我们将进一步深入探讨它们的差异:
RANK()----从 1 开始为每一行返回一个唯一的数字。当数值相等时,如果没有定义第二个条件,它会任意分配一个数字。
ROW_NUMBER() -----从1开始为每一行返回一个唯一的数字,除非数值相同,否则它将分配相同的数字。同样,重复的排名后会有空格。
DENSE_RANK()----- 重复排名后不留空格。
#计算运行总计
运行总计可能是最有用的窗口函数之一,尤其是当您想要可视化增长时。使用SUM()的窗口函数,我们可以计算累积聚合。
为此,我们只需要使用聚合器SUM()对变量求和,但使用 TDATE 列对该函数进行排序。
您可以观察到相应的查询如下:
正如您在上表中看到的那样,现在我们有了随着日期过去所花金额的累计汇总。
结论
SQL 很棒。上面使用的函数在处理数据分析、数据科学和任何其他与数据相关的领域时可能很有用。
这就是为什么我们应该注意不断提高 SQL 技能的原因。
谢谢
文章
姚 鑫 · 八月 14, 2021
# 第101章 属性关键字 - InitialExpression
指定此属性的初始值。
# 用法
要指定此属性的初始值,请使用以下语法:
```java
Property name As classname [ InitialExpression = initialexpression ];
```
其中,`initialexpression`是用大括号括起来的常量或ObjectScript表达式。
# 详解
此关键字指定属性的初始值。该值是在创建新实例时由类的`%New()`方法分配的。(如果属性是瞬态的的,则其初始值由创建实例时`%New()`调用的代码或实例从磁盘加载到内存时`%OpenId()`调用的代码确定。)
初始表达式的值必须适合给定的属性类型。
表达式可以是任意复杂的,有以下限制:
- 初始表达式不能引用其他属性。也就是说,诸如{`..therPropertyname`}这样的表达式无效。
- 初始表达式不能实例化对象,也不能包括对象引用。
- 初始表达式不能调用实例方法(只能调用类方法)。
- 必须在ObjectScript中指定初始表达式。
- 表达式执行的代码不应报告错误。InterSystems IRIS不提供处理表达式返回的错误的方法。
- 如果表达式执行的代码导致发生其他处理,则InterSystems IRIS不提供处理该处理结果的方法。
子类继承`InitialExpression`关键字的值并可以重写它。
# 默认
`InitialExpression`关键字的默认值为`NULL`。
# 示例
下面显示了几个使用ObjectScript表达式的示例:
```java
Property DateTime As %Date [ InitialExpression = {$zdateh("1966-10-28",3)} ];
Property MyString As %String [ InitialExpression = {$char(0)} ];
/// 此参数使用参数值进行初始化
Property MyProp As %String [ InitialExpression = {..#MYPARM} ];
/// 这是由一个类方法初始化的
Property MyProp2 As %Numeric [ InitialExpression = {..Initialize()} ];
```
# 第102章 属性关键字 - Internal
指定此属性定义是否为内部定义(不显示在类文档中)。
# 用法
要指定此属性为内部属性,请使用以下语法:
```java
Property propertyname As classname [ Internal ];
```
否则,请省略此关键字或将该词放在该关键字之前。
# 详解
类文档中不显示内部类成员。如果希望用户看到某个类,但不能看到其所有成员,则此关键字非常有用。
# 默认
如果省略此关键字,则此属性将显示在类文档中。
# 第103章 属性关键字 - Inverse
指定此关系的反面。关系属性需要。不用于其他属性。
# 用法
要在相关类中指定与该关系属性相反的关系属性,请使用以下语法:
```java
Relationship Chapters As Chapter [ Cardinality = cardinality; Inverse = inverse ];
```
其中,`Inverse`是相关类中属性的名称。
# 详解
此关键字指定关系的反向方的名称,即相关类中对应关系属性的名称。反向属性必须存在于相关类中,并且具有正确的基数值。
关系属性需要`Inverse`关键字。非关系属性会忽略它。
# 默认
没有默认值。定义关系时,必须指定逆序关键字。
# 示例
```java
Relationship Chapters As Chapter [ Cardinality = many; inverse = Book ];
```
# 第104章 属性关键字 - MultiDimensional
指定此属性具有多维数组的特征。
# 用法
要指定此属性具有多维数组的特征,请使用以下语法:
```java
Property Data [ Multidimensional ];
```
否则,省略此关键字或将单词Not放在关键字的前面。
# 详解
多维属性不同于其他属性,如下所示:
- IRIS不为其提供属性方法。
- 当对象被验证或保存时,它被忽略。
- 它不会保存到磁盘,除非应用程序包含专门保存它的代码。也就是说,属性也是自动瞬态的。
- 它不能暴露给Java或其他客户端。
- 它不能存储在或通过SQL表公开。
多维属性很少见,但它提供了一种有用的方法来临时包含关于对象状态的信息。
# 默认
如果省略此关键字,则属性不是多维的。
文章
Lilian Huang · 四月 10
社区朋友们好,
传统的基于关键词的搜索方式在处理具有细微差别的领域特定查询时往往力不从心。而向量搜索则通过语义理解能力,使AI智能体能够根据上下文(而非仅凭关键词)来检索信息并生成响应。
本文将通过逐步指导,带您创建一个具备代理能力的AI RAG(检索增强生成)应用程序。
实现步骤:
添加文档摄取功能:
自动获取并建立文档索引(例如《InterSystems IRIS 2025.1版本说明》)
实现向量搜索功能
构建向量搜索智能体
移交至主智能体(分流处理)
运行智能体
1. Create Agent Tools 添加文档摄取功能
Implement Document Ingestion: Automated ingestion and indexing of documents
1.1 - 以下是实现文档摄取工具的代码:
def ingestDoc(self):
#Check if document is defined, by selecting from table
#If not defined then INGEST document, Otherwise back
embeddings = OpenAIEmbeddings()
#Load the document based on the fle type
loader = TextLoader("/irisdev/app/docs/IRIS2025-1-Release-Notes.txt", encoding='utf-8')
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
#COLLECTION_NAME = "rag_document"
db = IRISVector.from_documents(
embedding=embeddings,
documents=texts,
collection_name = self.COLLECTION_NAME,
connection_string=self.CONNECTION_STRING,
)
db = IRISVector.from_documents(embedding=embeddings,documents=texts, collection_name = self.COLLECTION_NAME, connection_string=self.CONNECTION_STRING,)
向量搜索智能体(Vector Search Agent)能够自动完成文档的摄取(ingest)与索引构建(index), 该新功能在InterSystems IRIS 2025.1的数据资源文件夹里) 至 IRIS 向量存储, 只有当数据尚未存在时,才执行该操作。
运行以下查询以从向量存储中获取所需数据:
SELECT
id, embedding, document, metadata
FROM SQLUser.AgenticAIRAG
1.2 - 实现向量搜索功能
以下代码为智能体提供了搜索能力:
def ragSearch(self,prompt):
#Check if collections are defined or ingested done.
# if not then call ingest method
embeddings = OpenAIEmbeddings()
db2 = IRISVector (
embedding_function=embeddings,
collection_name=self.COLLECTION_NAME,
connection_string=self.CONNECTION_STRING,
)
docs_with_score = db2.similarity_search_with_score(prompt)
relevant_docs = ["".join(str(doc.page_content)) + " " for doc, _ in docs_with_score]
#Generate Template
template = f"""
Prompt: {prompt}
Relevant Docuemnts: {relevant_docs}
"""
return template
分流代理处理传入的用户查询,并将其委托给矢量搜索代理,后者执行语义搜索操作,以检索最相关的信息。
2 - 创建矢量存储代理
以下代码实现了 矢量存储代理vector_search_agent :
为智能体协同自定义交接描述规范 handoff_descriptions
明确的操作说明instructions
IRIS向量检索工具iris_RAG_search (使用irisRAG.py 用于文件输入和矢量搜索操作
@function_tool
@cl.step(name = "Vector Search Agent (RAG)", type="tool", show_input = False)
async def iris_RAG_search():
"""Provide IRIS Release Notes details,IRIS 2025.1 Release Notes, IRIS Latest Release Notes, Release Notes"""
if not ragOprRef.check_VS_Table():
#Ingest the document first
msg = cl.user_session.get("ragclmsg")
msg.content = "Ingesting Vector Data..."
await msg.update()
ragOprRef.ingestDoc()
if ragOprRef.check_VS_Table():
msg = cl.user_session.get("ragclmsg")
msg.content = "Searching Vector Data..."
await msg.update()
return ragOprRef.ragSearch(cl.user_session.get("ragmsg"))
else:
return "Error while getting RAG data"
vector_search_agent = Agent(
name="RAGAgent",
handoff_description="Specialist agent for Release Notes",
instructions="You provide assistance with Release Notes. Explain important events and context clearly.",
tools=[iris_RAG_search]
)
3 - 移交分流 (主要代理)
以下代码实现了将处理过的查询路由到分流代理(主协调器)的切换协议:
triage_agent = Agent(
name="Triage agent",
instructions=(
"Handoff to appropriate agent based on user query."
"if they ask about Release Notes, handoff to the vector_search_agent."
"If they ask about production, handoff to the production agent."
"If they ask about dashboard, handoff to the dashboard agent."
"If they ask about process, handoff to the processes agent."
"use the WebSearchAgent tool to find information related to the user's query and do not use this agent is query is about Release Notes."
"If they ask about order, handoff to the order_agent."
),
handoffs=[vector_search_agent,production_agent,dashboard_agent,processes_agent,order_agent,web_search_agent]
)
4 - 运行代理
以下代码:
接受用户输入
唤醒试运行代理triage_agent
将查询路由到矢量搜索处理Vector_Search_Agent 进行处理
@cl.on_message
async def main(message: cl.Message):
"""Process incoming messages and generate responses."""
# Send a thinking message
msg = cl.Message(content="Thinking...")
await msg.send()
agent: Agent = cast(Agent, cl.user_session.get("agent"))
config: RunConfig = cast(RunConfig, cl.user_session.get("config"))
# Retrieve the chat history from the session.
history = cl.user_session.get("chat_history") or []
# Append the user's message to the history.
history.append({"role": "user", "content": message.content})
# Used by RAG agent
cl.user_session.set("ragmsg", message.content)
cl.user_session.set("ragclmsg", msg)
try:
print("\n[CALLING_AGENT_WITH_CONTEXT]\n", history, "\n")
result = Runner.run_sync(agent, history, run_config=config)
response_content = result.final_output
# Update the thinking message with the actual response
msg.content = response_content
await msg.update()
# Append the assistant's response to the history.
history.append({"role": "developer", "content": response_content})
# NOTE: Here we are appending the response to the history as a developer message.
# This is a BUG in the agents library.
# The expected behavior is to append the response to the history as an assistant message.
# Update the session with the new history.
cl.user_session.set("chat_history", history)
# Optional: Log the interaction
print(f"User: {message.content}")
print(f"Assistant: {response_content}")
except Exception as e:
msg.content = f"Error: {str(e)}"
await msg.update()
print(f"Error: {str(e)}")
在行动中观看:
更多细节,请访问 iris-AgenticAI open exchange 页面。谢谢
文章
Claire Zheng · 二月 1, 2021
Hi, 大家好!
我们在开发者社区上发布问题的目的是获得答案。
以下是一个非常简单的准则文档,介绍如何提出问题会获得回答。
当您发布问题时,您需要填写 3 个字段:标题、正文和组。 以及标签。
1. 标题
一个好的标题应该包含问题的简短描述,长度不应超过 80-90 个符号。
但是简短并不表示只有一个词。 以下这些就不是很好的问题标题:Cache、Ensemble、Peace、World。
好问题示例:
使用 SQL 查询列表属性
使用 Record Mapper 时如何忽略 CSV 文件上的Headers
在 Cache´SQL 中使用 $CASE 或 $SELECT 功能
标题中的字母应该大写吗? 按照 英语 的规则——是的!这肯定会提高问题的感知度。
2. 正文
正文应该包含英语或/和 Caché Objecsript、SQL、JS 或其他语言的问题描述。 使用 代码块 突出显示 Caché ObjectScript。
提供产品版本总是有帮助的(在终端中输入 $zversion)。
正文中应该只有一个问题。 如果有两个问题,请发布两个不同的问题。
3. 组
组是必选标签,有助于将您的问题归类到一个 InterSystems 产品(Caché、Ensemble、HealthShare)、技术(DeepSee、iKnow)或服务(在线学习、WRC)。
4. 标签
使用标签可邀请(订阅了不同标签的)专家关注您的问题。 在这里,您可以选择关于开发、测试、变更管理、部署和环境的不同标签。
好问题通常很快就会得到回答。 您可以通过“回答”计数器上的绿色前景注意到已回答的问题。
一定要 将回答标记为已接受(将问题标记为已解决) ,当然前提是回答适合您。
当然,这不是如何提出好问题的完整建议列表。 请在本帖中发表您的意见和想法。
文章
Vivi Zhu · 五月 29, 2022
北京协和医院现公开招聘信息类技术岗位。有关事项公告如下:岗位1:运维工程师任职要求:1.年龄30岁以下,本科及以上学历,计算机相关专业;2.熟悉计算机软硬件技术,熟练排除各种软硬件的故障;有基本的网络知识,了解DNS、DHCP原理,熟练使用Ping、tracert等简单命令;3.有2年以上桌面运维工作经验者优先。
岗位2:数据库管理员任职要求:1. 本科及以上学历,计算机相关专业;2. 精通InterSystems Caché数据库,精通MySQL,SQL Server,熟悉Oracle,精通SQL脚本编写;有丰富数据库管理、运维调优经验;3. 5年以上数据库运维管理经验;4. 有医疗行业经验优先。
岗位3:开发工程师任职要求:1. 本科及以上学历,计算机及相关专业,有2年及以上JAVA WEB软件实际开发工作经验,有JVM调优经验者优先;2. 熟悉SSM和SSH框架;有SpringBoot或者SpringCloud实际开发经验;3. 熟悉html5,css,js 等前端开发技术;对jquery、vue等相关技术熟悉;熟悉websocket等相关技术;4. 熟练使用MySQL,SQL Server,熟悉Oracle,有一定的SQL优化经验;5. 熟练使用各种集成开发环境,Eclipse,Idea,SVN,GIT等,熟悉Linux操作系统。
招聘程序(一)个人应聘2022年6月27日24点前登录北京协和医院官网(学术版)招聘栏注册申请。(二)组织面试在资格审查的基础上按1:3的比例确定面试人选,根据综合成绩确定拟录人选。(三)体检考察对拟录人选进行体检和考察。(四)签订协议体检及考察合格人员签订协议。
官方招聘链接为 https://jobs.pumch.cn/JobManage/WebShowJobDetail.aspx?JobId=bf9dcde8-a3de-4fab-805e-f2582255056d
公告
jieliang liu · 三月 3, 2022
欢迎来到2月22日的社区新闻发布!
我们很高兴为InterSystems的开发者介绍我们全新的社区活动日历:
🎯 https://community.intersystems.com/events
在这个日历中,你将看到特区活动的历史。了解现在或即将发生的活动,查看过去的活动,并观看社区的网络研讨会和聚会的录音。
让我们仔细看看如何使用它。
要进入DC日历,请点击 "活动 "顶部菜单,进入 "活动日历 “部分:
在这个日历中,你会发现现有的和过去的活动,这些活动可以被分为不同的类别:
所有活动
网络研讨会
开发者聚会
比赛
通过点击 "预览模式 "中的事件,你将看到它的公告:
随意使用 "列表模式",它显示事件预告,并有一个选项可以将任何可用的事件添加到你的日历中:
你也可以在右边的小日历中选择任何日期,了解当天有什么活动安排或发生:
此外,你可以通过点击 "新事件 "按钮创建你自己的事件。你将被自动转到事件创建页面。
❗️ 将 "Event"标签添加到帖子中,将打开用于创建活动的特殊字段。
当你在字段中填写了活动名称、注册链接和时间后,你的活动将自动在主页面的 "活动 "块中突出显示。
此外,在你的活动公告中,你会看到:– 带有注册链接的特殊块– 用于快速添加事件到你的日历的按钮
欢迎添加更多关于你的活动的细节,添加简短的描述/直接链接加入/位置。
希望你喜欢我们的更新!
您可以将改进要求和错误报告提交到 DC GitHub. 或者在本帖的评论中发表你的建议。
请继续关注我们的新消息!
文章
姚 鑫 · 六月 6, 2021
# Caché 网络实用工具
# [第一章 发送HTTP请求☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117108190)
# [第二章 设置和获取HTTP标头☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117148255)
# [第三章 发送HTTP请求☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117195938)
# [第四章 收发电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117214514)
# [第五章 向邮件添加附件☆](https://yaoxin.blog.csdn.net/article/details/117248548)
# [第六章 从POP3服务器提取电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117278414)
# [第七章 从POP3服务器提取电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117320147)
# [第八章 处理收到的电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117350781)
# [第九章 创建、编写和阅读MIME邮件☆](https://yaoxin.blog.csdn.net/article/details/117378600)
# [第十章 使用FTP☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117394438)
# [第十一章 发送和接收IBM WebSphere MQ消息☆](https://yaoxin.blog.csdn.net/article/details/117409322)
# [第十二章 IBM WebSphere MQ检索邮件☆](https://yaoxin.blog.csdn.net/article/details/117435132)
# [第十三章 使用SSH☆](https://yaoxin.blog.csdn.net/article/details/117459391)
# [第十四章 其他InterSystems %Net工具☆☆☆](https://yaoxin.blog.csdn.net/article/details/117508484)
# [第十五章 Caché WebSocket☆☆☆](https://yaoxin.blog.csdn.net/article/details/117548341)
# 前言
手册帮助程序员使用%Net包中的一些关键类,这些类为许多有用的Internet协议提供了易于使用的接口。因为这个包的类文档相当广泛,所以本手册提供了一个快速、有条理的概述,而不是深入研究每个参数、属性和方法。熟悉本手册中提到的协议和第三方工具。
# 预告
下一期系列将用一个月的时间连载,**《Caché XML》**,敬请期待。
# 交流群
- QQ群号:410039091
- 笔者QQ:454115408
- 公众号:技术理科直男
- [intersys版主:姚鑫](https://cn.community.intersystems.com/user/236891/posts)
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9VqwzNP-1608850948003)(3E1D939266954ED48BDAEA9B8086B11E)\]](https://img-blog.csdnimg.cn/20201225070433434.png)
# 大型免费课程,进群410039091获取课程目录
- 适合所有阶段程序员,总有一款你遗漏的知识点!
