清除过滤器
文章
Jingwei Wang · 八月 30, 2023
案例描述
假设您是一名 Python 开发人员或拥有一支训练有素的 Python 专业团队,但您分析 IRIS 中某些数据的期限很紧迫。当然,InterSystems 提供了许多用于各种分析和处理的工具。然而,在给定的场景中,最好使用旧的 Pandas 来完成工作,然后将 IRIS 留到下次使用。对于上述情况和许多其他情况,您可能需要从 IRIS 获取表来管理 InterSystems 产品之外的数据。但是,当您有任何格式(即 CSV、TXT 或 Pickle)的外部表时,您可能还需要以相反的方式执行操作,您需要在其上导入并使用 IRIS 工具。无论您是否必须处理上述问题,Innovatium让我明白,了解更多解决编码问题的方法总是能派上用场。好消息是,从 IRIS 引入表时,您不需要经历创建新表、传输所有行以及调整每种类型的繁琐过程。本文将向您展示如何通过几行代码快速将 IRIS 表转换为 Pandas 数据框架并向后转换。您可以在我的GitHub上查看代码,您可以在其中找到包含本教程每个步骤的 Jupiter Notebook。
从 IRIS 引入一张Table
当然,您应该首先导入该项目所需的库。
import pandas as pd import sqlalchemy as db
下一步将是在 Python 文件和 IRIS 实例之间创建连接。为此,我们将使用 SQLAlchemy 的函数 create_engine(),并以字符串作为参数。该字符串应包含有关操作方法、用户名和密码、实例的主机和端口以及目标命名空间的信息。有关使用 sqlalchemy-iris 的基本概念的更多信息,请查看我之前的一篇文章SQLAlchemy - 在 IRIS 数据库中使用 Python 和 SQL 的最简单方法。
engine = db.create_engine( "iris://_system:SYS@localhost:1972/SAMPLE" ) connection = engine.connect()
然后,我们可以声明将保存数据帧的变量,并在此连接上调用 Pandas 的 read_sql_table() 函数,将表名指定为带有Schema的字符串。您还可以在另一个参数中声明Schema,事实上,这是更好的选择,因为名称字符串上有一个点在某些情况下可能会导致错误。
df = pd.read_sql_table( "NameAge" , connection, schema= "PD" )
最好仔细检查我们正在使用的表是否存在于我们想要使用的Schema中,当然,首先还要检查是否存在我们需要的Schema。在本文的最后一部分中,您将了解如何执行此操作以及更多提示。从现在开始,如果您有办法使用 Pandas,您可以执行任何您想要的更改和分析,因为您知道该怎么做。探索以下示例以了解其工作原理。
向 IRIS 发送表
在开始之前,让我们更改数据框中的某些内容作为示例。我们可以调整列的值以满足我们的需求(例如,添加行和列等)。经过一番尝试后,我将名称改为小写,并根据现有数据添加了一个新人和一列。您可以查看下图来查看结果。
现在我们可以用一行代码将其发送回 IRIS。我们需要的只是指定引擎和表名。
df.to_sql( "NameAge" , con=engine, schema= "PD" , if_exists= "replace" )
再次,我们需要将Schema与表名分开放在参数中,以避免一些错误和不良行为。除此之外,if_exists 参数指定如果给定Schema中已经存在同名表时要执行的操作。可能的值为:replace、fail(默认)和append。当然,replace 选项会删除表并使用 SQL 命令创建一个新表,而append 会将数据添加到现有表中。请记住,此方法不会检查重复值,因此使用此属性时要小心。最后,失败值会引发以下错误:
请记住,如果您指定的表名不存在,该函数将创建它。
现在,您可以查询 IRIS 以查看新增内容,或者转至管理门户查看专用于 SQL 的部分。请记住,如果您使用替换值,您应该考虑该类的源代码,因为该方法完全重写了它。这意味着如果您实现了任何方法,则应该将它们保留在超类中。
有关 sqlalchemy-iris 的更多提示
如果您有任何问题无法通过其他社区或论坛中共享的与您的应用程序代码相关的信息来解决,您可能会在本节中找到所需的帮助。在这里您将找到有关如何查找有关engine和dialect的详细信息的提示列表。
方言特有的特征
SQL Alchemy 使用根据您的engine自动选择的dialect。当您使用函数 create_engine() 连接到 IRIS 数据库时,选择的dialect是Dmitry Maslennikov 的 sqlalchemy-iris 。您可以使用engine的dialect属性访问和编辑其功能。
engine = db.create_engine( "iris://_system:SYS@localhost:1972/SAMPLE" )
engine.dialect
通过 VSCode 的 IntelliCode 扩展,您可以从此属性中搜索每个选项,或者在CaretDev 的 GitHub上检查源代码。
检查engine中的可用Schema
该dialect中值得强调的一个特殊函数是 get_schema_names() 函数。注意!如果您想避免代码和迭代中出现错误,以下信息可能对您至关重要。
connection = engine.connect()
engine.dialect.get_schema_names(connection)
检查Schema中的可用表
我们来看看类似的情况。您可能还需要了解Schema中的可用表。在这种情况下,您可以使用检查。在引擎上运行函数inspect()并将其保存在变量中。您将使用相同的变量来访问另一个函数 get_table_names()。它将返回一个列表,其中包含指定Schema中的表名称或默认的“SQLUser”。
inspection = db.inspect(engine)
inspection.get_table_names(schema= "Sample" )
此外,如果您想在数据上使用更多 SQL Alchemy 功能,您可以声明一个基础并使其元数据反映引擎中的Schema。
b = db.orm.declarative_base()
b.metadata.reflect(engine, schema= "Sample" )
如果您需要更多信息来解决此问题,请查看SQL Alchemy 文档和sqlalchemy-iris GitHub 存储库。或者,您也可以给我留言或发表评论,我们将一起尝试揭开这个秘密。
最后的考虑因素
本文中的实现方法强调使用 IRIS 实例作为云提供商,并使得可以在不同的基础上进行分析。它可以轻松地同时监控所有这些设备的任何质量问题并比较它们的性能和使用情况。如果您将这些知识与另一篇关于用 Django 制作的门户的文章中描述的开发结合起来,您可以根据需要快速构建一个强大的管理器,用于任意数量的特性和实例。此实现也是将数据从 IRIS 外部移动到构建良好的类的有效方法。由于您可能熟悉 Pandas 中用于处理多种不同语言的其他一些函数,即 CSV、JSON、HTML、Excel 和 Pickle,因此您可以轻松地将 read_sql_table 更改为 read_csv、read_json 或任何其他选项。是的,我应该警告您,某些类型与 InterSystems 的集成不是内置功能,因此可能不是很容易。然而,SQL Alchemy 和 Pandas 的结合在从 IRIS 导出数据时总是会派上用场。因此,在本文中,我们了解到 IRIS 拥有您所需的所有工具,可帮助您进行开发并轻松与系统的现有设备或您的专业知识小工具集成。
文章
Jingwei Wang · 三月 28, 2023
IRIS 配置和用户帐户包含需要跟踪的各种数据元素,许多人难以在 IRIS 实例之间复制或同步这些系统配置和用户帐户。那么如何简化这个过程呢?
在软件工程中,CI/CD 或 CICD 是持续集成 (CI) 和(更常见的)持续交付或(较少见的)持续部署 (CD) 的组合实践集。 CI/CD 能消除我们所有的挣扎吗?
我在一个开发和部署 IRIS 集群的团队工作。我们在 Red Hat OpenShift 容器平台上的容器中运行 IRIS。
如果您当前没有使用 Kubernetes,请不要停止阅读。即使您没有使用 Kubernetes 或在容器中运行 IRIS,您也可能会遇到与我和我的团队面临的挑战类似的挑战。
我们决定将代码与配置分开,并将它们放在不同的 GitHub 存储库中。每次在代码库中进行提交时,都会触发管道运行。结果,从代码库中的文件构建了一个新image。
我们通过将 YAML 文件和其他配置工件添加到部署 GitHub 存储库,将配置定义为以 GitOps 方式使用的代码。 GitOps 是一个软件开发框架,它使组织能够持续交付软件应用程序,同时使用 Git 作为单一事实来源有效地管理 IT 基础设施(以及更多)。 GitOps 的好处之一是能够轻松回滚。您所需要做的就是恢复到 Git 中的先前状态。
DevOps 是软件开发和 IT 行业的一种方法论。作为一套实践和工具使用,DevOps 将软件开发(Dev) 和IT 运营(Ops) 的工作集成并自动化,作为改进和缩短系统开发生命周期的一种手段。 [1]
我在维基百科上读到持续交付是“当团队在短周期内以高速和频率生产软件时,以便可以随时发布可靠的软件,并在决定部署时采用简单且可重复的部署过程。”
同时,维基百科将持续部署定义为“当新软件功能完全自动推出时”。
我们已决定将 YAML 文件存储在部署 GitHub 存储库中。
iris-cpf(上面的第 19 行)指的是一个 ConfigMap,其中包含用于 CPF Merge 的文件。
有多种可用的 CD 管道工具可以将配置作为代码推送部署,而不必手动应用文件。
例如,我的团队使用Argo CD 。它是一个 GitOps 工具,作为 Kubernetes 扩展部署在集群中。它很特别,因为它在集群中具有可见性。它的用户界面在浏览器中显示应用程序状态,因为 Argo CD 是 Kubernetes 扩展。
与仅启用基于推送的部署的外部 CD 工具不同,Argo CD 可以从 Git 存储库中拉取更新的(类似)代码并将其直接部署到 Kubernetes 资源。
像 Argo CD 这样的拉动部署工具将我们的 Kubernetes 集群的实际状态与我们的部署 repo 中描述的期望状态进行比较。
Argo CD 监视我们的部署 repo 和我们的 Kubernetes 集群。我们的部署repo 是唯一的真实来源。如果 GitHub 存储库中发生某些更改,Argo CD 将更新集群以匹配存储库中定义的所需状态。
Argo CD 代理同步 GitHub 存储库和 Kubernetes 集群。如果我们手动应用一个更改,当 Argo CD 将已部署的应用程序同步到 Git 中定义的所需状态时,它将被删除。
为了将不同的配置部署到不同的集群,我们使用Kustomize 。我们在部署仓库中定义了一个基本配置。我们还在部署 GitHub 存储库中定义了覆盖,以便为开发、SQA、阶段和生产等各种环境配置不同的系统默认设置和不同的images。
在第 417 行中,我们确定基于环境的系统默认设置存储在 SDS_ENV.xml 中。
那些没有使用 Kubernetes 的情况呢?我创建了许多可在 Open Exchange 中使用的应用程序。我学习了如何使用 Installer 类在 GitHub 存储库中定义 IRIS 配置,然后构建image并运行容器。
然而,如果在部署应用程序后需要对配置或用户帐户进行一些修改,情况会怎样呢?当涉及到持久卷时,事情就变得复杂了。发生这种情况是因为我们不想丢失存在于持久卷上的数据。
存储在持久卷上的所有这些东西是什么? IRIS 配置保存在数据目录的 mgr 目录中。 CPF Merge 功能应该使我们能够修改 iris.cpf 中的任何配置设置。
我的团队已将大量代码添加到 %ZSTART routines中,这些routines在 IRIS 计算或数据实例启动时执行。我们担心的一个问题是所谓的零大小 CPF 错误。我们经常遇到 IRIS 实例因大小为零的 CPF 文件而崩溃的情况。不幸的是,我们尚未发现该问题的根本原因。我们怀疑 CPF 合并操作以及在 %ZSTART routine中添加和删除的大量Routine、Global和包映射会导致零大小的 CPF 错误。
我们编写了代码来删除所有系统默认设置,并从作为卷安装在 IRIS 容器中的 Kubernetes ConfigMap 中导入它们。事实上,我们有两组系统默认设置:一组是在所有环境中导入的基本设置,另一组是因环境而异的环境特定设置。
我们决定从 XML 文件中导入用户。有时,当我们直接从 %ZSTART routine 执行这段代码时,我们会遇到问题。我们根据 InterSystems 的建议将此代码移至计划任务中。显然,我们发现了一个在某些情况下可能会破坏全局安全性的错误。无论如何,出于某种我现在不记得的原因,当用户帐户导入由计划从 %ZSTART routine 按需运行的任务执行时,此问题不再是问题。这一定是时间问题。计划任务晚于 %ZSTART routine运行。
我们创建了一个自定义密码验证routine来强制执行密码规则。
当我们需要一个新的 Web 应用程序时,我们应该怎么做?除了 CPF Merge,CSP Merge 怎么样?
我相信 Web 应用程序存储在 %SYS IRIS.dat 文件中。我考虑尝试在可以使用 ConfigMap 挂载的文件中定义 Web 应用程序。我们可以将代码添加到 %ZSTART 例程或添加另一个计划任务来查找文件并创建 IRIS 中尚不存在的任何 Web 应用程序。
使用 InterSystems Kubernetes Operator 部署的 Webgateway 容器具有一个持久数据卷,其中包含 CSP.conf 和 CSP.ini。但是,我们还没有实现在添加新的 Web 应用程序时根据需要自动更新这些文件的方法。
Lorenzo Scalese 创建了可在 Open Exchange 中使用的 config-api 和 config-copy 应用程序。他建议在您的应用程序安装程序模块中使用 IRS-Config-API 库。
IRIS-Config-API 可以在一个环境将 IRIS 配置导出到 JSON 文档,并在另一个环境中从 JSON 文档导入 IRIS 配置。
Lorenzo 创建了 iris-config-copy 工具,用于从一个 InterSystems IRIS 实例导出配置并将其导入另一个实例。如果我们在源实例和目标实例上都安装 iris-config-copy,则目标实例使用 REST 从源实例获取配置。
我们需要在源实例上创建一个 Web 应用程序,以使目标实例能够从源实例中检索 IRIS 配置。
Iris-config-copy 可以导出本地实例或远程实例的 IRIS 配置。
有一些方法可以导入特定的配置文件。我们可以导入Security、包含 SQL 连接的globals、CPF 配置数据或任务。
文章
Lilian Huang · 九月 19

您知道当您拿到验血结果时一切看起来都像天书的那种感觉吗? 这就是 **FHIRInsight** 要解决的问题。 它最初的理念是,医疗数据不应该令人恐惧或困惑 – 它应该是我们所有人都能使用的东西。 验血是健康检查中十分常见的检查,但说实话,大多数人都很难理解它们,有时甚至对不擅长实验室工作的医务人员来说也是如此。 FHIRInsight 希望整个过程能够变得更简单,信息更富有实用价值。

## 🤖我们为什么要构建 FHIRInsight
这一切都始于一个简单而有力的问题:
> “为什么验血结果仍然很难读懂 — 有时甚至对医生来说也是如此?”
>
如果您看过化验结果,您可能会看到一大堆数字、隐晦的缩写和“参考范围”,这些可能适用于您的年龄、性别或身体状况,也可能不适用。 毫无疑问,它是一种诊断工具,但如果没有背景信息,它就变成了一个猜谜游戏。 即使是经验丰富的医疗保健专业人员有时也需要交叉参考指导方针、研究论文或专家意见才能理解所有内容。
这正是 **FHIRInsight** 的用武之地。
我们不只是为患者而构建,也为一线医护人员而构建。 为轮流值班的医生,为捕捉生命体征细微变化的护士,为每一位试图在有限的时间和巨大的责任下做出正确决定的医护人员而构建。 我们的目标是让他们的工作简单一点,将密集的临床 FHIR 数据转化为**清晰、有用、以真正的医学科学为基础**的东西, 讲人类语言的东西。
FHIRInsight 不仅仅是解释化验结果。 它还:
- **提供化验结果是轻度、中度还是重度的情境建议**
- 根据临床症状**提出潜在病因和鉴别诊断**
- **提出下一步行动建议** — 是后续检查、转诊还是紧急护理
- **利用 RAG(检索增强生成)**拉取**相关科学文章**,为分析提供支持
想象一下,一位年轻的医生正在查看患者的贫血检查结果。 他们不需要在 Google 上搜索每一个异常值或翻阅医学期刊,而是收到一份报告,上面不仅总结了问题,还引用了最近的研究或世界卫生组织的指导方针来支持这一推理。 这就是将 **AI** 与**针对精选研究的矢量搜索**相结合的力量。
那患者呢?
他们再也不用盯着满屏的数字,猜想“胆红素 2.3 mg/dL”是什么意思,或者他们是否应该担心了。 他们会得到简单、周全的解释。 感觉更像是一场对话,而不是一份临床报告。 一些他们能真正理解的东西 — 并与他们的医生进行讨论,让人感觉更有准备,不那么焦虑。
因为这就是 **FHIRInsight** 的真正意义**:将复杂的医疗数据转化为清晰的见解**,**帮助医疗保健专业人员和患者共同制定更好、更自信的决策**。
## 🔍 表象之下
当然,所有这些表面上的简单,背后可能由一些默默运行的强大技术提供支持。
以下是 FHIRInsight 的构建基础:
- **FHIR (Fast Healthcare Interoperability Resources)** — 这是健康数据的全球标准。 它是我们接收化验结果、患者病史、受众特征和诊疗等结构化信息的方式。 FHIR 是医疗系统使用的语言,我们将这种语言翻译成人们可以真正使用的东西。
- **RAG(检索增强生成)的矢量搜索**:FHIRInsight 通过在**使用 InterSystems IRIS 原生矢量搜索的矢量数据库**中建立**科学 PDF 论文和可信 URL** 索引,增强其诊断推理能力。 当化验结果看起来模棱两可或差别细微时,系统会检索相关内容来支持其建议,它不是从记忆库中进行检索,而是从**真实的、最新的研究**中进行检索。
- **医学推理提示工程**:我们对提示进行了微调,以指导 LLM 识别各种血液相关疾病。 无论是缺铁性贫血、凝血功能障碍、激素失衡还是自身免疫触发因素,提示都会引导 LLM 了解症状、检验室模式和可能病因的变化。
- **LiteLLM 集成**:自定义适配器通过统一的接口将请求路由到多个 LLM 提供程序(OpenAI、Anthropic、Ollama 等),从而轻松实现回退、流式传输和模型切换。
无论您是查看 30 个患者图表的医生,还是想要理解数字含义的患者,都可以在几秒钟内将原始的化验数据转化为**可解释、富有实用价值的医学见解**。
## 🧩 创建 LiteLLM 适配器:使用一个接口管理所有模型
在后台,FHIRInsight 的 AI 赋能报告由 **LiteLLM** 驱动,后者是一个出色的抽象层,可以使我们通过一个 OpenAI 风格的界面调用 **100 多个 LLM**(OpenAI、Claude、Gemini、Ollama 等)。
但是要想将 LiteLLM 集成到 **InterSystems IRIS** 中,需要比隐藏在业务操作中的 Python 脚本更持久、更能重复使用的东西。 所以,我们创建了自己的 **LiteLLM 适配器**。
### 认识 `LiteLLMAdapter`
此适配器类可以处理您希望从一个强大的 LLM 集成中获得的所有东西:
- 接受 `prompt`、`model` 和 `temperature` 等参数
- 动态加载环境变量(例如,API 密钥)
为了将其嵌入我们的互操作性生产中,我们将其包装在一个专门的**业务操作**中:
- 通过标准的 `LLMModel` 设置处理生产配置
- 与 FHIRAnalyzer 组件集成,以实时生成报告
- 作为未来任何需要访问 LLM 的组件的中心“AI 桥”
以下是简化的核心流程:
```
set response = ##class(dc.LLM.LiteLLMAdapter).CallLLM("Tell me about hemoglobin.", "openai/gpt-4o", 0.7)
write response
```
## 🧭 结语
当我们开始构建 FHIRInsight 时,我们的使命很简单**:让验血结果对每个人来说都更容易理解**。 不仅仅是患者,还有医生、护士、护理人员… 任何曾经盯着化验结果苦思冥想的人,“*好吧,这到底是什么意思*?”
我们都有过这样的经历。
通过融合 FHIR 的结构、InterSystems IRIS 的速度、LLM 的智能,以及通过矢量搜索实现真实医学研究的深度,我们创造了一个可以将令人困惑的数字转化成有意义的叙述的工具。 帮助人们对自己的健康做出更明智的决定,甚至可能及早发现一些被忽视的疾病。
但 FHIRInsight 不仅仅与数据相关。 它还与**我们查看数据时的感受**相关。 我们希望它给人一种清晰、支持和赋能的感觉。 我们希望这种体验… 有点像**“氛围编程”医疗保健** — 在智能的代码、优秀的设计和人类同理心方面达到最佳平衡点。
我们希望您能尝试它,打破它,质疑它,并帮助我们改进它。
告诉我们您接下来想看到什么。 更多条件? 更具可解释性? 更加个性化?
这只是一个开端 — 我们希望您能帮助塑造它的未来。
文章
Michael Lei · 四月 13, 2022
这篇文章是对我的 iris-globals-graphDB 应用的介绍。在这篇文章中,我将演示如何在Python Flask Web 框架和PYVIS交互式网络可视化库的帮助下,将图形数据保存和抽取到InterSystems Globals中。
建议
阅读相关文档 使用 Globals
原生 SDK 介绍
PYVIS 互动式网络可视化库
第一步 : 通过使用Python 原生SDK建立与IRIS Globals的链接
#create and establish connection
if not self.iris_connection:
self.iris_connection = irisnative.createConnection("localhost", 1972, "USER", "superuser", "SYS")
# Create an iris object
self.iris_native = irisnative.createIris(self.iris_connection)
return self.iris_native
第二步 : 使用 iris_native.set( ) 功能把数据保存到Globals 里
#import nodes data from csv file
isdefined = self.iris_native.isDefined("^g1nodes")
if isdefined == 0:
with open("/opt/irisapp/misc/g1nodes.csv", newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
self.iris_native.set(row["name"], "^g1nodes", row["id"])
#import edges data from csv file
isdefined = self.iris_native.isDefined("^g1edges")
if isdefined == 0:
with open("/opt/irisapp/misc/g1edges.csv", newline='') as csvfile:
reader = csv.DictReader(csvfile)
counter = 0
for row in reader:
counter = counter + 1
#Save data to globals
self.iris_native.set(row["source"]+'-'+row["target"], "^g1edges", counter)
第三步: 使用iris_native.get() 功能把节点和边缘数据从Globals传递给PYVIS
#Get nodes data for basic graph
def get_g1nodes(self):
iris = self.get_iris_native()
leverl1_subscript_iter = iris.iterator("^g1nodes")
result = []
# Iterate over all nodes forwards
for level1_subscript, level1_value in leverl1_subscript_iter:
#Get data from globals
val = iris.get("^g1nodes",level1_subscript)
element = {"id": level1_subscript, "label": val, "shape":"circle"}
result.append(element)
return result
#Get edges data for basic graph
def get_g1edges(self):
iris = self.get_iris_native()
leverl1_subscript_iter = iris.iterator("^g1edges")
result = []
# Iterate over all nodes forwards
for level1_subscript, level1_value in leverl1_subscript_iter:
#Get data from globals
val = iris.get("^g1edges",level1_subscript)
element = {"from": int(val.rpartition('-')[0]), "to": int(val.rpartition('-')[2])}
result.append(element)
return result
Step4: Use PYVIS Javascript to generate graph data
<script type="text/javascript">
// initialize global variables.
var edges;
var nodes;
var network;
var container;
var options, data;
// This method is responsible for drawing the graph, returns the drawn network
function drawGraph() {
var container = document.getElementById('mynetwork');
let node = JSON.parse('{{ nodes | tojson }}');
let edge = JSON.parse('{{ edges | tojson }}');
// parsing and collecting nodes and edges from the python
nodes = new vis.DataSet(node);
edges = new vis.DataSet(edge);
// adding nodes and edges to the graph
data = {nodes: nodes, edges: edges};
var options = {
"configure": {
"enabled": true,
"filter": [
"physics","nodes"
]
},
"nodes": {
"color": {
"border": "rgba(233,180,56,1)",
"background": "rgba(252,175,41,1)",
"highlight": {
"border": "rgba(38,137,233,1)",
"background": "rgba(40,138,255,1)"
},
"hover": {
"border": "rgba(42,127,233,1)",
"background": "rgba(42,126,255,1)"
}
},
"font": {
"color": "rgba(255,255,255,1)"
}
},
"edges": {
"color": {
"inherit": true
},
"smooth": {
"enabled": false,
"type": "continuous"
}
},
"interaction": {
"dragNodes": true,
"hideEdgesOnDrag": false,
"hideNodesOnDrag": false,
"navigationButtons": true,
"hover": true
},
"physics": {
"barnesHut": {
"avoidOverlap": 0,
"centralGravity": 0.3,
"damping": 0.09,
"gravitationalConstant": -80000,
"springConstant": 0.001,
"springLength": 250
},
"enabled": true,
"stabilization": {
"enabled": true,
"fit": true,
"iterations": 1000,
"onlyDynamicEdges": false,
"updateInterval": 50
}
}
}
// if this network requires displaying the configure window,
// put it in its div
options.configure["container"] = document.getElementById("config");
network = new vis.Network(container, data, options);
return network;
}
drawGraph();
</script>
第五步: 从app.py 主文件调用上面的代码
#Mian route. (index)
@app.route("/")
def index():
#Establish connection and import data to globals
irisglobal = IRISGLOBAL()
irisglobal.import_g1_nodes_edges()
irisglobal.import_g2_nodes_edges()
#getting nodes data from globals
nodes = irisglobal.get_g1nodes()
#getting edges data from globals
edges = irisglobal.get_g1edges()
#To display graph with configuration
pyvis = True
return render_template('index.html', nodes = nodes,edges=edges,pyvis=pyvis)
下面是关于此项目的 介绍视频:
欢迎大家来我们的 Bilibili主页观看更多视频!
谢谢!
文章
姚 鑫 · 九月 30, 2021
# 第三十一章 SQL命令 DROP DATABASE
删除数据库(命名空间)。
# 大纲
```sql
DROP DATABASE dbname [RETAIN_FILES]
```
## 参数
- `dbname` - 要删除的数据库(命名空间)的名称。
- `RETAIN_FILES` - 可选-如果指定,则不会删除物理数据库文件(`IRIS.DAT`文件)。默认情况下,删除`.dat`文件以及命名空间和其他数据库实体。
# 描述
`DROP DATABASE`命令删除命名空间及其关联的数据库。
指定的`dbname`是包含相应数据库文件的命名空间和目录的名称。指定`dbname`作为标识符。命名空间名称不区分大小写。如果指定的`DBNAME`命名空间不存在, IRIS将发出`SQLCODE-340`错误。
`DROP DATABASE`命令是一个特权操作。
在使用`DROP DATABASE`之前,必须以`%Admin_Manage`资源的用户身份登录。
用户还必须拥有用于例程和全局数据库定义的资源的`READ`权限。
如果不这样做,将导致`SQLCODE -99`错误(权限冲突)。
使用`$SYSTEM.Security.Login()`方法为用户分配适当的权限:
```java
DO $SYSTEM.Security.Login("_SYSTEM","SYS")
&sql( )
```
必须具有`%Service_Login:Use`权限才能调用`$SYSTEM.Security.Login`方法。
不管权限如何,`DROP DATABASE`都不能用于删除系统命名空间。尝试这样做会导致`SQLCODE-342`错误。
`DROP DATABASE`不能用于删除当前正在使用或连接到的命名空间。尝试这样做会导致`SQLCODE-344`错误。
还可以使用管理门户删除命名空间。依次选择System Administration、Configuration、System Configuration、Namespaces以列出现有的`Namespace`。单击要删除的命名空间的删除按钮。
## RETAIN_FILES
如果指定此选项,则保留物理文件结构;删除数据库及其关联的命名空间。执行此操作后,后续尝试使用`DBNAME`将导致以下结果:
- `DROP DATABASE`不带`RETAIN_FILES`无法删除此物理文件结构。相反,它会导致`SQLCODE-340`错误(未找到数据库)。
- `DROP DATABASE WITH RETAIN_FILES`还会导致`SQLCODE-340`错误(找不到数据库)。
- `CREATE DATABASE`无法创建同名的新数据库。相反,它会导致`SQLCODE-341`错误(无法为数据库创建数据库文件)。
- 尝试使用此命名空间会导致``错误。
## 服务器初始化和断开代码
服务器初始化代码和服务器断开代码可以通过`$SYSTEM.SQL.Util.SetOption("ServerInitCode",value)`和`$SYSTEM.SQL.Util.SetOption("ServerDisconnectCode",value)`方法分配给命名空间。
可以使用相应的`$SYSTEM.SQL.Util.GetOption()`方法选项来确定当前值。
使用`DROP DATABASE`或其他接口删除命名空间,将删除这些`Server Init Code`和`Server Disconnect Code`值。
因此,删除并重新创建名称空间需要重新指定这些值。
# 示例
```sql
CREATE DATABASE DocTestDB ON DIRECTORY 'c:\InterSystems\IRIS142\mgr\DocTestDB'
```
```sql
DROP DATABASE DocTestDB RETAIN_FILES
```
文章
姚 鑫 · 九月 23, 2022
# 第四十一章 使用多个 IRIS 实例(一)
可以在单个主机系统上安装和运行多个 `IRIS®` 数据平台实例。每个实例都是一个独特的、独立的 `IRIS` 环境。
# 管理 IRIS 实例
有许多方法可以连接和管理 `IRIS` 实例,它可能是安装在给定系统上的几种方法之一。两种最常用的方法如下:
- 安装在 `Windows` 系统上的每个 `IRIS` 实例在系统托盘中都有自己的启动器,除其他选项外,还可以:
- 通过打开管理门户、 `Terminal`和 `Studio` 开发者客户端连接到实例。
- 启动、停止和重新启动实例。
- 打开用户和开发人员文档。
从启动器中,还可以管理多个远程 `IRIS` 实例,包括但不限于运行远程备份、编辑配置设置以及创建和编译远程对象和例程。
- `iris command` 在操作系统命令行上执行 iris 命令可让管理访问 `IRIS` 实例,其中包括其他选项,可以:
- 使用 `Terminal`连接到实例。
- 启动、停止和重新启动实例。
- 显示有关该实例以及系统上安装的其他实例的信息。
要在远程服务器上使用 `iris` 命令,请使用 `Telnet` 或 `SSH` 客户端;要将它与容器化实例一起使用,请在容器内使用它,或者使用 `docker exec` 命令从容器外部运行它。
# 连接到 `IRIS` 实例
`Terminal` 是一个命令行,可以在 `IRIS` 实例的任何命名空间中使用。使用命令 `iris terminal instname` 打开正在运行的实例的终端,其中 `instname` 是在安装时为实例指定的名称。容器化实例通常被命名为 `IRIS`。
使用在安装期间提供的密码或创建的帐户使用预定义的用户帐户之一登录。显示的提示指示登录命名空间,例如:
```java
# iris terminal IRISHealth
Node: intersystems2588, Instance: IRIS27
Username: admin
Password: ********
USER>
```
要退出终端并关闭窗口,请输入命令 `halt`。
当使用`docker exec` 命令打开容器化实例的终端时(如在部署和探索 `IRIS` 中使用 终端进行交互中所述),将自动以 `irisowner` 身份登录,无需进行身份验证。
在 `Windows` 系统上,必须从其位置( `IRIS` 实例的 `install-dir\bin` 目录)执行命令,或在命令中包含完整路径,例如 `c:\InterSystems\IRIS27\bin\iris terminal IRISHealth` .可以执行给定实例的二进制文件以连接到该实例或另一个;无论哪种方式,实例名称都是必需的。
文章
姚 鑫 · 十二月 31, 2023
# 第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串
# 使用 `J` 链接类型传递标准计数字符串
`iris-callin.h` 头文件定义了计数字符串结构 `IRIS_EXSTR`,表示标准 `IRIS` 字符串。此结构包含一个字符元素数组(`8` 位、`16` 位 `Unicode` 或 `32` 位 `wchar t`)和一个指定数组中元素数量的 `int` 值(最多字符串长度限制):
```java
typedef struct {
unsigned int len; /* length of string */
union {
Callin_char_t *ch; /* text of the 8-bit string */
unsigned short *wch; /* text of the 16-bit string */
wchar_t *lch; /* text of the 32-bit string */
/* OR unsigned short *lch if 32-bit characters are not enabled */
} str;
} IRIS_EXSTR, *IRIS_EXSTRP;
```
C Datatype| Input |In/Out |Notes
---|---|---|---
IRIS_EXSTR| 1j or j |1J or J| 8 位国家字符的标准字符串
IRIS_EXSTR |2j or n| 2J or N|16 位 Unicode 字符的标准字符串
IRIS_EXSTR| 4j |4J |32 位字符的标准字符串 wchar_t 字符
`IRIS_EXSTR` 数据结构由 `Callin API`(低级 `InterSystems` 函数调用库)中的函数进行操作。有关详细信息,请参阅使用 `Callin API` 中的“`Callin` 函数参考”。尽管名称相似,`Callin API` 和 `$ZF`标注接口是完全独立的产品)。
以下函数用于创建和销毁 `IRIS_EXSTR` 实例:
- `IrisExStrNew[W][H`] — 为字符串分配请求的存储量,并使用长度和指向该结构的值字段的指针填充 `IRIS_EXSTR` 结构。
- `IrisExStrKill` — 释放与 `IRIS_EXSTR` 字符串关联的存储。
这是一个 `Callout` 库,它使用所有三种链接类型来返回数字字符串:
### 使用 `J` 连接传递字符串
以下三个函数均生成一个随机整数,将其转换为最多包含 `6` 位数字的数字字符串,并使用 `J` 链接返回字符串 。
```java
#define ZF_DLL // Required when creating a Callout library.
#include
#include
#include
#include
int get_sample_L(IRIS_EXSTRP retval) { // 8-bit characters
Callin_char_t numstr[6];
size_t len = 0;
sprintf(numstr,"%d",(rand()%1000000));
len = strlen(numstr);
IRISEXSTRKILL(retval);
if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.ch,numstr,len); // copy to retval->str.ch
return ZF_SUCCESS;
}
int get_sample_LW(IRIS_EXSTRP retval) { // 16-bit characters
unsigned short numstr[6];
size_t len = 0;
swprintf(numstr,6,L"%d",(rand()%1000000));
len = wcslen(numstr);
IRISEXSTRKILL(retval);
if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.wch,numstr,(len*sizeof(unsigned short))); // copy to retval->str.wch
return ZF_SUCCESS;
}
int get_sample_LH(IRIS_EXSTRP retval) { // 32-bit characters
wchar_t numstr[6];
size_t len = 0;
swprintf(numstr,6,L"%d",(rand()%1000000));
len = wcslen(numstr);
IRISEXSTRKILL(retval);
if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.lch,numstr,(len*sizeof(wchar_t))); // copy to retval->str.lch
return ZF_SUCCESS;
}
ZFBEGIN
ZFENTRY("GetSampleL","1J",get_sample_L)
ZFENTRY("GetSampleLW","2J",get_sample_LW)
ZFENTRY("GetSampleLH","4J",get_sample_LH)
ZFEND
```
注意:始终终止 `IRIS_EXSTRP` 输入参数 在前面的示例中,始终调用 `IRISEXSTRKILL(retval)` 以从内存中删除输入参数。即使参数不用于输出,也应该始终这样做。如果不这样做可能会导致内存泄漏。
文章
姚 鑫 · 二月 12, 2023
# 第七十四章 使用 irisstat 实用程序监控 IRIS - 查看 irisstat 输出
# 查看 `irisstat` 输出
可以立即查看 `irisstat` 数据(通过终端)或重定向到输出文件以供以后分析。查看数据的最常见方法是:
注意:当 `IRIS` 被强制关闭时,`irisstat` 会运行以捕获系统的当前状态。作为紧急关闭程序的一部分,输出被添加到消息日志中。
## irisstat 文本文件
`irisstat` 报告可以重定向到文件而不是终端,如果想收集一组 `IRIS` 工具(诊断报告任务、`IRISHung` 脚本、`^SystemPerformance` 实用程序)未提供的一组 `irisstat` 选项,这可能很有用或者如果在运行这些工具时遇到问题。
## 诊断报告任务
诊断报告任务会创建一个包含基本信息和高级信息的 HTML 日志文件,InterSystems 全球响应中心 (WRC) 可以使用该文件来解决系统问题。
注意:诊断报告任务不能在挂起的系统上运行;如果系统挂起,请参阅本附录中的 `IRISHung` 脚本。
## IRISHung 脚本
`IRISHung` 脚本是一个操作系统工具,用于在 `IRIS` 实例挂起时收集系统数据。位于 `install-dir\bin` 目录中的脚本名称是特定于平台的,如下表中指定:
Platform| Script name
---|---
`Microsoft Windows`| `IRISHung.cmd`
`UNIX®/Linux` |`IRISHung.sh`
`IRISHung` 脚本应以管理员权限运行。与诊断报告任务一样,`IRISHung` 脚本运行 `irisstat` 两次,间隔 `30` 秒,以防状态发生变化,并将报告与其他收集的数据一起打包到一个 `html` 文件中。从 `IRISHung` 获取的 `irisstat` 报告使用以下选项
```java
irisstat -e2 -f-1 -m-1 -n3 -j5 -g1 -L1 -u-1 -v1 -p-1 -c-1 -q1 -w2 -E-1 -N65535
```
`IRISHung` 还运行仅使用 `-S2` 选项的第三个 `irisstat`,它将其写入一个单独的输出部分,称为“自诊断”。 `-S2` 选项导致可疑进程留下小型转储;因此,运行 `IRISHung` 可能会收集有关负责挂起的特定进程的信息,而简单地强制实例关闭不会收集此信息。
此外,`IRISHung` 生成的 `irisstat` 输出文件通常非常大,在这种情况下,它们被保存到单独的 `.txt` 文件中。请记住在收集输出时检查这些文件。
## `^SystemPerformance Utility`
`^SystemPerformance` 实用程序收集有关 `IRIS` 实例及其运行平台的详细性能数据。在 `IRIS` 内运行一段可配置的时间,在该时间间隔内收集样本,并在完成时生成报告。
文章
姚 鑫 · 八月 29, 2024
# 第十一章 创建和使用策略 - 在运行时指定策略
# 在运行时指定策略
对于 `IRIS Web` 客户端,可以指定运行时要使用的策略;这将覆盖任何策略配置类。要在运行时指定策略,请设置 `Web` 客户端实例的 `PolicyConfiguration` 属性。该值必须具有以下形式:
```java
Configuration class name:Configuration name
```
其中,配置类名称是策略配置类的完整包和类名,如本主题前面所述,配置名称是该类中策略的 `` 元素的 `name` 属性的值
# 抑制不支持的策略的编译错误
默认情况下,当编译配置类时,如果配置包含 `IRIS` 不支持的任何策略表达式, `IRIS` 会发出错误。要避免此类错误,请在配置类中包含以下内容:
```java
Parameter REPORTANYERROR=0;
```
当从 `WSDL` 生成 `Web` 客户端或 `Web` 服务时,如果 `IRIS` 还生成配置类,则会将此参数设置包含在该类中。
只要有一个受支持的策略替代方案,就可以忽略不受支持的替代方案。
## 编辑生成的策略
如果从 `WSDL` 生成配置类,并且 `WSDL` 位于 `IRIS` 此实例的外部,则必须编辑配置类以包含有关要使用的证书和 `SSL/TLS` 配置的信息。或者可以在运行时指定此信息。
下表给出了详细信息:
If the Generated Policy Includes ...| Do the following ...
---|---
`` |对于附加到客户端的策略,请执行以下操作之一:按照添加扩展属性中的说明编辑此元素。按照指定客户端要使用的 `SSL/TLS` 配置中所述指定 `SSL/TLS` 配置的名称。对于附加到服务的策略,不需要进行任何更改。
`` |对于附加到客户端的策略,请执行以下操作之一:按照添加 `InterSystems` 扩展属性中所述编辑其中的 ``元素。检索凭证集并添加包含的证书,如在运行时添加证书中所述。无论如何,这必须是客户端拥有的凭证集。对于附加到服务的策略,无需进行任何更改。
`` |执行以下操作之一:按照添加 扩展属性中所述编辑其中的 ``元素。检索凭证集并添加包含的证书,如在运行时添加证书中所述。无论哪种情况,这都必须是服务拥有的凭证集。
``| 可选择添加 `cfg:Lifetime` 属性,如添加 扩展属性中所述。默认生存期为 `5` 分钟。
文章
姚 鑫 · 一月 27
[toc]
# 第九章 D - E 开头的术语
#### 显示格式 (display format)
**对象(Objects)**
属性的显示格式是用于显示和输入数据的格式。
#### 分布式数据库 (distributed database)
**系统**
存储在网络中多台计算机上的数据库。当在分布式数据库环境中使用`IRIS` 时,位于一台计算机上的 `ObjectScript` 例程可以在网络中其他计算机的文件保护限制内访问全局。
#### DMNNET
**系统**
处理来自网络的传入全局请求的`IRIS` 进程。它是在系统状态(`%SS`)显示或系统操作实用工具中的进程面板上表示网络守护进程的名称。
#### 点语法 (dot syntax)
**对象(Objects)**
点语法允许获取和设置属性值以及执行方法。它还允许从引用对象访问被引用和嵌入对象的属性和方法。
# 以 E 开头的术语.
#### 可嵌入类 (embeddable class)
**对象(Objects)**
从可嵌入(序列化)类派生的对象可以在内存中独立存在,但在存储到数据库时,只作为持久对象中的数据存储。参见` %SerialObject` 方法。
#### 内嵌 HTML (embedded HTML)
**ObjectScript**
直接嵌入在 `ObjectScript` 方法或宏例程中的 `HTML`。内嵌 `HTML` 必须包含在 `&html` 语句中。
#### 内嵌对象 (embedded object)
**对象(Objects)**
可嵌入类的实例。内嵌对象在内存中是独立的对象,但只能作为持久对象中的数据嵌入存储。
#### 内嵌 SQL (embedded SQL)
**InterSystems SQL**
直接嵌入在 `ObjectScript` 方法或宏例程中的 `SQL`。内嵌 `SQL` 必须包含在 `&sql()` 语句中。
#### 空字符串 (empty string)
**系统**
逻辑上没有任何字符的字符串,通常在文本中表示为 ""。有些资料也将其称为“空值字符串”。
不同语言对空字符串的表示方式不同,这决定了它是否以及如何在计算机内存中占用实际空间。例如,在 `ObjectScript` 中,`""` 不会占用内存空间,而在 `SQL` 中会。还要注意,虽然一个字符串中没有字符,它仍然是一个字符串,并且在不同的上下文中可能会与 `NULL`(未分配)值不同对待。
例如,在以下 `ObjectScript` 代码中:
```java
New A
New B
Set A = ""
Write A
Write B
第一个 Write 语句成功执行(尽管视觉上不明显),而第二个会导致 错误。
```
#### 封装 (encapsulation)
**对象(Objects)**
封装通过呈现一个公开接口来隐藏类的内部细节,该接口概述了类允许的所有交互,而不展示执行这些操作所使用的任何细节。
文章
Jingwei Wang · 十月 9, 2024
Foreign Table 的概念
Foreign Table 是 IRIS SQL 中一种特殊类型的表。它不代表 IRIS 本地全局管理的数据,而是投射出来的,由 “外部服务器 ”管理的外部数据。从 SQL 的角度来看,外部表与普通表一样,可以在查询中使用,没有任何特定限制。
在数据编织中可以帮助整合不同的来源的数据,以支持各种应用、分析并提供智能洞察力。
Foreign Table 和 Linked Table 的区别
Linked Table
Lined Table 不能读取外部文件
对于 JDBC 和 ODBC 的数据源是分开的
Foreign Table
可以读取外部文件
不局限于同一类型的数据源
Foreign Table 的用例
当某个数据集时由外部应用程序在外部数据库中管理,而你的 IRIS 查询需要在该外部数据集中查找某些内容时,您可以使用某种 ETL 流程将数据加载到 IRIS 中,但如果外部数据经常更新,而你的查询需要访问当前的版本,那么这个过程可能会变得很棘手。可以通过 Foreign Table 将数据投射到 IRIS 并在查询时从外部源检索当前数据来解决这个问题。
当您要使用某些基于文件的大型数据集,您只需要偶尔查询一下,用来建立报告或训练模型。由于文件过大,加载文件可能会很麻烦,而且大型数据会占用昂贵的存储空间,而且一旦文件更新,就必须清除并重新加载。Foreign Table可以保持 SQL 查询对数据的可访问性,而不会增加 IRIS 的存储空间占用,也可以会保持最新数据。
Foreign Table 操作步骤
创建外部服务器
CREATE FOREIGN SERVER Sample.PostgresDB FOREIGN DATA WRAPPER JDBC CONNECTION 'postgresConnection'
创建 Foreign Tables
CREATE FOREIGN TABLE Sample.AccountTeam ( TeamID BIGINT, Name VARCHAR(50), CountryCode VARCHAR(10) ) SERVER Sample.PostgresDB TABLE 'Sample.Teams'
查询
SELECT t.Name, COUNT(m.*) FROM Sample.AccountManager m JOIN Sample.AccountTeam t ON m.TeamID = t.TeamID WHERE t.CountryCode = 'UK' AND m.Salary > 100000 GROUP BY t.Name
删除 Foreign Tables
DROP FOREIGN TABLE Example.MyForeignTable
删除外部服务器
DROP FOREIGN SERVER Example.PostgresDB CASCADE
( CASCADE 选项用来删除外部服务器和该外部服务器上定义的所有外部表 )
Foreign Table 演示
如果您想获取更详细的对于Foreign Table的演示,您可以参考 InterSystems 2023 峰会上面的演示示例,该示例使用docker,示例代码请参考Github ,安装后访问http://localhost:8888/
文章
Claire Zheng · 十月 10
InterSystems Data Fabric Studio(IDFS)提供了一种新方法,可在安全可控的环境中将正确的数据在正确的时间提供给正确的消费者。10月17日14:00,我们将举办题为“借助IDFS构建实时数据中枢:从多源整合到智能分析”的线上研讨会,欢迎👉点击此处报名参会!
IDFS是一个完全由云计算管理的解决方案 ,旨在轻松实施和维护智能数据编织(smart data fabric),将不同的数据连接并转换为单一的统一可操作信息源。这一自助式解决方案使数据分析师、数据管理员和数据工程师能够访问和处理业务利益相关者所需的数据,而无需依赖开发人员。
本次分享将展示如何通过多源数据管道自动化构建(定义数据源连接、字段提取与清洗规则)、业务日历驱动的实时调度(周期自动运行数据任务)以实现多种异构数据系统的无缝融合。
您将在此次分享中了解到以下经典场景:
数据工程师视角:通过可视化 “配方” 工具(Recipes)定义数据转换逻辑,无需编码即可完成从数据到分析表的自动化加载;
分析师实践:基于整合后的标准化数据集,快速构建生产效率 BI 立方体,联动Power BI 生成动态看板;
合规管理:利用系统内置的 “快照调度” 功能,自动生成符合审计要求的历史数据存档,结合层级化权限控制(管理员 - 工程师 - 分析师分工),确保数据安全可追溯。
无论您是数据工程师、架构师,还是AI应用开发者,都能在本次研讨会中获取IDFS实战经验、技术架构设计思路与前沿趋势洞察,IDFS助力您轻松部署以数据为中心、连接数据和应用孤岛的AI应用!
我们期待与您的进一步互动。
1. 留言互动
在会议进行过程中,如果您有任何疑问,或者希望与我们进一步讨论,可以在屏幕上方点击“提问”按钮,提交您的问题,我们会在分享结束后整理问题,并通过邮件向您回复。
2. 有奖调研
参会期间,点击屏幕右上角“有奖调研”完成问卷,将有机会获得定制小礼品。
快来加入我们吧٩(๑>◡<๑)۶ 👉点击查看
文章
Nicky Zhu · 一月 18, 2021
在最近的项目里,多方同时连接同一个数据库并执行增删改查等各项数据操作。研发人员不时发现一些数据在不合规的情况下被新增甚至删除。因此,在实际工作中会有监控数据操作以便识别和处理异常操作的需求。本文将以监控和识别删除操作为例,介绍如何通过IRIS的审计功能实现对数据操作的监控和查询。
# 注意事项
在应用审计功能之前,必须注意的是:
1. 开启审计功能会事无巨细地记录每一条对应的操作(如被执行的SQL),因此对于存储空间的需求将急剧增加。举例而言,仅开启对XDBCStatement的监控后,对于一张只由5个简单(整型,VARCHAR型)字段构成的表中插入100万条记录,在Audit数据库中将占用300~400MB的空间。在因业务所需确实需要开启审计功能时,必须预先分配更多磁盘空间给IRIS Audit数据库,并在审计功能开启期间定时巡检磁盘空间,避免因日志占满磁盘导致其他数据无法写入引发系统挂起的故障。
2. 在研发环境中多人、多单位需要连接数据库时,应为不同的开发者和数据来源分配独立的数据库账户和权限,避免多人共用超级账户,导致数据异常时难以追踪异常操作究竟从何而来。也就意味着为不同角色的开发、测试、用户等参与者开启独立的用户,分配各自所需的的数据库权限以及管理数据库账户这样一系列项目正常运行所依赖的实践并不能被审计功能所替代。在项目进展过程中,您更希望见到的,一定不是出现问题后再来跟踪问题和耽误工期,而是通过良好的协作规程和研发习惯减少非技术问题出现的概率。
# IRIS中的审计功能
IRIS提供了丰富的数据库审计功能,用于记录从系统权限变更到数据删除的各类操作,用户可通过我们的[**官方文档**](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCAS_audit)查看系统支持的各类审计事件。
对于SQL操作而言,可用到的审计事件包括三大类:
- %System/%SQL/DynamicStatement 可捕获通过动态SQL执行的SQL操作
- %System/%SQL/EmbeddedStatement 可捕获通过嵌入式SQL执行的SQL操作
- %System/%SQL/XDBCStatement 可捕获通过第三方(JDBC/ODBC)SQL连接执行的SQL操作
# 开启数据库审计
1. 由于默认安装时IRISAUDIT数据库通常位于IRIS安装目录,空间有限,因此在需要开启审计时,应先将IRISAUDIT数据库从系统安装目录迁移到空间更充裕的数据库目录
2. 在System Administration -> Security -> Auditing -> Configure System Events下,开启对%System/%SQL/XDBCStatement的监控,如下图

3. 预先配置好删除AuditLog的任务,以便在AuditLog过大时清除数据
系统虽然自带定时删除Audit数据库的任务,但其默认的触发条件为在Journal发生切换时才执行,因此不适用于需要扩展监控范围导致审计库将剧增的情况,应配置额外的任务便于随时执行。

并将其设置为按需启动

4. 待可疑操作发生时,使用SQL工具或portal在%SYS命名空间下运行如下SQL:
SELECT
ID, AuditIndex, Authentication, CSPSessionID, ClientExecutableName, ClientIPAddress, Description, Event, EventData, EventSource, EventType, GroupName, JobId, JobNumber, Namespace, OSUsername, Pid, Roles, RoutineSpec, Status, SystemID, UTCTimeStamp, UserInfo, Username
FROM %SYS.Audit
where Description = 'SQL DELETE Statement'
order by UTCTimeStamp desc
即可找到最近的删除操作。通过Truncate table或delete语句执行的操作均可由该日志捕获到。如需监控insert或update等操作,在上述Description字段的选择上加入对insert或update语句的筛选即可。
通过这些日志,可以查看到操作发生的时间,来源IP和数据库用户等信息,如下所示:

5. 必须再次提醒各位,一旦开启对语句的监控,Audit数据库会快速增长,需要每日甚至每日多次巡检,确保磁盘空间不会被占满导致系统崩溃。
一旦发现Audit所在磁盘占有量过大(例如大于80%)或Audit库本身的占用过大(例如大于20G),即应运行步骤3中 配置的任务,然后对Audit库进行压缩和截断操作释放空间。
文章
姚 鑫 · 十二月 27, 2022
# 第二十六章 使用系统监视器 - 使用 ^%SYSMONMGR 管理应用程序监视器
如使用 `^%SYSMONMGR` 实用程序中所述,`^%SYSMONMGR` 实用程序允许管理和配置系统监视器,包括应用程序监视器。该实用程序可以在任何名称空间中执行,使用它所做的更改只会影响启动它的名称空间。必须通过在该命名空间中启动 `^%SYSMONMGR` 来为配置的每个启动命名空间维护单独的应用程序监视器配置。
注意:在对应用程序监视器配置进行任何更改(例如激活类)之后,必须在进行更改的名称空间中重新启动系统监视器以使更改生效。
要管理应用程序监视器,请在终端中输入以下命令:
```java
%SYS>do ^%SYSMONMGR
```
然后为管理应用程序监视器输入 `5`。显示以下菜单:
```java
1) Set Sample Interval
2) Manage Monitor Classes
3) Change Default Notification Method
4) Manage Email Options
5) Manage Alerts
6) Debug Monitor Classes
7) Exit
Option?
```
输入选择的数字或按 `Enter` 退出 `Application Monitor`实用程序。
# 管理应用程序监视器
主菜单中的选项可让管理应用程序监视器,如下表所述:
Option| Description
---|---
1) Set Sample Interval|设置指标采样的时间间隔;默认值为 `30` 秒。通过设置类特定的间隔(使用“管理监视器类”子菜单上的“设置类采样间隔”选项),可以为单个类覆盖此设置。注意:如果系统监视器采样间隔(请参阅“设置系统监视器选项”子菜单中的“设置采样间隔”)长于应用程序监视类的采样间隔,则使用两个间隔中较长的一个。例如,如果系统监视器间隔为 `30`,应用程序监视器间隔为 `120`,则所有活动的应用程序监视器类每 `120` 秒采样一次;如果系统监视器间隔为 `60` 且 `%Monitor.System.LockTableclass` 间隔为 `20`,则该类每 `60` 秒采样一次。
2) Manage Monitor Classes|显示 `Manage Monitor Classes` 子菜单,它允许在运行 `Application Monitor Manager` 的命名空间中管理系统和用户定义的监视器类。
3) Change Default Notification Method |允许指定警报触发时的默认操作。除非另有说明,否则创建的任何警报都将使用此操作。
4) Manage Email Options| 显示监控电子邮件选项子菜单,它允许启用和配置电子邮件通知,以便可以在警报中指定此操作。
5) Manage Alerts|显示 Manage Alerts 子菜单,它允许为系统和用户定义的监视器类创建警报。
## 管理监视器类
该子菜单允许管理系统和用户定义的监视器类。输入选择的号码或按 `Enter` 返回主菜单:
```
Option? 2
1) Activate/Deactivate Monitor Class
2) List Monitor Classes
3) Register Monitor System Classes
4) Remove/Purge Monitor Class
5) Set Class Sample Interval
6) Exit
Option?
```
此子菜单显示菜单项列表,可让管理系统和用户定义的类,如下表所述:
Option| Description
---|---
1) Activate / Deactivate Monitor Class|`Application Monitor` 仅对活动类进行采样。此选项可让激活一个非活动类,或停用一个活动类。可以显示在本地名称空间中注册的系统和用户定义类的编号列表,包括每个类的激活状态,方法是输入?在类上?提示,然后输入编号或类名。
2) List Monitor Classes |显示在本地命名空间中注册的系统和用户定义类的列表,包括每个类的激活状态。
3) Register Monitor System Classes |注册所有系统监视器类(`%Monitor.System.HistorySys`、`%Monitor.System.HistoryPerf` 和 `%Monitor.System.HistoryUser` 类除外)并将它们存储在本地名称空间中。仍必须使用选项 1) 激活/停用此菜单上的监控器类来激活系统类,以便开始采样。
4) Remove/Purge Class|从本地名称空间中的类列表中删除监视器类。可以显示在本地名称空间中注册的系统和用户定义类的编号列表,包括每个类的激活状态,方法是输入?在类上?提示,然后输入编号或类名。注意:此选项不会删除类,而只是从可以激活的已注册类列表中删除类的名称。要重置列表,请在此菜单上选择选项 3) `Register Monitor System Classes`。
5) Set Class Sample Interval|允许为单个类覆盖默认的应用程序监视器采样间隔,该间隔由“管理应用程序监视器”菜单的 1) 设置采样间隔选项指定。默认值为 0,这意味着该类没有特定于类的样本间隔。有关此设置、设置采样间隔设置和设置系统监视器选项中讨论的系统监视器采样间隔之间优先顺序的说明,请参阅设置采样间隔选项的说明。
6) Debug Monitor Classes|显示 `Debug Monitor Classes` 菜单,它允许启用和禁用调试以及列出错误。
文章
姚 鑫 · 二月 19, 2022
# 第五十九章 SQL函数 GETDATE
日期/时间函数,返回当前本地日期和时间。
# 大纲
```java
GETDATE([precision])
```
# 参数
- `precision` - 可选-一个正整数,指定时间精度为小数秒的位数。
默认值是`0`(没有小数秒);
这个默认值是可配置的。
精度值是可选的,括号是必选的。
# 描述
`GETDATE`将此时区的当前本地日期和时间作为时间戳返回;它根据本地时间变量(如夏令时)进行调整。
`GETDATE`可以返回`%TIMESTAMP`数据类型格式(`yyyy-mm-dd hh:mm:ss.ffff`)或`%PosiTime`数据类型格式(编码的`64`位有符号整数)的时间戳。以下规则确定返回哪种时间戳格式:
1. 如果当前时间戳被提供给数据类型为`%PosiTime`的字段,则当前时间戳值将以`POSIXTIME`数据类型格式返回。例如, `WHERE PosixField=GETDATE() or INSERT INTO MyTable (PosixField) VALUES (GETDATE())`
2. 如果当前时间戳被提供给数据类型为`%TIMESTAMP`的字段,则当前时间戳值将以TIMESTAMP数据类型格式返回。其ODBC类型为`TIMESTAMP`,长度为`16`,精度为`19`,例如 `WHERE TSField=GETDATE() or INSERT INTO MyTable (TSField) VALUES (GETDATE())`
3. 如果当前时间戳是在没有上下文的情况下提供的,则当前时间戳值以`TIMESTAMP`数据类型格式返回。例如,选择`GETDATE()`。
要更改默认日期时间字符串格式,请使用带有各种日期和时间选项的`set option`命令。
`GETDATE`可以在`SELECT`语句`SELECT LIST`或查询的`WHERE`子句中使用。在设计报表时,可以使用`GETDATE`在每次生成报表时打印当前日期和时间。`GETDATE`对于跟踪活动也很有用,比如记录事务发生的时间。
可以在`CREATE TABLE`中使用`GETDATE`指定字段的默认值。`GETDATE`是`CURRENT_TIMESTAMP`的同义词,提供`GETDATE`是为了与Sybase和Microsoft SQL Server兼容。
`CURRENT_TIMESTAMP`和`NOW`函数还可以用于以时间戳或`POSIXTIME`格式将当前本地日期和时间作为时间戳返回。`CURRENT_TIMESTAMP`支持精度,现在不支持精度。
要仅返回当前日期,请使用`CURDATE`或`CURRENT_DATE`。要仅返回当前时间,请使用`CURRENT_TIME`或`CURTIME`。这些函数使用日期或时间数据类型。这些函数都不支持精度。
`TIMESTAMP`数据类型以相同的格式存储和显示其值。`POSIXTIME`数据类型将其值存储为编码的64位有符号整数。时间和日期数据类型将它们的值存储为`$HOROLOG`格式的整数。它们可以以显示格式或逻辑(存储)格式显示。可以使用`CAST`或`CONVERT`函数更改日期和时间的数据类型。
# 世界时(UTC)
`GETDATE`返回当前本地日期和时间。除`GETUTCDATE`之外,所有SQL时间戳、日期和时间函数都特定于本地时区设置。`GETUTCDATE`将当前`UTC`(通用)日期和时间作为时间戳值或POSIXTIME值返回。还可以使用ObjectScript `$ZTIMESTAMP`特殊变量来获取通用的当前时间戳(独立于时区)。
# 精确到小数部分的秒
`GETDATE`可以返回多达9位的精度。
使用`precision`参数设置返回的精度的位数。
`precision`参数的默认值可以通过以下方式配置:
- 使用`TIME_PRECISION`选项设置`OPTION`。
- 系统范围的`$SYSTEM.SQL.Util.SetOption()`方法配置选项`DefaultTimePrecision`。
要确定当前设置,调用`$SYSTEM.SQL.CurrentSettings()`,它显示默认的时间精度;
默认值为0。
- 进入管理门户,选择“系统管理”、“配置”、“SQL和对象设置”、“SQL”。
查看和编辑`GETDATE()`、`CURRENT_TIME`和`CURRENT_TIMESTAMP`的默认时间精度的当前设置。
指定从0到9(包括9)的整数,作为返回的十进制精度的默认位数。
默认值为0。
实际返回的精度取决于平台;
超过系统中可用精度的精度数字将作为零返回。
分数秒总是被截断,而不是四舍五入到指定的精度。
# 示例
下面的示例以`TIMESTAMP`格式返回当前日期和时间:
```sql
SELECT GETDATE() AS DateTime
2022/2/12 15:39:00
```
下面的示例以两位精度返回当前日期和时间:
```sql
SELECT GETDATE(2) AS DateTime
2022/2/12 15:39:21
```
下面的嵌入式SQL示例比较了本地(特定于时区)和通用(独立于时区)的时间戳:
```java
ClassMethod GetDate()
{
&sql(SELECT GETDATE(),GETUTCDATE() INTO :a,:b)
if SQLCODE'=0 {
w !,"Error code ",SQLCODE }
else {
w !,"Local timestamp is: ",a
w !,"UTC timestamp is: ",b
w !,"$ZTIMESTAMP is: ",$ZDATETIME($ZTIMESTAMP,3,,3)
}
}
```
```java
DHC-APP> d ##class(PHA.TEST.SQLCommand).GetDate()
Local timestamp is: 2022-02-12 15:40:34
UTC timestamp is: 2022-02-12 07:40:34
$ZTIMESTAMP is: 2022-02-12 07:40:34.978
```
下面的示例将`Orders`表中所选行中的`LastUpdate`字段设置为当前系统日期和时间。
如果`LastUpdate`是数据类型`%TimeStamp`, `GETDATE`返回当前日期和时间作为ODBC时间戳;
如果`LastUpdate`是数据类型`%PosixTime`, `GETDATE`返回当前日期和时间为编码的64位带符号整数:
```sql
UPDATE Orders SET LastUpdate = GETDATE()
WHERE Orders.OrderNumber=:ord
```
在下面的例子中,`CREATE TABLE`语句使用`GETDATE`为`StartDate`字段设置一个默认值:
```sql
CREATE TABLE Employees(
EmpId INT NOT NULL,
LastName CHAR(40) NOT NULL,
FirstName CHAR(20) NOT NULL,
StartDate TIMESTAMP DEFAULT GETDATE())
```