搜索​​​​

清除过滤器
文章
Kelly Huang · 八月 2, 2023

在本地的K8s 上部署一台FHIR服务器

这是一个使用 IKO 在 k3d 上部署 iris-oauth-fhir 的示例。 * iris-oauth-fhir 是一个示例,用于部署带有 OAuth2 身份验证功能的 FHIR 服务器,InterSystems IRIS for Health 作为资源服务器,Google OpenId 则作为授权服务器。 * k3d 作为一个轻量级封装器,用于在 docker 中运行 k3s (Rancher Lab 的最小 Kubernetes 发行版) * IKO 是一个在 Kubernetes 上部署 InterSystems IRIS for Health 的工具。 2. 目录表 1. K3D + iris-operator + iris-oauth-fhir 2. Table of Contents 2.1. Prerequisites 2.2. Installation 2.2.1. Warning 2.2.2. Build iris-oauth-fhir image 2.2.3. Download k3d 2.2.4. Create a registry 2.2.4.1. add registry to hosts 2.2.4.1.1. mac 2.2.4.1.2. windows 2.3. Start the culster 2.3.1. Check the cluster 2.3.2. Install iris-operator 2.3.2.1. install helm 2.3.2.2. install iris-operator 2.3.3. Install iriscluster 2.3.3.1. What are we going to deploy? 2.3.3.2. Prepare the deployment for the data node 2.3.3.3. Prepare the deployment for the web gateway node 2.3.4. Deploy iriscluster 2.3.5. Deploy ingress 2.4. Easy scale 2.5. Quick init 2.6. Quick deployment 2.1 须知 Docker Git Helm k3d kubectl IKO 2.2 安装 2.2.1 警告 这将是很值得经历的一段漫长的过程,您将学到很多关于 Kubernetes 和 InterSystems IRIS for Health 的知识。 2.2.2 构建 iris-oauth-fhir 镜像 首先克隆下面这个存储库 git clone https://github.com/grongierisc/iris-oauth-fhir 然后按照 README.md 中的说明构建 iris-oauth-fhir 镜像。 接下来我们安装 k3d。 2.2.3 下载k3d curl -s https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash 2.2.4 创建一个注册表 我们必须创建一个注册表,因为目前 Docker Desktop 还没有将其内部注册表用作容器 ID 注册表。有一项实验性功能可将 Docker Desktop 注册表用作容器 ID 注册表,但目前还不稳定。因此,我们将使用 k3d 创建一个注册表。 k3d registry create registry.localhost --port 5000 该命令将在端口 5000 上创建一个注册表。我们将用它来推送图像。这是在 k3d 中使用图像的唯一方法。 现在,我们将把注册表添加到 hosts 文件中。这样,我们就能将其用作 DNS 名称。这一点很重要,因为我们将在部署中使用它。这个 DNS 名称对于我们的主机和 Kubernetes 都是一样的。 2.2.4.1 将注册表添加到主机中 2.2.4.1.1. mac sudo sh -c 'echo "127.0.0.1 k3d-registry.localhost" >> /etc/hosts' 2.2.4.1.2 windows Open Notepad as an administrator. Open the file C:\Windows\System32\Drivers\etc\hosts. Add the following line to the end of the file: 127.0.0.1 k3d-registry.localhost. Save the file and close Notepad. 2.3 启动群集 现在,我们将使用此命令行启动群集: k3d cluster create demo --servers 1 --agents 2 --volume $(pwd)/k8s/data:/var/lib/rancher/k3s/storage@all --registry-use k3d-registry.localhost:5000 -p "8081:80@loadbalancer" -p "4443:443@loadbalancer" --api-port 6550 --volume "$(pwd)/k8s/config/traefik-config.yaml:/var/lib/rancher/k3s/server/manifests/traefik-config.yaml" 有哪些选项 --servers 1 will create one server node, server nodes are the master nodes. --agents 2 will create two agent nodes, agent nodes are the worker nodes. --volume $(pwd)/k8s/data:/var/lib/rancher/k3s/storage@all will mount the k8s/data folder to the cluster. This is where we will store our data. --registry-use k3d-registry.localhost:5000 will use the registry we created before. -p "8081:80@loadbalancer" -p "4443:443@loadbalancer" will expose the port 8081 and 4443 to the host. This is where we will access our cluster. --api-port 6550 will expose the port 6550 to the host. This is where we will access the Kubernetes API. --volume "$(pwd)/k8s/config/traefik-config.yaml:/var/lib/rancher/k3s/server/manifests/traefik-config.yaml" will mount the k8s/config/traefik-config.yaml file to the cluster. This is the configuration file for the ingress controller. This will configure the ingress controller to allow traefik to route the data on the secure port without verification of the certificate. # k8s/config/traefik-config.yaml apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- globalArguments: - "--serversTransport.insecureSkipVerify=true" 2.3.1 检查群集 为了让你了解 Kubernetes 集群的样子,下面是一个示意图: kubectl get nodes 你应该看到如下的内容 NAME STATUS ROLES AGE VERSION k3d-demo-server-0 Ready control-plane,master 10m v1.21.2+k3s1 k3d-demo-agent-0 Ready <none> 10m v1.21.2+k3s1 k3d-demo-agent-1 Ready <none> 10m v1.21.2+k3s1 这意味着集群已准备就绪。现在,您拥有了一个包含一个主节点和两个工作节点的 Kubernetes 集群。 2.3.2 安装 iris-operator 我们现在开始安装 iris-operator。iris-operator是一个 Kubernetes 操作器,用于在 Kubernetes 上部署 InterSystems IRIS for Health。它可在 WRC 或 InterSystems Container Registry 上获取。我们将使用 3.6.6.100 版本。 例如,如果容器注册表有 IKO,可以使用此命令行: docker pull containers.intersystems.com/intersystems/iris-operator-amd:3.6.6.100 现在,我们将标记这个image,将其推送到注册表中: docker tag intersystems/iris-operator-amd:3.6.6.100 k3d-registry.localhost:5000/intersystems/iris-operator-amd:3.6.6.100 继续推送 docker push k3d-registry.localhost:5000/intersystems/iris-operator-amd:3.6.6.100 要安装 Iko 操作员,我们将使用 helm。Helm 是 Kubernetes 的软件包管理器。可在here下载。 2.3.2.1 安装 helm curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh 2.3.2.2 安装 iris-operator helm install intersystems k8s/iris_operator_amd-3.6.6.100/chart/iris-operator 要检查 operator 是否正在运行,可以使用此命令行: kubectl --namespace=default get deployments -l "release=intersystems, app=iris-operator-amd" 你应该看到👇🏻的内容 NAME READY UP-TO-DATE AVAILABLE AGE intersystems-iris-operator 1/1 1 1 2m 2.3.3 安装 iriscluster 2.3.3.1 我们要部署什么 我们需要部署👇🏻的架构 One data node One web gateway node 正是我们在这个 docker-compose 文件中看到的内容: # docker-compose.yaml version: '3.6' services: iris: image: iris-oauth-fhir-iris:latest build: context: . dockerfile: Dockerfile restart: always ports: - 1972 - 8083:52773 - 53773 volumes: - ./:/irisdev/app/ - ./data:/data environment: - ISC_CPF_MERGE_FILE=/irisdev/app/common.cpf - ISC_OAUTH_SECRET_PATH=/irisdev/app/misc/auth/secret.json - ISC_DATA_DIRECTORY=/data/iris webgateway: build: context: ./webgateway args: link: 'iris' port: '52773' image: proxyiris:latest ports: - "8080:80" - "4443:443" volumes: - ./webgateway/CSP.ini:/opt/webgateway/bin/CSP.ini - ./webgateway/httpd-csp.conf:/usr/local/apache2/conf/extra/httpd-csp.conf 几个注意的点: 我们在数据节点中使用了 iris-oauth-fhir-iris:latest 镜像。 该镜像使用三个环境变量: ISC_CPF_MERGE_FILE 用于合并 common.cpf 文件。 ISC_OAUTH_SECRET_PATH 用于设置秘密文件的路径。 ISC_DATA_DIRECTORY 用于设置数据目录。 网络网关节点使用 proxyiris:latest 映像。 该镜像使用两个volumes: CSP.ini 用于配置 CSP 应用程序。 httpd-csp.conf 用于配置 apache 服务器。 因此,在 Kubernetes 部署中,我们必须做同样的事情。 这意味着我们必须 数据节点 向数据节点提供 common.cpf 文件。 同样也要提供 secret.json 文件,以配置 OAuth2 身份验证。 数据目录将作为volume加载。 对于网络网关节点: 向网络网关节点提供一些 CSP.ini 文件。 同样,httpd-csp.conf 文件用于配置 apache 服务器。 2.3.3.2 准备数据节点的部署 为了向数据节点提供 common.cpf 文件,我们将使用配置映射。配置映射是用于存储配置文件的 Kubernetes 对象。我们将使用本版本库中的 common.cpf 文件。 下面是配置映射的示意图: 要创建配置映射,我们将使用以下命令行: kubectl create cm iriscluster-config --from-file common.cpf 为了向数据节点提供 secret.json 文件,我们将使用一个secret。secret是用于存储敏感数据的 Kubernetes 对象。我们将使用该版本库中的 secret.json 文件。 要创建secret,我们将使用以下命令行: kubectl create secret generic iriscluster-secret --from-file misc/auth/secret.json 要将数据目录挂载为volume,这将是自动的。我们将使用 IrisCluster 定义拓扑部分的存储字段,并将其作为默认设置。 我们仍需将 iris-oauth-fhir-iris:latest 映像推送到注册表。我们将使用与之前相同的命令行: docker tag iris-oauth-fhir-iris:latest k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest docker push k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest 2.3.3.3 准备网络网关节点的部署 网络网关节点有点不同,因为我们不会使用 proxyiris:latest 映像。我们将使用 intersystems/webgateway:2023.1.1.380.0-linux-amd64 映像。该镜像可从 InterSystems Container Registry. 上获取。该镜像是原始 Web 网关镜像。 原始网络网关镜像与 proxyiris 镜像有何不同? proxyiris 已用自签证书预配置了 https。 因此,我们必须配置网络网关使用 https。为此,我们将使用一个secret。secret是一个用于存储敏感数据的 Kubernetes 对象。我们将使用该版本库中的 tls.crt 和 tls.key 文件。 要创建secret,我们将使用以下命令行: kubectl create secret tls tls-secret --key k8s/tls/tls.key --cert k8s/tls/tls.crt 好消息是,我们无需配置 CSP 应用程序和 apache 服务器。我们将使用 IrisCluster 定义中拓扑部分的 applicationPaths 和 alternativeServers 字段,并将它们作为默认设置。 在 docker-compose.yaml 文件中,我们必须配置 CSP.ini 文件和 httpd-csp.conf 文件。在 Kubernetes 部署中,我们不需要这样做,因为我们无法提前知道数据节点的 IP 地址。但我们仍然需要告诉 IKO 连接到数据节点的登录名和密码。为此,我们将使用一个secret。secret是一个用于存储敏感数据的 Kubernetes 对象。我们将使用该版本库中的 iris-webgateway-secret 文件。 要创建secret,我们将使用以下命令行: kubectl create secret generic iris-webgateway-secret --from-literal='username=CSPSystem' --from-literal='password=]]]U1lT' 我们仍然需要将 intersystems/webgateway:2023.1.1.380.0-linux-amd64 映像推送到注册表中。我们将使用与之前相同的命令行 docker tag containers.intersystems.com/intersystems/webgateway:2023.1.1.380.0-linux-amd64 k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 docker push k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 2.3.4 部署 iriscluster 现在,我们将安装 IrisCluster。IrisCluster 是一种 Kubernetes 自定义资源,用于在 Kubernetes 上部署 InterSystems IRIS for Health。它定义在 k8s/config/iris-sample.yaml 文件中。 # k8s/config/iris-sample.yaml ## uncommented fields deploy one InterSystems IRIS data server ## WARNING: default password is not reset, to do so include ## configSource below ## include commented fields for purposes described; see documentation at ## https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=AIKO_clusterdef_sample ## update image tags (from ":tag") before using; see list of available images at ## https://docs.intersystems.com/components/csp/docbook/Doc.View.cls?KEY=PAGE_containerregistry apiVersion: intersystems.com/v1alpha1 kind: IrisCluster metadata: name: sample spec: ## provide InterSystems IRIS license key if required # licenseKeySecret: # name: iris-key-secret ## specify files used to customize the configurations of ## InterSystems IRIS nodes, including passwordHash parameter ## to set the default password, securing InterSystems IRIS configSource: name: iriscluster-config ## provide repository credentials if required to pull images # imagePullSecrets: # - name: iris-pull-secret ## provide VolumeSource specifications for certificates for each desired TLS feature ## "common" enables all TLS features, but each particular feature's property is given priority over "common" tls: # common: # secret: # secretName: tls-certs # mirror: # csi: # driver: secrets-store.csi.k8s.io # readOnly: true # volumeAttributes: # secretProviderClass: "my-provider" webgateway: secret: secretName: tls-secret ## specify platform-specific storage class used to allocate storage ## volumes (default: use platform-defined class) # storageClassName: iris-ssd-storageclass ## select update strategy (default: RollingUpdate) # updateStrategy: # type: RollingUpdate ## create external IP address(es)for the cluster ## ("type: LoadBalancer" and "externalTrafficPolicy: Local" are required) # serviceTemplate: # spec: # type: LoadBalancer # externalTrafficPolicy: Local ## define persistent volumes (to be mounted by "volumeMounts:" in node definitions) # volumeClaimTemplates: # - metadata: # name: extra-disk # spec: # accessModes: # - ReadWriteOnce # resources: # requests: # storage: 2Gi ## define ephemeral volumes (to be mounted by "volumeMounts:" in node definitions) volumes: - name: auth-config secret: secretName: iriscluster-secret ## topology: defines node types to be deployed; only "data:" is required topology: data: image: k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest ## set enviroment variable for the container podTemplate: spec: env: - name: ISC_OAUTH_SECRET_PATH value: /auth/secret.json ## deploy a sharded cluster of data nodes and (optionally) compute ## nodes; if not included, "data:" definition in "topology:" deploys ## a single data server, "compute:" adds application servers # shards: 2 ## deploy mirrored data nodes or data server (default: nonmirrored) # mirrored: true ## override default size and other attributes of predefined storage ## volumes for data nodes (additional volume names: storageWIJ, ## storageJournal1, storageJournal2); can also be included in ## "compute:" definition # storageDB: # resources: # requests: # storage: 10Gi # storageClassName: my-storageclass ## constrain nodes to platform-specific availability zones (can be ## included in other node definitions) # preferredZones: # - us-east1-a # - us-east1-b ## mount volumes defined in "volumeClaimTemplates:" (persistent) and "volumes:" (ephemeral) volumeMounts: - mountPath: "/auth" name: auth-config ## deploy webgateway (web server) nodes webgateway: image: k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 type: apache replicas: 1 applicationPaths: - /csp/sys - /fhir/r4 alternativeServers: LoadBalancing loginSecret: name: iris-webgateway-secret ## deploy System Alerting and Monitoring (SAM) with InterSystems IRIS # sam: # image: containers.intersystems.com/intersystems/sam:tag ## deploy InterSystems API Manager (IAM) with InterSystems IRIS # iam: # image: containers.intersystems.com/intersystems/iam:tag 内容太多了!别担心,我们一一做解释 让我们从 configSource 部分开始: ## specify files used to customize the configurations of ## InterSystems IRIS nodes, including passwordHash parameter ## to set the default password, securing InterSystems IRIS configSource: name: iriscluster-config 这是我们之前创建的配置映射。我们将在这里找到 common.cpf 文件。 接下来是 tls 部分: ## provide VolumeSource specifications for certificates for each desired TLS feature ## "common" enables all TLS features, but each particular feature's property is given priority over "common" tls: webgateway: secret: secretName: tls-secret 这是我们之前创建的secret。我们将在这里找到 tls.crt 和 tls.key 文件。 接下来是volumes部分: ## define ephemeral volumes (to be mounted by "volumeMounts:" in node definitions) volumes: - name: auth-config secret: secretName: iriscluster-secret 这是我们之前创建的secret。我们将在这里找到 secret.json 文件。 IrisCluster 定义了如何在 Kubernetes 上部署 InterSystems IRIS for Health。重要的部分是拓扑部分。该部分定义了要部署的节点。在本例中,我们将部署一个数据节点和一个网络网关节点。 让我们看看数据节点的定义: ## topology: defines node types to be deployed; only "data:" is required topology: data: image: k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest ## set enviroment variable for the container podTemplate: spec: env: - name: ISC_OAUTH_SECRET_PATH value: /auth/secret.json volumeMounts: - mountPath: "/auth" name: auth-config 图像字段定义了要使用的图像。我们将使用之前构建的映像。podTemplate 字段定义 Kubernetes pod 模板。env 字段定义要在容器中设置的环境变量。我们将使用该环境变量来设置将创建的秘密文件的路径。podTemplate 相当于 docker-compose.yaml 文件中的 podTemplate。volumeMounts 字段定义了要挂载到容器中的卷。我们将挂载之前创建的秘密。 现在让我们看看网络网关节点的定义: ## deploy webgateway (web server) nodes webgateway: image: k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 type: apache replicas: 1 applicationPaths: - /csp/sys - /fhir/r4 alternativeServers: LoadBalancing loginSecret: name: iris-webgateway-secret 图像字段定义了要使用的图像。类型字段定义要部署的网络网关类型。我们将使用 apache。副本字段定义要部署的网络网关的数量。我们将部署一个。applicationPaths 字段定义路由到网络网关的应用程序路径。我们将把 /csp/sys 和 /fhir/r4 路由到网络网关。alternativeServers 字段定义要使用的替代服务器。我们将使用 LoadBalancing。loginSecret 字段定义连接网关和数据节点的登录名和密码。 要部署 IrisCluster,我们将使用以下命令行: kubectl apply -f k8s/config/iris-sample.yaml 要检查 IrisCluster 是否正在运行,可以使用此命令行: kubectl get iriscluster 几分钟后,可以看到👇🏻这些信息 NAME SHARDS MIRRORED STATUS AGE sample Running 2m16s 要了解 IrisCluster 的详细信息,可以使用此命令行: kubectl describe iriscluster sample 要检查 pod 是否正在运行,可以使用此命令行: kubectl get pods 几分钟后,可以看到👇🏻这些信息 NAME READY STATUS RESTARTS AGE intersystems-iris-operator-amd-87c955c9c-4zmrj 1/1 Running 0 44m sample-data-0 1/1 Running 0 4m19s sample-webgateway-0 0/1 ContainerCreating 0 17s 要获取 pod 的详细信息,可以使用以下命令行 kubectl describe pod sample-data-0 2.3.5 部署 ingress 现在,我们将部署一个ingress。ingress 是一个 Kubernetes 对象,用于将流量路由到正确的 pod。我们将使用 k8s/config/ingress.yaml 文件。 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress namespace: default spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: sample-webgateway port: number: 443 该ingress将把流量路由到端口为 443 的 sample-webgateway 服务。 要部署ingress,我们将使用以下命令行 kubectl apply -f k8s/config/ingress.yaml 要检查ingress是否正在运行,可以使用此命令行: kubectl get ingress 要测试整个过程,可以使用以下命令行: curl -k https://localhost:4443/fhir/r4/metadata 恭喜您!已成功的在 Kubernetes 上部署了 iris-oauth-fhir。 2.4 Easy Scale 如果要创建一个新租户,可以使用 iris-demo.yaml 文件。 基本上,它与 iris-sample.yaml 文件相同,只是改变了租户的名称。 你可以使用此命令行进行部署: kubectl apply -f k8s/config/iris-demo.yaml 您可以使用新的 ingress 将流量路由到新租户。 apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: strip-prefix namespace: default spec: stripPrefix: prefixes: - /sample - /demo --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress namespace: default annotations: traefik.ingress.kubernetes.io/router.middlewares: default-strip-prefix@kubernetescrd spec: rules: - http: paths: - path: /sample pathType: Prefix backend: service: name: sample-webgateway port: number: 443 - path: /demo pathType: Prefix backend: service: name: demo-webgateway port: number: 443 新增两条路线 /sample to route the traffic to the sample-webgateway service. /demo to route the traffic to the demo-webgateway service. 您可以缩放 Compte 节点,但需要License Key。 2.5 快速 init Tag images docker tag iris-oauth-fhir-iris:latest k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest docker tag containers.intersystems.com/intersystems/webgateway:2023.1.1.380.0-linux-amd64 k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 docker tag intersystems/iris-operator-amd:3.6.6.100 k3d-registry.localhost:5000/intersystems/iris-operator-amd:3.6.6.100 Push image docker push k3d-registry.localhost:5000/iris-oauth-fhir-iris:latest docker push k3d-registry.localhost:5000/intersystems/webgateway:2023.1.1.380.0-linux-amd64 docker push k3d-registry.localhost:5000/intersystems/iris-operator-amd:3.6.6.100 2.6 快速部署 删除 cluster k3d cluster delete demo 创建 cluster k3d cluster create demo --servers 1 --agents 2 --volume $(pwd)/k8s/data:/var/lib/rancher/k3s/storage@all --registry-use k3d-registry.localhost:5000 -p "8081:80@loadbalancer" -p "4443:443@loadbalancer" --api-port 6550 --volume "$(pwd)/k8s/config/traefik-config.yaml:/var/lib/rancher/k3s/server/manifests/traefik-config.yaml" 安装 iris-operator helm install intersystems k8s/iris_operator_amd-3.6.6.100/chart/iris-operator 创建配置和Secret kubectl create cm iriscluster-config --from-file common.cpf kubectl create secret generic iriscluster-secret --from-file misc/auth/secret.json kubectl create secret tls tls-secret --key k8s/tls/tls.key --cert k8s/tls/tls.crt kubectl create secret generic iris-webgateway-secret --from-literal='username=CSPSystem' --from-literal='password=]]]U1lT' 部署 IrisCluster: kubectl apply -f k8s/config/iris-sample.yaml 部署 Ingress kubectl apply -f k8s/config/ingress.yaml
公告
Claire Zheng · 三月 26

相聚青岛|InterSystems诚邀您共赴2024 CHINC之约,即日起可预约展会Demo咨询

2024年3月29日-3月31日,由国家卫生健康委医院管理研究所主办、《中国数字医学》杂志社有限公司承办的“2024中华医院信息网络大会(CHINC)”将在青岛国际会展中心(红岛馆)举办。InterSystems诚邀您莅临展会,我们带来了内容丰富的Demo演示,包括:InterSystems IRIS 2024.1新特性、 InterSystems IRIS矢量存储和矢量查询、InterSystems FHIR数据资产化解决方案,以及InterSystems IRIS医疗版互联互通套件解决方案。 2024 CHINC期间,InterSystems在合作伙伴东华医为展位(B3馆-A02)设立Demo演示区,即日起即可预约现场Demo咨询,欢迎点击【此处】注册预约。 Demo演示详情 Demo演示: InterSystems IRIS 2024.1新特性 欢迎点击【此处】注册,预约Demo咨询 矢量查询 快速联机备份 (EAP) 多超级服务器端口SuperServer Ports FHIR R4 and R5 Object Model Generation IRIS for Health 支持 Smart on FHIR 2.0.0 FHIR查询的性能提升 新的监控指标 嵌入式Python BPL editor 灵活的Python版本设置 Demo演示: InterSystems IRIS矢量存储和矢量查询 欢迎点击【此处】注册,预约Demo咨询 InterSystems IRIS 提供全SQL的矢量存储和基于矢量相似度矢量查询能力 让业务数据无需迁移到其它平台就可以矢量化存储和查询 进一步通过集成矢量化语言模型、生成式语言模型,利用本地数据实现检索增强生成 Demo演示: InterSystems FHIR数据资产化解决方案 欢迎点击【此处】注册,预约Demo咨询 数据作为生产要素推动数字经济已成为我国国策。要让数据成为生产资料参与交易,则需满足两个条件:其一是建立数据生产、流通、消费环节中数据语义的一致性,使数据质量可被控制,数据价值可被度量;二是对数据进行按需加工,形成品类众多的半成品、预制件,以便适应各类业务场景的需要。也即:交易双方应对数据的含义和价值达成共识,这是能够交易的前提——这也正如在中国制造业高速发展的三十年中,标准化部件和预制件之于大规模生产的作用一样。 数据资产清单就是一种有助于在交易双方建立共识、进一步计量计价的有力工具。在医疗行业,FHIR可以成为语言基础,而SQL Builder则提供了FHIR数据资产清单。因此,“FHIR 存储库+SQL builder”能够构成盘活数据资产价值的解决方案。 InterSystems作为深耕医疗行业40余年的专业厂商,在IRIS for Health(IRIS医疗版)数据平台中,借助HL7 FHIR标准提供的语义基础,推出了集FHIR存储库、SQL Builder、FHIR API等功能于一体的医疗行业数据资产解决方案,用于满足医疗数据资产化的业务需要。 在本次解决方案展示中,我们将演示如何基于FHIR进行数据资产盘点,如何按需投放资产支撑数据集需求和数据应用,一遍盘活已成规模的行业数据。包括:1)使用SQL Builder投射SQL数据,在SQL上进一步支撑以数据集为基础的业务(数据集交易或BI),其中按需投放、最小化原则是重要的规约,而IRIS提供了这两种规约的直接支持。2)使用API支撑的业务,不仅仅是使用CRUD操作,FHIR的Search操作对于支撑CDSS等业务具有重要意义。 Demo演示: InterSystems IRIS医疗版互联互通套件 欢迎点击【此处】注册,预约Demo咨询 InterSystems IRIS医疗版互联互通套件是一个全面的解决方案,提供了一整套工具和标准,旨在支持互联互通成熟度测评和通过测评之后的数据利用。它提供了满足互联互通成熟度测评的符合性基础,包括数据元与值集标准以及基于互联互通规范的69个服务和53个电子病历共享文档。此外,该套件还赋能数据利用,能够将电子病历共享文档转换成FHIR资源并存储,通过FHIR SQL Builder实现FHIR资源到SQL表的转换,从而支持数据分析,这一功能打通了互联互通和FHIR生态系统,促进了医疗数据的流动和分析。 更多活动|答问卷,领取《FHIR白皮书》! 由HL7中国委员会主持撰写的《FHIR白皮书》包含FHIR的设计路线与版本、基本用法、核心定义解读与适配、FHIR的发布实施、本地化方法、国外典型实践和案例、国内案例、基于FHIR的参考架构等丰富的内容。欢迎点击【此处】答问卷,领取《FHIR白皮书》!
文章
Claire Zheng · 五月 18, 2023

【视频】对话:“数据二十条”与FHIR标准

“数据二十条”体现了怎样的制度创新和政策智慧?FHIR将如何发挥作用?来看InterSystems亚太区总经理老卢(Luciano Brustia)与CHIMA主任委员王才有的精彩探讨!
公告
Claire Zheng · 十一月 9, 2023

InterSystems开发者社区中文版第二届技术征文大赛专家评审团亮相!

大家好! 2023年9月19日-11月24日(北京时间),🏆InterSystems开发者社区中文版第二届技术征文大赛🏆正在进行中(←点击链接进入参赛页面,浏览所有参赛文章)!作为此次大赛重要奖项“专家提名奖”评比的重要部分,我们的专家评审团已组建成团! 以下为我们的专家团成员,来自我们的销售工程师团队与WRC支持团队。 @Yunfei.Lei @Peng.Qiao @Lin.Zhu @jieliang.liu7848 @Ida.Yang @Louis.Lu @Hao.Ma @Jingwei.Wang @Tete.Zhang @Tengzhou.Zhuang 我们期待专家评审团对参赛作品的公平审阅与打分。 作为社区成员,您的个人贡献也会对每一篇参赛文章产生影响,每一次浏览和点赞都将助力您喜欢的文章赢得“开发者社区奖”。 欢迎大家积极投稿、点赞、分享、学习! 欢迎积极参加InterSystems开发者社区中文版第二届技术征文大赛
公告
Claire Zheng · 六月 14, 2023

2023 年 6 月 13 日 - 公告:进程内存使用量增加

InterSystems 已纠正导致进程内存使用量增加的缺陷。 具体来说,在对局部变量执行$Order 、 $Query 或 Merge时,会出现本地进程分区内存消耗增加的问题。虽然这对大多数运行环境没有不利影响,但支持大量进程或严格限制每个进程最大内存使用的环境可能会受到影响。某些进程可能会遇到<STORE> 错误。 该缺陷存在于2023.1.0.229.0中,但它被重新发布为2023.1.0.235.1,并包含了修复程序,以加快修正,而无需客户等待维护版本。 此缺陷的更正标识为 DP-423127 和 DP-423237。这些将包含在所有未来版本中。 该缺陷出现在 InterSystems IRIS ® 、InterSystems IRIS for Health ™ 和HealthShare ® Health Connect 的版本 2022.2、2022.3 和 2023.1(内部版本 229)中。如果您运行的是这些版本之一,我们建议升级到 2023.1(内部版本 235)。 此修复也可通过 Ad hoc 分发获得。 如果您对此警报有任何疑问,请联系全球响应中心。
文章
Louis Lu · 八月 30, 2023

使用代码获取数据库剩余空间

大家可以通过InterSystems IRIS 管理门户SMP查看当前数据库剩余空间,路径是 Management Portal: System Operation > Database 当然大家也可以通过下面的代码查看数据库的可用磁盘空间: /// ZISJ.mac Set stmt=##class(%SQL.Statement).%New() Set status=stmt.%PrepareClassQuery("SYS.Database","FreeSpace") Set rs=stmt.%Execute() While rs.%Next() { Write ! For i=1:1:9 { Write rs.%GetData(i),"," } }
文章
姚 鑫 · 七月 25, 2023

第二章 HL7 架构和可用工具

# 第二章 HL7 架构和可用工具 - HL7 模式和消息概述 ## HL7 模式和消息概述 `InterSystems` 产品可以处理和传递 `HL7` 消息,而无需使用架构来解析它,但将架构与消息关联允许执行以下操作: - 解析消息并访问以下字段值: - 数据转换 - 路由规则 - 自定义 `ObjectScript` 代码 - 验证消息是否符合架构。 每个 `HL7` 消息均由消息类型标识,该消息类型在 `MSH` 段 `MessageType` 字段 (`MSH:9`) 中指定。一些消息类型共享相同的消息结构。例如,在`HL7`版本`2.3.1`中,用于预先接纳患者的`ADT_A05`消息具有与`ADT_A01`接纳消息相同的结构。该架构指定 `ADT_A05` 消息具有结构类型 `ADT_A01`。 为了解析 `HL7` 消息,需要两条信息: - 架构类别 — 这是 `HL7` 版本号,例如 `2.3.1` 或 `2.7`,或者它可能是 `InterSystems` 产品中定义的自定义架构的类别。`production` 从业务服务消息模式类别设置或从数据转换设置获取模式类别。尽管 `HL7` 消息在 `MSH` 段 `VersionID` 字段中包含模式版本号 (`MSH:12`),但 `InterSystems` 不使用此值,因为许多应用程序并未一致地设置此字段。 - 结构类型 - `production` 从 `MSH:9` 字段获取消息类型,然后检查架构定义以获取该消息的结构类型。 在某些情况下,使用 `MSH:9.3` 子字段来限定消息类型。 `MSH:9:`3 子字段在 `HL7` 消息中以两种方式使用:1) 作为消息类型的修饰符,或 2) 指定结构类型。如果 MSH:9:3 修改消息类型(通常为数字),InterSystems 产品会将其作为消息类型的一部分。如果 MSH:9:3 指定结构类型(例如 `ADT_A01`),则 `InterSystems` 在确定消息类型和设置 `Name` 属性时都会忽略它。 `InterSystems` 产品不需要 `MSH:9.3` 子字段来确定结构类型,因为它们从架构中获取结构类型。 当业务服务或数据转换创建 `EnsLib.HL7.Message` 对象来存储 `HL7` 消息时,它会组合架构类别和结构类型,并使用以下语法将其存储在 `DocType` 属性中: ``` category:structureType ``` 例如,类别 `2.3.1` 的有效 `DocType` 值包括 `2.3.1:ACK`、`2.3.1:ADT_A17`、`2.3.1:BAR_P01` 和 `2.3.1:PEX_P07`。消息类型可以与结构类型不同,存储在 `Name` 属性中。 如果在 `ObjectScript` 代码中创建 `EnsLib.HL7.Message` 对象,则应根据 `MSH:9` 字段中的值设置 `DocType` 和 `Name` 属性。 `HL7` 标准允许本地扩展,例如尾部 `Z` 段。这些段未在基本架构类别中定义。如果要访问数据转换、路由规则或 `ObjectScript` 中自定义 `Z` 段中的字段,则需要定义指定扩展消息的自定义架构类别。 可以将自定义 `HL7` 架构置于源代码管理之下。启用源代码控制后,源代码控制选项(例如签出和签入)可从主 `HL7` 模式页面使用,但在用于处理自定义模式的其他页面(例如 `HL7` 模式消息类型页面)上不可用。在使用其他页面编辑架构之前,必须从 `HL7` 架构页面检查整个架构。 `HL7` 模式主页面提供了源代码控制输出窗口,该窗口捕获所有相关 `HL7` 模式页面的源代码控制活动。有关设置源代码控制的信息,请参阅将 `IRIS` 与源代码控制系统集成。 这个应该只是讲的HL7 v2 的消息吧?
问题
li liao · 八月 30, 2023

Caché 2016.1 CDC

参考 https://blog.csdn.net/InterSystems/article/details/115350635 搭建 mirror ,获取数据变更,示例给出了获取数据变更的代码: Class ZCustom.MirrorDejournal Extends SYS.MirrorDejournal{ Method RunFilter( MirrorDBName As %String, GlobalReference As %String, RecordType As %String, Address As %Integer) As %Integer{ Set ^CDCLog( $I($^CDCLog))=$lb(MirrorDBName,GlobalReference,RecordType,Address) Quit 1} 示例代码将变更存储在 global 对象 CDCLog 中,想请问下获取变更前后数据,发送到外部系统,有哪些方式? 可以参考我们的CDC系列文章https://cn.community.intersystems.com/node/491941,谢谢!
公告
Claire Zheng · 十月 17, 2023

重要公告:征文大赛将延期至11月24日!欢迎继续投稿,参加InterSystems开发者社区中文版第二届技术征文大赛!

嗨,开发者们! 我们决定将🏆InterSystems开发者社区中文版第二届技术征文大赛 🏆的参赛时间延长至11月24日,请参赛者关注重要时间节点的变化。 📝 2023年9月19日-11月23日(北京时间),文章发布与点赞收集!在社区发布文章后即可开始为您的文章收集点赞。越早发布文章,就越有时间收集更多点赞(这是您获得“开发者社区奖”的关键)。 📝 2023年11月23日(北京时间),专家打分截止(专家提名奖)。 🎉 2023年11月24日(北京时间),公布获奖名单。 欢迎大家继续积极投稿,赢取大奖! 了解参赛规则及文章样例:点击此处 了解奖品详情:点击此处 欢迎投稿参赛! 快乐分享技术,期待您的大作!✨ 🏆InterSystems开发者社区中文版第二届技术征文大赛 🏆(←点击链接进入参赛页面,浏览所有参赛文章)
文章
Michael Lei · 八月 10, 2023

如何比较两个数据库中的多个Global和Routines

InterSystems 常见问题解答 ※如果您想比较使用Mirror、Shadow或其他机制复制的数据库,请使用此方法。 您可以使用 DATACHECK 实用程序来比较Global。请参阅下面的文档。DataCheck 概述 [IRIS] *** Routines比较使用系统例程 %RCMP 或管理门户。 以下是如何在管理门户中使用它。 例如,假设以下Routine位于 USER 命名空间中。 test() public{ quit "hello" } 假设以下Routine位于 USER2 命名空间中。 test() public{ quit "Hello" } 下面是在连接到 USER 命名空间的终端中运行 %RCOM 的结果。 * 在Compare : 中写入Routine名称以及要与: 进行比较的Routine名称要指定另一个命名空间中的Routine,请指定|“命名空间名称”|例程名称.MAC。 用户>执行 ^%RCMP比较:comptest.mac 与:|"USER2"|comptest.macCompare: // [备注] 如果没有可比较的内容,请按 Enter忽略评论差异?否 => 否忽略前导空格?否 => 否显示结果于Device: c:\temp\comp.txt // [备注] 指定文件名时的文件输出 参数? (“WNS”)=>comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************用户> 对比结果如下。 常规比较 2021 年 2 月 2 日 2:31 PM来自目录:c:\intersystems\iris\mgr\user\ comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************竞争测试.MAC+2 退出“你好”......................|“USER2”|comptest.MAC+2 退出“你好”****************************************************** **************************
文章
Weiwei Gu · 九月 14, 2023

VS Code 无法连接到服务器的原因之一

昨天,我在一个客户网站提供从 Studio 迁移到 VS Code 的定制咨询时,就遇到了这种情况。 该站点的服务器已配置为使用delegated authentication,但尚未针对 /api/atelier Web 应用程序设置“delegated”复选框,而 InterSystems ObjectScript 扩展包的成员正是使用该复选框进行连接的。 一旦我们的应用程序设置了其复选框并单击了服务器管理器刷新按钮,就可以在服务器上枚举命名空间。
文章
Weiwei Gu · 八月 14, 2023

调试管理门户加载图片失败的原因

在提交的 WRC case中(Intersystems 全球技术支持响应中心),我们经常看到客户提出有关新 Web 网关设置的问题,其中管理门户加载一半,但不显示图像。本文将解释为什么会出现此错误,以及如何修复它。本说明主要针对服务 InterSystems IRIS 实例的 Web 网关,但相同的说明也应适用于服务 Caché 实例的 CSP 网关。 问题: 您刚刚在独立的 Web 服务器上安装了 Web Gateway。当你去加载管理门户时,你发现它无法显示或加载图像,如下所示: 为什么会发生这种情况: 问题是,为了完整加载管理门户,InterSystems IRIS 必须加载许多 .js、.css 和 .png 文件(静态文件)。如果您看到像上面这样的管理门户页面,请随时打开浏览器的开发人员工具小程序,导航到“网络”选项卡,并确认未提供各种 .js、.css 和 .png 组件: 最初安装 Web Gateway 时,我们仅为以下扩展设置映射: .csp .cls .zen .cxw 这些是客户在自己的自定义应用程序中最常使用的文件扩展名类型,以及用于为 Web Gateway 管理门户提供服务的 .cxw 扩展名。如果您想要加载其他管理门户组件,则必须注册其他文件类型以由 Web 网关提供服务。 如何解决该问题: 要使管理门户完全显示,您必须配置 Web 网关以提供其他文件类型。对于 IIS,您可以为 .js、.png、.css 等扩展名添加单独的映射,也可以添加通配符映射。可以在此处找到有关注册 IIS 的其他文件类型的文档:https: //docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_win#GCGI_registering 如果您在 Unix / Linux 系统上的 Apache 之上运行 Web Gateway,您有几个选择。您可以通过添加其他文件扩展名(如 IIS 上的情况)来配置此功能,也可以添加 CSP 位置指令。请参阅此处的文档了解完整详细信息: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_ux,位于“使用 CSP 注册其他文件类型”下
文章
Qiao Peng · 一月 31

用Java开发互操作产品 - PEX

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

访问 IRIS 终端:Visual Studio Code 用户综合指南

介绍 由于InterSystems最近宣布从2023.2版本开始停止对InterSystems Studio的支持,转而独家开发Visual Studio Code(VSC)IDE的扩展,相信后者比Studio提供了更优越的体验,我们很多开发者都已切换或开始使用 VSC。很多人可能想知道如何打开终端进行操作,因为VSC没有像Studio那样的输出面板,也没有集成的功能来打开IRIS终端,除非下载InterSystems开发的插件。 概括 介绍 解决方案 对于至少具有 IRIS 2020.1 或 IRIS IRIS 2021.1.2 的用户– 使用 Web 终端 对于至少具有 IRIS 2023.2 的用户 – 使用 WebSocket 终端 对于使用基于 Docker 的 IRIS 的用户 对于在本地计算机上使用 2023.2 之前的 IRIS 版本的用户 对于使用 SSH 连接在基于远程服务器的 IRIS 上进行编码的用户 解决方案 在 VSC 中打开终端的方法有多种,具体取决于您使用的具体配置,我在这里总结了适合任何情况的最佳解决方案: 对于至少具有 IRIS 2020.1.1 或 IRIS 2021.1.2 的用户 – 使用 Web 终端 至少拥有 IRIS 2020.1.1 或 IRIS 2021.1.2 且被允许安装外部扩展的用户(某些人可能由于公司有关第三方应用程序的政策而不允许安装),可能会发现 VSC 的 Web 终端扩展很有用。谁不知道, Web 终端是一个基于 Web 的 InterSystems 产品终端,使用 ObjectScript(例如 IRIS、Caché、Ensemble、HealthShare、TrakCare)构建,允许在浏览器中使用更高级版本的终端( 这里是项目页面)。通过此 VSC 扩展,只需单击一下即可直接从 VSC 启动基于 Web 的终端。 要打开 Web 终端,请单击: InterSystems Tools > 选择一个名称空间 > 单击以下图标之一 ( , )在 VSC 终端面板或浏览器上打开 Web 终端(按 Alt 更改默认图标): 对于至少具有 IRIS 2023.2 的用户 – 使用 WebSocket 终端 至少拥有 IRIS 2023.2 的用户可以利用最新版本的 VSC 扩展中包含的新“ WebSocket 终端”功能,并且不需要其他解决方法。 要打开 WebSocket 终端,请单击: InterSystems Tools > 选择一个名称空间 > 单击 Web 终端旁边的图标。 对于使用基于 Docker 的 IRIS 的用户 在 Docker 中使用 IRIS 环境并使用 VSC 的人员可以直接在 Docker 环境中启动终端会话。 单击状态栏中的 Docker 语音,然后选择Open Terminal in Docker 。 我要感谢@Evgeny.Shvarov 有关这一点的图片和解释。 对于在本地计算机上使用 2023.2 之前的 IRIS 版本的用户 对于使用在本地计算机上运行的 IRIS 版本的用户,可以在 VSC 中设置专用的 IRIS 终端: 打开设置.json 文件。您可以通过多种方式找到它,例如单击“视图”> “命令面板”> 输入:“设置”>打开用户设置 (JSON) 在“ terminal.integrated.profiles.windows ”下添加以下代码: "terminal.integrated.profiles.windows" :{ "IRIS Terminal" : { "path" : [ "C:\\InterSystems\\IRISHealth\\bin\\irissession.exe" ], "args" : [ "IRISHEALTH" ], "icon" : "terminal-cmd" } } 注意:插入irissession.exe的正确路径。 C。要从 VSC 打开终端,请导航至:终端>新终端>启动配置文件... > IRIS 终端。 d.终端菜单中现在应该可以使用“IRIS Terminal”语音: 对于使用 SSH 连接在基于远程服务器的 IRIS 上进行编码的用户 对于使用基于可通过 SSH 连接(例如使用PuTTY )访问的远程服务器(例如公司服务器)的 IRIS 版本的人员来说,可以使用远程 - SSH VSC扩展将 VSC 直接连接到服务器。为此: 安装远程 - SSH:编辑配置文件 VSC 扩展; 单击“远程资源管理器”图标 在侧边栏中; 选择“打开 SSH 配置文件” 并打开配置文件,路径为: C:\Users\<用户名>\.ssh\config 在配置文件中插入以下代码: Host my-putty-connection HostName < IP address or server name > User < username > IdentityFile < private key path on your local machine > Port < port > IP 地址和端口对应于 PuTTY 中指定的主机名和端口,用户名是用于访问远程服务器的用户凭据,IdentityFile 是 PuTTY 私钥的文件路径。 注意:VSC 无法读取 PuTTY (.ppk) 生成的私钥的原始格式。要通过 PuTTY 在 VSC 和远程服务器之间建立连接,您必须复制原始私钥并将新版本转换为 .pem 格式。为了进行转换: 启动 PuTTYgen 应用程序 在“文件”菜单下,单击“加载私钥” 选择 .ppk 格式的私钥,然后选择“打开” 在“转换”菜单下,单击“导出 OpenSSH 密钥”(强制使用新文件格式)。 设置扩展名为 .pem 的新名称,然后单击“保存”按钮。 将此新 .pem 文件的路径链接到 VSC 中的IdentifyFile 参数 保存文件。几秒钟后,新连接应出现在“远程资源管理器”面板中; 单击“在新窗口中连接... ”以在新的 VSC 窗口中打开 SSH 连接: 选择远程计算机的操作系统(仅在第一次访问时) 在新窗口中,导航至:终端>新终端(或使用快捷键 Ctrl + ò 或 Ctrl + Shift + ò)。 您现在已连接到远程计算机,并且可以在 VSC 中使用其 IRIS 终端。 注意:此操作仅在您之前通过 PuTTY 启动远程连接时有效,并且在 PuTTY 关闭或未连接到远程服务器时不起作用。此操作不会启动 PuTTY,它仅允许 VSC 连接到 PuTTY 建立的隧道。 要通过 VSC 启动 PuTTY 连接,您可以使用批处理文件(在 Windows 上)。提供的connect_remote.bat文件使用 PuTTY 附带的 Plink 命令来启动会话: @echo off set SESSION="<your saved session name>" plink -load %SESSION% 要启动会话,只需在 VSC 终端中键入.\connect_remote.bat以打开远程连接并插入您的凭据。 注意:后一种方法使您可以访问支持所有 VSC 快捷方式的终端版本!欢迎回来 Ctrl+V,再见 Shift+Insert 🎉
文章
Michael Lei · 八月 31, 2023

常见问题--如何根据ID重建索引

InterSystems 常见问题解答 通过在持久类(=table)定义中提供的%BuildIndices() 方法的参数中指定要重建索引的 ID 的开始值和结束值,您可以仅重建该范围内的索引。 例如,要仅针对 ID=10 到 20 重建 Sample.Person 类中的 NameIDX 索引和 ZipCode 索引,请执行以下代码(ID 范围在第 5 个和第 6 个参数中指定)。 set status = ##class (Sample.Person). %BuildIndices ( $LB ( "NameIDX" , "ZipCode" ), 1 ,, 1 , 10 , 20 ) $LB() 是$ListBuild() 函数。 %BuildIndices() 方法使用它来指定索引名称。 有关如何重建索引的更多信息,请参阅文档。 2018.1版本请参考此文档。