搜索​​​​

清除过滤器
文章
姚 鑫 · 五月 9, 2021

第四章 多维存储的SQL和对象使用(一)

# 第四章 多维存储的SQL和对象使用(一) 本章介绍InterSystems IRIS®对象和SQL引擎如何利用多维存储(全局变量)来存储持久对象、关系表和索引。 尽管InterSystems IRIS对象和SQL引擎会自动提供和管理数据存储结构,但了解其工作原理的详细信息还是很有用的。 数据的对象视图和关系视图使用的存储结构是相同的。为简单起见,本章仅从对象角度介绍存储。 # 数据 每个使用`%Storage.Persistent`存储类(默认)的持久化类都可以使用多维存储(全局变量)的一个或多个节点在InterSystems IRIS数据库中存储其自身的实例。 每个持久化类都有一个存储定义,用于定义其属性如何存储在全局变量节点中。这个存储定义(称为“默认结构”)由类编译器自动管理。 ## 默认结构 用于存储持久对象的默认结构非常简单: - 数据存储在名称以完整类名(包括包名)开头的全局变量中。附加`“D”`以形成全局数据的名称,而附加`“I”`作为全局索引。 - 每个实例的数据都存储在全局数据的单个节点中,所有非瞬态属性都放在`$list`结构中。 - 数据全局变量中的每个节点都以对象`ID`值作为下标。默认情况下,对象`ID`值是通过调用存储在全局变量数据根(没有下标)的计数器节点上的`$Increment`函数提供的整数。 例如,假设我们定义了一个简单的持久化类`MyApp.Person`,它有两个文本属性: ```java Class MyApp.Person Extends %Persistent { Property Name As %String; Property Age As %Integer; } ``` 如果我们创建并保存此类的两个实例,得到的全局变量结果将类似于: ```java ^MyApp.PersonD = 2 // counter node ^MyApp.PersonD(1) = $LB("",530,"Abraham") ^MyApp.PersonD(2) = $LB("",680,"Philip") ``` **注意,存储在每个节点中的`$List`结构的第一部分是空的; 这是为类名保留的。 如果定义`Person`类的子类,则此槽包含子类名。 当多个对象存储在同一个区段内时,`%OpenId`方法(由`%Persistent`类提供)使用此信息多态地打开正确的对象类型。 此槽在类存储定义中显示为名为`“%%CLASSNAME”`的属性。** ## IDKEY `IDKEY`机制允许显式定义用作对象`ID`的值。为此,只需将`IDKEY`索引定义添加到类中,并指定将提供`ID`值的一个或多个属性。请注意,一旦保存对象,其对象`ID`值就不能更改。这意味着在保存使用`IDKEY`机制的对象后,不能再修改该对象`ID`所基于的任何特性。 ```java Class MyApp.Person Extends %Persistent { Index IDKEY On Name [ Idkey ]; Property Name As %String; Property Age As %Integer; } ``` 如果我们创建并保存`Person`类的两个实例,得到的全局变量结果现在类似于: ```java ^MyApp.PersonD("Abraham") = $LB("",530,"Abraham") ^MyApp.PersonD("Philip") = $LB("",680,"Philip") ``` 请注意,不再定义任何计数器节点。还要注意,通过将对象`ID`基于`Name`属性,我们已经暗示了`Name`的值对于每个对象必须是唯一的。 如果`IDKEY`索引基于多个属性,则主数据节点具有多个下标。例如: ```java Class MyApp.Person Extends %Persistent { Index IDKEY On (Name,Age) [ Idkey ]; Property Name As %String; Property Age As %Integer; } ``` 在这种情况下,生成的全局变量现在类似于: ```java ^MyApp.PersonD("Abraham",530) = $LB("",530,"Abraham") ^MyApp.PersonD("Philip",680) = $LB("",680,"Philip") ``` **重要提示:`IDKEY`索引使用的任何属性的值中都不能有连续的一对竖线(`||`),除非该属性是对持久类实例的有效引用。 这种限制是由InterSystems SQL机制的工作方式强加的。 在`IDKey`属性中使用`||`会导致不可预知的行为。** ## Subclasses 默认情况下,持久性对象的子类引入的任何字段都存储在附加节点中。 子类的名称用作附加的下标值。 例如,假设我们定义了一个具有两个文本属性的简单持久`MyApp.Person`类: ```java Class MyApp.Person Extends %Persistent { Property Name As %String; Property Age As %Integer; } ``` 现在,我们定义了一个持久子类`MyApp.Students`,它引入了两个额外的文本属性: ```java Class MyApp.Student Extends Person { Property Major As %String; Property GPA As %Double; } ``` 如果我们创建并保存此`MyApp.Student`类的两个实例,得到的全局结果将类似于: ```java ^MyApp.PersonD = 2 // counter node ^MyApp.PersonD(1) = $LB("Student",19,"Jack") ^MyApp.PersonD(1,"Student") = $LB(3.2,"Physics") ^MyApp.PersonD(2) = $LB("Student",20,"Jill") ^MyApp.PersonD(2,"Student") = $LB(3.8,"Chemistry") ``` 从`Person`类继承的属性存储在主节点中,而由`Student`类引入的属性存储在另一个子节点中。这种结构确保了学生数据可以作为人员数据互换使用。例如,列出所有`Person`对象名称的SQL查询正确地获取`Person`和`Student`数据。当属性被添加到超类或子类时,这种结构还使类编译器更容易维护数据兼容性。 请注意,主节点的第一部分包含字符串`“Student”`-它标识包含学生数据的节点。 ## 父子关系 在父子关系中,子对象的实例存储为它们所属的父对象的子节点。这种结构确保子实例数据与父数据在物理上是集群的。 ```java /// An Invoice class Class MyApp.Invoice Extends %Persistent { Property CustomerName As %String; /// an Invoice has CHILDREN that are LineItems Relationship Items As LineItem [inverse = TheInvoice, cardinality = CHILDREN]; } ``` 和`LineItem`: ```java /// A LineItem class Class MyApp.LineItem Extends %Persistent { Property Product As %String; Property Quantity As %Integer; /// a LineItem has a PARENT that is an Invoice Relationship TheInvoice As Invoice [inverse = Items, cardinality = PARENT]; } ``` 如果我们存储多个`Invoice`对象的实例,每个实例都有关联的`LineItem`对象,则得到的全局变量结果将类似于: ```java ^MyApp.InvoiceD = 2 // invoice counter node ^MyApp.InvoiceD(1) = $LB("","Wiley Coyote") ^MyApp.InvoiceD(1,"Items",1) = $LB("","Rocket Roller Skates",2) ^MyApp.InvoiceD(1,"Items",2) = $LB("","Acme Magnet",1) ^MyApp.InvoiceD(2) = $LB("","Road Runner") ^MyApp.InvoiceD(2,"Items",1) = $LB("","Birdseed",30) ``` ## 嵌入对象 存储嵌入对象的方法是先将它们转换为序列化状态(默认情况下是包含对象属性的`$List`结构),然后以与任何其他属性相同的方式存储此串行状态。 例如,假设我们定义了一个具有两个文字属性的简单串行(可嵌入)类: ```java Class MyApp.MyAddress Extends %SerialObject { Property City As %String; Property State As %String; } ``` 现在,我们修改前面的示例以添加嵌入的`Home Address`属性: ```java Class MyApp.MyClass Extends %Persistent { Property Name As %String; Property Age As %Integer; Property Home As MyAddress; } ``` 如果我们创建并保存此类的两个实例,则生成的全局变量相当于: ```java ^MyApp.MyClassD = 2 // counter node ^MyApp.MyClassD(1) = $LB(530,"Abraham",$LB("UR","Mesopotamia")) ^MyApp.MyClassD(2) = $LB(680,"Philip",$LB("Bethsaida","Israel")) ``` ## 流 **通过将全局流的数据拆分成一系列块(每个块小于`32K`字节)并将这些块写入一系列顺序节点,全局流被存储在全局流中。文件流存储在外部文件中。**
文章
Tianyu wu · 三月 3, 2021

欢迎大家来给我们投票啦!

这是我们团队参加的第一届InterStstems编程竞赛! 快来看看投票给我们! 超额预订管理系统结合了酒店业的独特条件,例如房价,订购渠道,客户需求等。 本系统使用机器学习算法(例如:KNN / ES-RNN ...)来准确预测酒店的每日未入住和入住率,并进一步与收益结合以找到最佳的最大客房销售量,从而精准增加酒店的边际收益。 移步欣赏作品点击如下连接 https://github.com/BroadCastAir/hotel_api & https://github.com/BroadCastAir/Hotel_OverBooking_Sys 投票给我们点击: Check the related application on InterSystems Open Exchange 我们ISC 中国也想跟您聊一下合作事宜,请 @Jun.Qian 联系一下,谢谢! good! 很棒的应用! 非常棒!很好的应用!
公告
Nicky Zhu · 三月 30, 2021

2021年3月23日 - 提醒:HS2021-03,镜像Dejournaling的潜在数据完整性问题(HealthShare)

尊敬的HealthShare用户: 本帖是HealthShare HS2021-03提醒沟通流程的一部分,同样的信息也会以以下渠道分发: 邮件通知 HealthShare 用户 在 Product Alerts & Advisories 主页上通知 在 WRC Distribution Page InterSystems Documents主页上通知 提醒 产品版本和影响 风险等级 和评分 HS2021-03 -01:镜像Dejournaling的潜在数据完整性问题 这个问题会影响所有支持镜像的HealthShare产品和版本: HealthShare Unified Care Record/Information Exchange, Health Insight, and Patient Index version 15.02 and newer HealthShare Personal Community version 12.0 and newer HealthShare Provider Directory 2019.2, 2020.1 and 2020.2 HealthShare Health Connect and HSAP versions that support mirroring 2-低风险 (临床安全) 1-极低风险(隐私) 1-极低风险 (安全) 2-低风险 (运维) 如果您对本提醒有任何疑问,请联系 support@intersystems.com,并引述“HealthShare Alert HS2021-03”。
问题
xu hui · 六月 22, 2021

ERROR [HYT00] [Cache ODBC][State : HYT00][Native Code 450] [c:\windows\system32\inetsrv\w3wp.exe] Request timed out due to user timeout

我在用.net通过ODBC连接cache数据库,OdbcConnection connection = new OdbcConnection(dbConnection);connection.Open();打开链接时报这错,请教大佬们,这应该怎么解决吗?不胜感激! 您好!该问题请提交WRC服务 您可以登录网址:https://wrc.intersystems.com提交 第一个问题, 你是连本机还是远程?第2个问题, 你有没有测windows操作系统的cache odbc连接? 您好,非常感谢您的回复。我连接的是局域网内的其他远程服务器;我用同样的代码连接windows操作系统的DSN,是可以connection.Open();运行到这步并进行下去的。请问还有可能是什么原因吗?万分感谢@ 好的,初来乍到,不懂流程,抱歉。但我登录您所给的网址,提示 is not enabled for WRC login. If this is unexpected, please contact InterSystems Support.提交不了WRC服务
文章
姚 鑫 · 六月 25, 2021

第十八章 签署XML文档

# 第十八章 签署XML文档 本章介绍如何向XML文档添加数字签名。 # 关于数字签名文档 数字签名的XML文档包括一个或多个``元素,每个元素都是数字签名。 每个``元素对文档中的特定元素进行如下签名: - 每个签名元素都有一个ID属性,该属性等于某个唯一值。例如: ```xml ``` - 一个``元素包含一个``元素,它指向该Id,如下所示: ```xml ``` ``元素是由私钥签名的。此元素包括由签名机构签署的X.509证书。如果已签名文档的接收方信任此签名机构,则接收方可以验证证书,并使用包含的公钥验证签名。 注意: IRIS还支持一种变体,其中有签名的元素有一个名为ID的属性,而不是ID。 下面是一个示例,为了便于阅读,添加了空格: ```xml Persephone MacMillan 1976-02-20 FHwW2U58bztLI4cIE/mp+nsBNZg= MTha3zLoj8Tg content omitted MIICnDCCAYQCAWUwDQYJ content omitted ``` 要创建数字签名,可以使用类`%XML.Security.Signature`。 这是一个支持xml的类,它的投影是适当名称空间中的有效``元素。 # 创建数字签名XML文档 要创建数字签名的XML文档,请使用`%XML.Writer`为一个或多个适当定义的启用了XML的对象生成输出。 在为对象生成输出之前,必须创建所需的签名并将其写入对象,以便可以将信息写入目标。 ## 签名的前提条件 在签署文档之前,必须至少创建一个IRIS凭据集。InterSystems IRIS凭据集是存储在系统管理器数据库中的以下信息集的别名: - 包含公钥的证书。证书应由文档接收者信任的签名机构签名。 - 关联的私钥, IRIS在需要时使用,但从不发送。签名需要私钥。 - (可选)私钥的密码, IRIS在需要时使用私钥,但从不发送。可以加载私钥,也可以在运行时提供私钥。 ## 启用XML的类的要求 启用XML的类必须包括以下内容: - 投影为ID属性的特性。 - 至少一个类型为`%XML.Security`的属性。投影为``元素的签名。(一个XML文档可以包含多个``元素。) 考虑以下类: ```java Class XMLEncryption.Simple Extends (%RegisteredObject, %XML.Adaptor) { Parameter NAMESPACE = "http://mynamespace"; Parameter XMLNAME = "Person"; Property Name As %String; Property DOB As %String; Property PersonId As %String(XMLNAME = "Id", XMLPROJECTION = "ATTRIBUTE"); Property MySig As %XML.Security.Signature(XMLNAME = "Signature"); } ``` ## 生成和添加签名 要生成和添加数字签名,请执行以下步骤: 1. 可以选择包含`%soap.inc`包含文件,该文件定义可能需要使用的宏。 2. 创建`%SYS.X509Credentials`的实例在访问相应InterSystems IRIS凭据集。为此,调用`%SYS.X509Credentials`的`GetByAlias()`类方法。 ```java classmethod GetByAlias(alias As %String, pwd As %String) as %SYS.X509Credentials ``` - alias 别名是证书的别名。 - pwd 是私钥密码。仅当关联的私钥已加密并且在加载私钥文件时未加载密码时,才需要私钥密码。 若要运行此方法,必须以该凭据集的`OwnerList`中包含的用户身份登录,否则`OwnerList`必须为空。 3. 在使用给定凭据集创建 `%XML.Security.Signature`的实例。为此,请调用该类的`Createx509()`类方法: ```java classmethod CreateX509(credentials As %SYS.X509Credentials, signatureOption As %Integer, referenceOption As %Integer) as %XML.Security.Signature ``` - `credentials` 凭据是刚刚创建`%SYS.X509Credentials`的实例。 - `signatureOption`是`$$$SOAPWSIncludeNone`(还有其他选项,但它们不适用于此方案) - `referenceOption` 指定对符号元素的引用的性质。 这里使用的宏在`%soap.inc`中定义包括文件。 4. 获取ID属性的值,对于此签名将点的ID。此详细信息取决于启用XML对象的定义。 5. 创建`%XML.Security.Reference`的实例,指向该ID。为此,请调用该类的`Create()`类方法: ```java ClassMethod Create(id As %String, algorithm As %String, prefixList As %String) ``` - `id`是该参考应该指向的ID。 - `algorithm` 算法应该是以下之一: - `$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSexcc14`n — 使用此版本获取独占规范化。 - `$$$SOAPWSEnvelopedSignature` — 这相当于前面的选项。 - `$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSexcc14n` — 使用此版本进行包容性规范化。 6. 对于签名对象,调用`AddReference()`方法将此引用添加到签名: ```java Method AddReference(reference As %XML.Security.Reference) ``` 7. 更新启用XML的类的相应属性以包含签名。 ```java set object.MySig=signature ``` 8. 创建`%XML.Document`的实例,该实例包含序列化为XML的启用了XML的对象。 这是必要的,因为签名必须包括有关签名文档的信息。 注意:本文档不包含空格。 9. 调用签名对象的`SignDocument()`方法: ```java Method SignDocument(document As %XML.Document) As %Status ``` 此方法的参数是刚刚创建的中`%XML.Document`的实例。`SignDocument()`方法使用该实例中的信息更新签名对象。 10. 使用`%XML.Writer`中为对象生成输出。 注意:生成的输出必须包含与签名中使用的文档相同的空格(或不包含空格)。签名包含文档的摘要,如果将编写器中的缩进属性设置为1,则摘要将与文档不匹配。 例如: **放入到对应的实体类中,有一些属性需要替换** ```java Method WriteSigned(filename As %String = "") { #Include %soap //创建签名对象 set cred=##class(%SYS.X509Credentials).GetByAlias("servercred") set parts=$$$SOAPWSIncludeNone set ref=$$$KeyInfoX509Certificate set signature=##class(%XML.Security.Signature).CreateX509(cred,parts,ref,.status) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} // 获取我们要签名的元素的ID属性; set refid=$this.PersonId ; 此详细信息取决于类的结构 // 然后在签名对象中创建对该ID的引用 set algorithm=$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSc14n set reference=##class(%XML.Security.Reference).Create(refid,algorithm) do signature.AddReference(reference) //设置MySig属性,以便$this具有我们为其生成输出时所需的所有信息 set $this.MySig=signature ; 此详细信息取决于类的结构 //除了$this之外,我们还需要%XML.Document的一个实例,该实例包含序列化为XML的对象 set document=..GetXMLDoc($this) //使用序列化的XML对象对文档进行签名,这将更新部分签名 set status=signature.SignDocument(document) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} // 写入对象的输出 set writer=##class(%XML.Writer).%New() if (filename'="") { set status=writer.OutputToFile(filename) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} } do writer.RootObject($this) } ``` 前面的实例方法使用以下泛型类方法,该方法可以与任何启用了XML的对象一起使用: ```java ClassMethod GetXMLDoc2(object) As %XML.Document { //步骤1-将对象作为XML写入流 set writer=##class(%XML.Writer).%New() set stream=##class(%GlobalCharacterStream).%New() set status=writer.OutputToStream(stream) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} set status=writer.RootObject(object) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} //步骤2-从流中提取%XML.Document set status=##class(%XML.Document).GetDocumentFromStream(stream,.document) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} quit document } ``` 变体:引用中带有`URI=""`的数字签名 作为一种变体,签名的``元素可以具有`URI=""`,这是对包含签名的XML文档根节点的引用。 要通过以下方式创建数字签名: 1. 可以选择包含`%soap.inc`包含文件,该文件定义可能需要使用的宏。 2. 创建`%SYS.X509Credentials`的实例在访问相应InterSystems IRIS凭据集。为此,请调用`%SYS.X509Credentials`的`GetByAlias()`类方法,如前面的步骤所述。 3. 创建使用给定凭据集的`%XML.Security.Signature`的实例。为此,请调用该类的`CreateX509()`类方法,如前面的步骤所述。 4. 按如下方式创建`%XML.Security.X509Data`的实例: ```java set valuetype=$$$KeyInfoX509SubjectName_","_$$$KeyInfoX509Certificate set x509data=##class(%XML.Security.X509Data).Create(valuetype,cred) ``` 其中,`cred`是`%SYS`的实例。 `x509credentials`在之前创建的新窗口中打开。 这些步骤创建了一个``元素,其中包含一个``元素和一个``元素。 5. 将``元素添加到签名的``元素中,方法如下: ```java do signature.KeyInfo.KeyInfoClauseList.Insert(x509data) ``` 其中签名是`%XML.Security`的实例。 `x509data`是`%XML.Security.X509Data`的实例。 6. 创建`%XML.Security`的实例。 参考如下: ```java set algorithm=$$$SOAPWSEnvelopedSignature set reference=##class(%XML.Security.Reference).Create("",algorithm) ``` 7. 在步骤6(调用`AddReference()`)中继续上述步骤。 # 验证数字签名 对于收到的任何数字签名文档,都可以验证签名。不需要具有与文档内容匹配的启用XML的类。 ## 验证签名的前提条件 若要验证数字签名,必须首先为签名者向InterSystems IRIS提供受信任的证书。如果InterSystems IRIS可以验证签名者的证书链(从签名者自己的证书到来自InterSystems IRIS信任的证书颁发机构(CA)的自签名证书),包括中间证书(如果有),则InterSystems IRIS可以验证签名。 ## 验证签名 要验证数字签名的XML文档中的签名,请执行以下操作: 1. 创建`%XML.Reader`的实例并使用它打开文档。 2. 获取阅读器的`Document`属性。这是 `%XML.Document`的一个实例。包含作为`DOM的XML文档的文档 3. 使用阅读器的`correlation()`方法将``元素或元素与类`%XML.Security.Signature`关联起来。 例如: ```java do reader.Correlate("Signature","%XML.Security.Signature") ``` 4. 遍历文档以读取``元素或多个元素。为此,可以使用阅读器的`Next()`方法,该方法通过引用返回一个导入的对象(如果有的话)。 例如: ```java if 'reader.Next(.isig,.status) { write !,"Unable to import signature",! do $system.OBJ.DisplayError(status) quit } ``` 导入的对象是`%XML.Security.Signature`的实例 5. 调用导入签名的`ValidateDocument()`方法。该方法的参数必须是`%XML`的实例。先前检索到的文档。 ```java set status=isig.ValidateDocument(document) ``` 例如: ```java ClassMethod ValidateDoc(filename As %String) { set reader=##class(%XML.Reader).%New() set status=reader.OpenFile(filename) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } set document=reader.Document //获取 元素 //假设只有一个签名 do reader.Correlate("Signature","%XML.Security.Signature") if 'reader.Next(.isig,.status) { write !,"无法导入签名",! do $system.OBJ.DisplayError(status) quit } set status=isig.ValidateDocument(document) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } } ``` # 变体:引用ID的数字签名 在典型的情况下,``元素包含一个``元素,该元素指向文档中其他地方的唯一Id。 InterSystems IRIS还支持一种变体,其中``元素指向名为ID(而不是ID)的属性。 在这种变体中,需要额外的工作来签署文档和验证文档。 要对文档进行数字签名,请遵循“创建数字签名XML文档”中的步骤,并进行以下更改: - 对于支持xml的类,包含一个作为ID属性而不是ID属性投影的属性。 - 在生成和添加签名时,调用`%XML`的`AddIDs()`方法。文档实例。 在获得序列化的XML文档之后,在调用签名对象的`SignDocument()`方法之前,执行此操作。 例如: ```java //设置MySig属性,使$this在为其生成输出时拥有所需的所有信息 set $this.MySig=signature ; 这个细节取决于类的结构 //除了$this之外,我们还需要%XML的实例 包含序列化为XML的对象的文档 set document=..GetXMLDoc($this) //***** 当签名引用ID属性时添加步骤 ***** do document.AddIDs() //使用序列化的XML对象对文档进行签名,这更新了部分签名 set status=signature.SignDocument(document) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} ``` - 当验证文档时,在调用`Correlate()`之前包含以下步骤: 1. 调用 `%XML.Document`的`AddIDs()`方法。 2. 调用XML阅读器的`Rewind()`方法。 例如: ``` set document=reader.Document //添加签名引用ID属性时的步骤 do document.AddIDs() do reader.Rewind() //获取 元素 do reader.Correlate("Signature","%XML.Security.Signature") ```
文章
姚 鑫 · 三月 6, 2021

第五章 SQL定义表(一)

# 第五章 SQL定义表 # 表名称和架构名称 可以通过定义表(使用`CREATE TABLE`)或通过定义投影到表的持久类来创建表: - DDL:InterSystemsIRIS®数据平台使用CREATE TABLE中指定的表名来生成相应的持久类名,并使用指定的架构名来生成相应的包名。 - 类定义:InterSystemsIRIS®数据平台使用持久类名称来生成对应的表名,并使用包名称来生成对应的模式名。 由于以下原因,这两个名字之间的对应关系可能不相同: - 持久化类和SQL表遵循不同的命名约定。 适用不同的有效字符和长度要求。 模式和表名不区分大小写; 包名和类名区分大小写。 系统自动将有效提供的名称转换为有效的对应名称,以确保生成的名称是惟一的。 - 持久化类名与对应的SQL表名之间的匹配是默认的。 可以使用`SqlTableName`类关键字来提供不同的SQL表名。 - **默认模式名可能与默认包名不匹配。 如果指定一个非限定的SQL表名或持久类名,系统将提供一个默认的模式名或包名。 初始的默认模式名是`SQLUser`; 初始默认包名为`“User”`。** # 模式名称 表、视图或存储过程名称可以是限定的(`schema.name`),也可以是限定的(`name`)。 - 如果指定模式名(限定名),则指定的表、视图或存储过程将被分配给该模式。 如果模式不存在,则InterSystems SQL创建模式,并将表、视图或存储过程分配给它。 - 如果没有指定模式名(非限定名),InterSystems SQL将使用默认模式名或模式搜索路径分配模式,如下所述。 ## 模式命名注意事项 模式名遵循标识符约定,需要特别注意非字母数字字符的使用。 模式名不应该指定为带分隔符的标识符。 **尝试指定“USER”或任何其他SQL保留字作为模式名会导致`SQLCODE -312`错误。** `INFORMATION_SCHEMA`模式名和相应的信息。 模式包名在所有命名空间中保留。 用户不应该在这个模式/包中创建表/类。 当执行一个创建操作(比如`create TABLE`),指定一个还不存在的模式时,InterSystems IRIS将创建新的模式。 InterSystems IRIS使用模式名生成相应的包名。 由于模式及其对应包的命名约定不同,用户应该注意非字母数字字符的名称转换注意事项。 这些名称转换的注意事项与表不同: - 初始字符: - `%` (percent):指定%作为模式名的第一个字符,表示相应的包为系统包,其所有类为系统类。 这种用法需要适当的权限; 否则,这种用法会发出一个`SQLCODE -400`错误,`%msg`表示``错误。 - **`_`(下划线):如果模式名的第一个字符为下划线,则该字符将被对应包名中的小写`“u”`替换。 例如,模式名`_MySchema`生成名为`uMySchema`的包。** - 后续的字符: - **`_`(下划线):如果模式名第一个字符以外的其他字符是下划线,则该字符将被对应包名中的句点(`.`)替换。 由于句点是类的分隔符,下划线将模式分为包和子包。 因此,`My_Schema`生成包含包模式(`My.Schema`)的包My。** - **`@`, `#`, `$` characters:如果模式名包含任何这些字符,这些字符将从相应的包名中剥离。 如果剥离这些字符会产生重复的包名,那么将进一步修改剥离的包名:将剥离的模式名的最后一个字符替换为顺序整数(以0开始),以产生唯一的包名。 因此,`My@#$Schema`生成`MySchema`包,然后创建`My#$Schema`生成`MySchem0`包。 同样的规则也适用于表名对应的类名。** ## 保留模式名 `INFORMATION_SCHEMA`模式名和相应的信息。 模式包名在所有命名空间中保留。 用户不应该在这个模式/包中创建表/类 在所有名称空间中保留`IRIS_Shard`模式名。 用户不应在此模式中创建表、视图或过程。 存储在`IRIS_Shard`模式中的项不会通过编目查询或`INFORMATION_SCHEMA`查询显示。 ## 默认模式名称 - 在执行DDL操作(例如创建或删除表、视图、触发器或存储过程)时,会提供一个非限定名称作为默认的模式名。 架构搜索路径值将被忽略。 - 在执行DML操作时,例如通过选择、调用、插入、更新或删除访问现有表、视图或存储过程,将从模式搜索路径(如果提供了)提供一个不限定的名称。 如果没有架构搜索路径,或者没有使用架构搜索路径定位指定项,则提供默认的架构名称。 初始设置是对所有名称空间(系统范围)使用相同的默认模式名。 可以为所有命名空间设置相同的默认模式名,也可以为当前命名空间设置默认模式名。 如果创建了一个具有非限定名称的表或其他项,InterSystems IRIS将为其分配默认模式名和相应的持久类包名。 如果一个命名的或默认的模式不存在,InterSystems IRIS将创建模式(和包),并将创建的项分配给该模式。 如果删除模式中的最后一项,InterSystems IRIS将删除该模式(和包)。 下面的模式名解析描述适用于表名、视图名和存储过程名。 系统范围的初始默认模式名是`SQLUser`。 对应的持久类包名是`User`。 因此,非限定表名`Employee`或限定表名`SQLUser`。 `Employee`将生成类`User.Employee`。 因为`USER`是一个保留字,尝试用`USER`的模式名(或任何SQL保留字)指定限定名会导致`SQLCODE -1`错误。 **要返回当前默认模式名,请调用`$SYSTEM.SQL.DefaultSchema()`方法:** ```java DHC-APP>WRITE $SYSTEM.SQL.DefaultSchema() SQLUser ``` 或者使用以下预处理器宏: ```java #Include %occConstant WRITE $$$DefSchema ``` 可以使用以下任意一种方式更改默认模式名: - 进入管理界面。 在系统管理中,选择Configuration,然后选择SQL和对象设置,然后选择SQL。 在这个屏幕上,可以查看和编辑当前系统范围内的默认模式设置。 这个选项设置系统范围的默认模式名。![image](/sites/default/files/inline/images/tu_pian__2.png) ![image](/sites/default/files/inline/images/tu_pian__3.png) 这个系统范围的设置可以被当前命名空间的`SetDefaultSchema()`方法值覆盖。 - `$SYSTEM.SQL.SetDefaultSchema()`方法。默认情况下,此方法在系统范围内设置默认架构名称。但是,通过将布尔值第3个参数设置为1,可以仅为当前名称空间设置默认架构。当不同的名称空间具有不同的默认架构名称时,`DefaultSchema()`方法将返回当前名称空间的默认架构名称。 **注意:当更改默认的SQL模式名称时,系统将自动清除系统上所有名称空间中的所有缓存查询。 通过更改默认模式名称,可以更改所有包含非限定表、视图或存储过程名称的查询的含义。 强烈建议在安装InterSystems IRIS时建立默认的SQL模式名,以后不要修改。** 模式名用于生成相应的类包名。 因为这些名称有不同的命名约定,所以它们可能不相同。 可以通过将其设置为系统范围的默认模式来创建与SQL保留字同名的模式,但是不建议这样做。 名为`User`的默认模式根据类命名唯一性约定,生成相应的类包名称`User0`。 ### `_CURRENT_USER`关键字 - 作为系统范围的默认模式名:如果指定`_CURRENT_USER`作为默认模式名,InterSystems IRIS将指定当前登录进程的用户名作为默认模式名。 `_CURRENT_USER`值是`$USERNAME` ObjectScript特殊变量值的第一部分。 如果`$USERNAME`包含一个名字和一个系统地址(`Deborah@TestSys`), `_CURRENT_USER`只包含名字片段; 这意味着`_CURRENT_USER`可以将相同的默认模式名分配给多个用户。 如果进程没有登录,`_CURRENT_USER`指定`SQLUser`作为默认的模式名。 如果指定`_CURRENT_USER/name`作为默认模式名,其中name是选择的任意字符串,那么InterSystems IRIS将当前登录进程的用户名分配为默认模式名。 如果进程没有登录,则name将用作默认的模式名。 例如,如果进程没有登录,`_CURRENT_USER/HMO`使用HMO作为默认模式名。 在`$SYSTEM.SQL.SetDefaultSchema()`中,指定`"_CURRENT_USER"`作为带引号的字符串。 - DDL命令中的模式名:如果在DDL语句中指定`_CURRENT_USER`作为显式的模式名,InterSystems IRIS将其替换为当前系统范围内的默认模式。 例如,如果系统范围的默认模式是`SQLUser`,则命令`DROP TABLE _CURRENT_USER`。 `OldTable SQLUser.OldTable`下降。 这是一种方便的方式来限定名称,以显式地指示应该使用系统范围的默认模式。 它在功能上与指定非限定名相同。 此关键字不能在DML语句中使用。 ## 模式搜索路径 当访问一个现有的表(或视图,或存储过程)进行DML操作时,将从模式搜索路径中提供一个非限定的名称。 按照指定的顺序搜索模式,并返回第一个匹配项。 如果在搜索路径中没有找到匹配的模式,或者没有搜索路径,则使用默认的模式名。 (注意,`#Import`宏指令使用了不同的搜索策略,不会“失败”到默认的模式名。) - 在嵌入式SQL中,可以使用`#SQLCompile Path`宏指令或`#Import`宏指令来提供架构搜索路径,系统间IRIS使用该路径来解析非限定名称。 `#SQLCompile Path`根据遇到的第一个匹配项解析不限定的名称。 如果搜索路径中列出的所有模式只有一个匹配项,则`#Import`解析非限定名。 - 下面的示例提供了包含两个模式名的搜索路径: ```java #SQLCompile Path=Customers,Employees ``` - 在动态SQL中,可以使用`%SchemaPath`属性提供模式搜索路径,系统间IRIS使用该路径解析不限定的表名。 可以直接指定`%SchemaPath`属性,也可以将其指定为`%SQL`的第二个参数。 声明`%new()`方法。 下面的示例提供了包含两个模式名的搜索路径: ```java SET tStatement = ##class(%SQL.Statement).%New(0,"Customers,Employees") ``` - 在SQL Shell中,可以设置`PATH SQL Shell`配置参数来提供架构搜索路径,系统间IRIS使用该路径解析不限定的名称。 如果非限定名与模式搜索路径中指定的任何模式或默认模式名不匹配,则会发出`SQLCODE -30`错误,例如:`SQLCODE: -30`消息:`Table 'PEOPLE' not found in schemas: CUSTOMERS,EMPLOYEES,SQLUSER`。 ## 包含特定于平台的模式名 当创建一个基于odbc的查询以通过Mac上的Microsoft query从Microsoft Excel运行时,如果从可用的表列表中选择一个表,则生成的查询不包括该表的模式(相当于类的包)。 例如,如果选择从示例模式返回`Person`表的所有行,则生成的查询为: ```java SELECT * FROM Person ``` **因为InterSystems IRIS将不限定的表名解释为`SQLUser`模式中的表名,所以该语句要么失败,要么从错误的表返回数据。 要纠正这一点,编辑查询(在SQL View选项卡上),显式引用所需的模式。 然后查询应该是:** ```java SELECT * FROM Sample.Person ``` ## List模式 `INFORMATION.SCHEMA`。 `SCHEMATA persistent`类列出当前名称空间中的所有模式。 下面的示例返回当前命名空间中的所有非系统模式名: ```java SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE NOT SCHEMA_NAME %STARTSWITH '%' ``` Management Portal SQL界面的左侧允许查看模式(或匹配筛选器模式的多个模式)的内容。 # 表名 每个表在其模式中都有一个唯一的名称。 一个表有一个SQL表名和一个对应的持久化类名; 这些名称在允许的字符、区分大小写和最大长度方面有所不同。 如果使用SQL `CREATE TABLE`命令定义,则指定遵循标识符约定的SQL表名; 系统生成一个对应的持久化类名。 如果定义为持久类定义,则必须指定只包含字母和数字字符的名称; 这个名称既用作区分大小写的持久类名,也用作(默认情况下)对应的不区分大小写的SQL表名。 可选的`SqlTableName class`关键字允许用户指定不同的SQL表名。 当使用`CREATE TABLE`命令创建表时,InterSystems IRIS使用表名生成相应的持久化类名。 由于表及其对应类的命名约定不同,用户应该注意非字母数字字符的名称转换: - 初始字符: - `%` (percent): %作为表名的第一个字符是保留的,应该避免(参见标识符)。 如果指定了,`%`字符将从对应的持久化类名中剥离。 - `_`(下划线):如果表名的第一个字符是下划线,则该字符将从对应的持久化类名中剥离。 例如,表名`_MyTable`生成类名`MyTable`。 - 数字:表名的第一个字符不能是数字。 如果表名的第一个字符是标点符号,则第二个字符不能是数字。 这将导致一个`SQLCODE -400`错误,`%msg`值为`" error #5053:类名'schema.name' is invalid "`(没有标点字符)。 例如,指定表名`_7A`会生成`%msg " ERROR #5053: Class name 'User.7A' is invalid "`。 - 后续的字符: - 字母:表名中至少包含一个字母。 表名的第一个字符或初始标点字符后的第一个字符必须是字母。 如果一个字符通过`$ZNAME`测试,它就是一个有效的字母; `$ZNAME`字母验证因不同的地区而不同。 (注意,$ZNAME不能用于验证SQL标识符,因为标识符可能包含标点字符。) - `_`(下划线),`@`,`#`,`$` characters:如果表名包含这些字符中的任何一个,这些字符将从对应的类名中剥离出来,并生成一个唯一的持久类名。 由于生成的类名不包括标点字符,因此不建议创建仅在标点字符上不同的表名。 - 表名在其模式中必须是唯一的。 如果试图创建一个名称仅与现有表大小写不同的表,将会产生`SQLCODE -201`错误。 同一个模式中的视图和表不能具有相同的名称。 尝试这样做会导致`SQLCODE -201`错误。 可以使用`$SYSTEM.SQL.TableExists()`方法确定一个表名是否已经存在。 可以使用`$SYSTEM.SQL.ViewExists()`方法确定视图名是否已经存在。 这些方法还返回与表或视图名称对应的类名。 管理门户SQL interface Catalog Details表信息选项显示与所选SQL表名称对应的类名。 试图指定`“USER”`或任何其他SQL保留字作为表名或模式名会导致`SQLCODE -312`错误。 要指定SQL保留字作为表名或模式名,可以指定名称作为带分隔符的标识符。 如果使用带分隔符的标识符指定包含非字母数字字符的表或模式名,InterSystems IRIS将在生成相应的类或包名时删除这些非字母数字字符。 适用以下表名长度限制: - 唯一性:InterSystems IRIS对持久化类名的前189个字符执行唯一性检查。 对应的SQL表名可能超过189个字符,但是,当去掉非字母数字字符时,它必须在189个字符的限制内是唯一的。 InterSystems IRIS对包名的前189个字符执行唯一性检查。 - 建议最大长度:一般来说,一个表名不应该超过128个字符。 一个表名可能比96个字符长得多,但是在前96个字母数字字符中不同的表名更容易处理。 - 最大组合长度:包名和它的持久类名(加在一起时)不能超过220个字符。 这包括默认的模式(包)名(如果没有指定模式名)和分隔包名和类名的点字符。 当表名转换为对应的持久化类名时,删除超过220个字符时,模式和表名的组合长度可以超过220个字符。 # RowID字段 **在SQL中,每条记录都由一个唯一的整数值标识,这个整数值称为`RowID`。** 在InterSystems SQL中,不需要指定`RowID`字段。 当创建表并指定所需的数据字段时,会自动创建RowID字段。 这个`RowID`在内部使用,但没有映射到类属性。 默认情况下,只有当持久化类被投影到SQL表时,它的存在才可见。 在这个投影表中,将出现一个额外的`RowID`字段。 默认情况下,这个字段被命名为`“ID”`,并分配给第1列。 默认情况下,当在表中填充数据时,InterSystems IRIS将从1开始向该字段分配连续的正整数。`RowID`数据类型为`BIGINT(%Library.BigInt)`。为`RowID`生成的值具有以下约束:每个值都是唯一的。不允许使用`NULL`值。排序规则是精确的。**默认情况下,值不可修改。** 默认情况下,InterSystems IRIS将此字段命名为`“ ID”`。但是,此字段名称不是保留的。每次编译表时都会重新建立`RowID`字段名。如果用户定义了一个名为`“ ID”`的字段,则在编译表时,InterSystems IRIS会将`RowID`命名为`“ ID1”`。例如,如果用户随后使用`ALTER TABLE`定义了一个名为`“ ID1”`的字段,则表编译会将`RowID`重命名为`“ ID2”`,依此类推。在持久性类定义中,可以使用`SqlRowIdName`类关键字直接为此类投影到的表指定`RowID`字段名。由于这些原因,应避免按名称引用`RowID`字段。 InterSystems SQL提供了`%ID`伪列名称(别名),无论分配给`RowID`的字段名称如何,该伪列名称始终返回`RowID`值。 (InterSystems TSQL提供了`$IDENTITY`伪列名称,其作用相同。) `ALTER TABLE`无法修改或删除`RowID`字段定义。 将记录插入表中后,InterSystems IRIS将为每个记录分配一个整数ID值。 `RowID`值始终递增。它们不被重用。因此,如果已插入和删除记录,则`RowID`值将按升序排列,但可能不连续。 - **默认情况下,使用`CREATE TABLE`定义的表使用`$SEQUENCE`执行`ID`分配,从而允许多个进程快速同时填充该表。当使用`$SEQUENCE`填充表时,会将`RowID`值序列分配给进程,然后该进程将顺序分配它们。因为并发进程使用它们自己分配的序列分配`RowID`,所以不能假定多个进程插入的记录按插入顺序排列。** 可以通过设置`SetDDLUseSequence()`方法,将InterSystems IRIS配置为使用`$INCREMENT`执行`ID`分配。若要确定当前设置,请调用`$ SYSTEM.SQL.CurrentSettings()`方法。 - 默认情况下,通过创建持久性类定义的表将使用`$INCREMENT`执行ID分配。在持久性类定义中,可以将`IdFunction`存储关键字设置为序列或增量;否则,可以设置为0。例如,`序列`。 在持久性类定义中,`IdLocation`存储关键字global(例如,对于持久性类`Sample.Person: ^ Sample.PersonD `)包含RowID计数器的最高分配值。 (这是分配给记录的最高整数,而不是分配给进程的最高整数。)请注意,此RowID计数器值可能不再与现有记录相对应。要确定是否存在具有特定RowID值的记录,请调用表的`%ExistsId()`方法。 通过`TRUNCATE TABLE`命令重置`RowID`计数器。即使使用`DELETE`命令删除表中的所有行,也不会通过`DELETE`命令将其重置。如果没有数据插入表中,或者已使用`TRUNCATE TABLE`删除所有表数据,则`IdLocation`存储关键字全局值未定义。 默认情况下,`RowID`值不可用户修改。尝试修改`RowID`值会产生`SQLCODE -107`错误。覆盖此默认值以允许修改`RowID`值可能会导致严重的后果,只有在非常特殊的情况下并应格外谨慎。 `Config.SQL.AllowRowIDUpdate`属性允许`RowID`值是用户可修改的。 ## 基于字段的RowID 通过定义一个用于投影表的持久类,可以定义`RowID`以具有字段或字段组合中的值。为此,请使用`IdKey index`关键字指定一个索引。例如,一个表可以具有一个`RowID`,其`RowId`通过在`PatientName [IdKey]`上指定索引定义`IdxId`来与`PatientName`字段的值相同;或者可以通过指定索引定义`IdxId`来将`PatientName`和`SSN`字段的组合值在`(PatientName,SSN)[IdKey];`上。 - 基于字段的`RowID`效率比采用系统分配的连续正整数的`RowId`效率低。 - 在`INSERT`上:为构成`RowId`的字段或字段组合指定的值必须唯一。指定非唯一值将生成`SQLCODE -119`“在插入时唯一性或主键约束唯一性检查失败”。 - 在`UPDATE`上:默认情况下,组成`RowId`的每个字段的值都是不可修改的。尝试修改这些字段之一的值会生成`SQLCODE -107`“无法基于字段更新`RowID`或`RowID`”。 当`RowID`基于多个字段时,`RowID`值是由`||`连接的每个组成字段的值。操作员。例如,`Ross,Betsy || 123-45-6789`。 InterSystems IRIS尝试确定基于多个字段的`RowID`的最大长度。如果无法确定最大长度,则`RowID`长度默认为512。 ## 隐藏的RowID? - 使用`CREATE TABLE`创建表时,默认情况下隐藏`RowID`。 `SELECT *`不会显示隐藏字段,而是`PRIVATE`。创建表时,可以指定`%PUBLICROWID`关键字以使`RowID`不隐藏和公开。可以在`CREATE TABLE`逗号分隔的表元素列表中的任何位置指定此可选的`%PUBLICROWID`关键字。不能在`ALTER TABLE`中指定。 - 创建作为表投影的持久类时,默认情况下不会隐藏`RowID`。它由`SELECT *`显示,并且是`PUBLIC`。可以通过指定类关键字`SqlRowIdPrivate`来定义具有隐藏且为`PRIVATE`的`RowID`的持久类。 用作外键引用的`RowID`必须是公共的。 默认情况下,不能将具有公共`RowID`的表用作源表或目标表,以使用`INSERT INTO Sample.DupTable SELECT * FROM Sample.SrcTable`将数据复制到重复表中。 可以使用Management Portal SQL界面“目录详细信息字段”列出“隐藏”列来显示`RowID`是否被隐藏。 可以使用以下程序返回指定字段(在此示例中为`ID`)是否被隐藏: ```java /// d ##class(PHA.TEST.SQL).RowID() ClassMethod RowID() { SET myquery = "SELECT FIELD_NAME,HIDDEN FROM %Library.SQLCatalog_SQLFields(?) WHERE FIELD_NAME='ID'" SET tStatement = ##class(%SQL.Statement).%New() SET qStatus = tStatement.%Prepare(myquery) IF qStatus'=1 { WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT } SET rset = tStatement.%Execute() DO rset.%Display() WRITE !,"End of data" } ``` 最后一个占位符使用案例很棒!谢谢 总结的很好
文章
姚 鑫 · 五月 19, 2021

IRIS 单元测试

# IRIS 单元测试 # [第一章 单元测试概述☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/116884316) # [第二章 使用%UnitTest进行单元测试☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/116906659) # [第三章 执行测试☆☆☆](https://yaoxin.blog.csdn.net/article/details/116974672) # [第四章 使用Setup和tear Down方法执行测试☆☆☆](https://yaoxin.blog.csdn.net/article/details/117014533) # 前言 IRIS提供了用于对应用程序进行单元测试的类的%UnitTest包。该包为快速开发单元测试类、执行测试和创建报告提供了便利。可以直接使用该包,也可以扩展其类来自定义单元测试工具。%UnitTest在结构上与用于单元测试的xUnit框架非常相似。熟悉这些框架的开发人员使用%UnitTest会特别容易。 本教程提供对%UnitTest包的快速实践介绍。本教程的第一部分和第二部分是相互独立的,可以按任何顺序完成。 - 完成本教程的第一部分,了解单元测试和集成测试之间的区别、xUnit框架和%UnitTest之间的结构相似性,以及单元测试在敏捷应用程序开发方法中的作用。 - 完成本教程的第二部分,学习如何使用%UnitTest中的类为InterSystems IRIS应用程序创建和执行单元测试。 注意:本教程假定基本熟悉ObjectScript和InterSystems IRIS的面向对象开发。 # 预告 下一期系列将用一个月的时间连载,**《Caché 网络实用工具》**,敬请期待。 # 交流群 - QQ群号:410039091 - 笔者QQ:454115408 - 公众号:技术理科直男 - [intersys版主:姚鑫](https://cn.community.intersystems.com/user/236891/posts) ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9VqwzNP-1608850948003)(3E1D939266954ED48BDAEA9B8086B11E)\]](https://img-blog.csdnimg.cn/20201225070433434.png)
文章
Shanshan Yu · 七月 5, 2023

基于IntegratedML及Dashboard的数据分析应用

基于InterSystems的集成ML技术和Dashboard,根据上传的CSV文件自动生成相关预测和BI页面。前端和后端在Vue和Iris中完成,使用户可以通过简单的操作生成所需的数据预测和分析页面,并根据这些页面做出决策。 # ZPM 安装 zpm:USER>install IntegratedMLandDashboardSample # 部署流程 使用或创建新的命名空间 将代码导入相应的命名空间 在终端中执行: Do # # class (customizemashinelerningandaanalysis. Util. Tool) Deployment() 前端是Vue文件夹下的dist文件夹。在使用它之前,请打开dist-static config.js并修改后端服务器要使用的IP和端口。然后您需要将iframeUrl的测试修改为“Analysis”+后端使用的命名空间,例如“AnalysisUSER” 然后启动前端文件(可以将dist文件夹放在tomcat中开始使用) 访问地址为: Ip: port/dist # 如何使用 以women.csv为例 1.选择要上传的CSV文件,CSV文件名和数据列名不得包含空格等其他符号 2.填写需要预测的列名,如“高度” 3.单击“确定”按钮,等待界面返回 成功返回后,刷新当前页面,然后单击“模型列表”下的辅助选项。新生成的项目将出现 ① 填写完其他值后,点击②确定,在③处生成预测值 ④ 嵌入式虹膜仪表板显示以前导入CSV的一些数据 # 其他 CSV 展示 # 单元测试 Set ^UnitTestRoot=your modules dir +"\src"+namespace+"\integratedmlanddashboardsample\src" (such C:\InterSystems\HealthConnect\mgr\.modules\USER\integratedmlanddashboardsample\src) do ##class(%UnitTest.Manager).RunTest("UnitTests") #注意 由于页面上嵌入了iris的仪表板,如果您遇到无法正确显示的跨域问题,可以访问iris查看图表 非常棒的应用!那csv中的数据能不能是非数字呢?
文章
Hao Ma · 十一月 26, 2022

ZPM介绍(3)

## 建立私服(Porxy-Registry) 这张图解释了您的私服是怎么工作的, 整篇文章在这里: [Proxy-Registry](https://community.intersystems.com/post/new-zpm-registry-feature-%E2%80%93-proxy-registry) ![](https://community.intersystems.com/sites/default/files/inline/images/proxy.png) ### 搭建私服 您需要有一台自己的的服务器, 在上面安装IRIS, zpm, 然后用zpm去下载另一个软件包“zpm-registry"。象这样 ```sh zpm:DEMO>search -r zpm-registry registry https://pm.community.intersystems.com: zpm-registry 1.1.11Repository: https://github.com/intersystems-community/zpm-registry/ zpm:DEMO>install zpm-registry [DEMO|zpm-registry] Reload START (/usr/irissys/mgr/.modules/DEMO/zpm-registry/1.1.11/) [DEMO|zpm-registry] Reload SUCCESS [zpm-registry] Module object refreshed. [DEMO|zpm-registry] Validate START [DEMO|zpm-registry] Validate SUCCESS [DEMO|zpm-registry] Compile START [DEMO|zpm-registry] Compile SUCCESS [DEMO|zpm-registry] Activate START [DEMO|zpm-registry] Configure START [DEMO|zpm-registry] Configure SUCCESS [DEMO|zpm-registry] Activate SUCCESS zpm:DEMO> ``` 到github页面, https://github.com/intersystems-community/zpm-registry/, 你可以得到更详细的软件信息。 配置私服连接公服, 需要在私服的IRIS的安装目录添加一个yaml文件, 定义uplink: ```yaml uplinks: pm: url: https://pm.community.intersystems.com/ allow_packages: dsw,zpm*,?u* ``` 几点说明: - uplinks的项目可以有多个,pm是intersystems的默认公共registry - allow_packages: - a comma-separated list of allowed packages, you can use the exact package name or mask: * - any sequence of characters, ? - any charac - registry 提供的rest 接口描述: https://pm.community.intersystems.com/_spec ### 设置zpm client连接私服 通过repo命令将您的zpm client切换到刚刚配置的私服。`repo -n registry`里面的 - user, - pass是你搭建的私服的账号密码。您也可以在私服上修改/registryWeb应用不做用户验证。 ```sh zpm:DEMO>repo -list registry Source: https://pm.community.intersystems.com Enabled? Yes Available? Yes Use for Snapshots? Yes Use for Prereleases? Yes Is Read-Only? No Deployment Enabled? No zpm:DEMO>repo -n registry -r -url http://localhost:52773/registry/ -user superuser -pass demo registry Source: http://localhost:52773/registry/ Enabled? Yes Available? Yes Use for Snapshots? Yes Use for Prereleases? Yes Is Read-Only? No Deployment Enabled? No Username: superuser Password: zpm:DEMO> ``` 这时的私服时没有连接公服。 ### 发布软件包到私服 **发布一个 GitHub 的包** 先把软件存在github, 然后用curl命令把包发布在私服的地址。 ```sh $ curl -i -X POST -H "Content-Type:application/json" -u superuser:1104 -d '{"repository":"https://github.com/psteiwer/ObjectScript-Math"}' 'http://localhost:52773/registry/package’ ``` **使用zpm 客户端先在本地load,然后使用publish 命令** 大概像这个样子: ```sh zpm:USER>help load ... ■ Examples ∙ load C:\module\root\path\ load C:\module\root\path\module-0.0.1.tgz Loads the module described in C:\module\root\path\module.xml ∙ load -dev -verbose C:\module\root\path\ load -dev -verbose C:\module\root\path\module-0.0.1.tgz Loads the module described in C:\module\root\path\module.xml in developer mode and with verbose output. ∙ load https://github.com/user/repository.git load https://github.com/user/repository.git -b branch-name Loads the module described in C:\module\root\path\module.xml in developer mode and with verbose output. zpm:USER> load https://github.com/user/repository.git zpm: USER> publish ``` ## 其他的Feature 在使用中您还会有各种各样的需求, 但我相信看到现在您应该对怎么寻找答案非常清楚了。这里简单的说两个feautre ### 1. 发布为Delopyed模式 如果您要隐藏自己的代码,只发布编译后的软件, 可以简单的修改Module.xml, 设置““, zpm会自动完成。 ### 2. 包的依赖 因为有朋友问,所以说一些包依赖的功能。是的, zpm是设计了包依赖的功能的,在module.xml里添加Dependencies节点, 可以定被依赖的包的列表。 具体的写法请参见这个例子:[module.xml example](https://github.com/intersystems/ipm/wiki/03.-Module.xml#modulexml-example)。 虽然但是,对ObjectScript程序来说,定义包依赖的机会并不多。我能想到的应用场景就是, 当您的软件中想用社区其他包,比如上面的bitmap-adoption的包的话,您可以包"bitmap-adoption"打包到module.xml里面。 我对当前发布的200多软件包随便挑了一些,还没有发现有哪个使用了包依赖, 象这样: ```sh zpm:USER>list-dependents yaml-utils zpm:USER>list-dependents terminal-multiline-editor zpm:USER>list-dependents bitmap-adoption zpm:USER>list-dependents global-dump-sql ... ```
文章
Hao Ma · 三月 25, 2021

Covid-19 肺部 X 射线分类和 CT 检测演示(HealthShare 临床查看器与第三方AI PACS viewer整合)

Covid-19 肺部 X 射线分类和 CT 检测演示 **关键字**:COVID-19,医学影像,深度学习,PACS Viewer 和 HealthShare。   ## **目的** 在这场史无前例的新冠疫情笼罩之下, 我们竭尽所能为客户提供支援,同时利用先进的 AI 技术观察着不同的疫情战线。  去年,我简单提及了一个[深度学习演示环境](https://community.intersystems.com/post/run-deep-learning-demo-python3-binding-healthshare-part-ii)。 在这个漫长的复活节周末,我们就来看一看现实世界的图像,在 Covid-19 肺部 X 射线数据集上测试运行一些深度学习模型以进行快速分类,并见证这类用于 X 射线甚至 CT 的工具如何通过 docker 等方式快速部署到云端,实现及时的“AI 分诊”并协助放射科医生。      这只是一个 10 分钟的快速笔记,希望通过简单的方法帮助各位上手实践。          ## **范围** 本演示环境中使用了以下组件, 这是我目前能找到的最简单的形式: * 一个小型**匿名开放数据集**,共 3 种类型:Covid-19 肺与细菌性肺炎肺与正常透明肺。 * 一组**深度学习模型**,如用于肺部 X 射线分类的 Inception V3 模型 * 带有 Jupyter Notebook 的 **Tensorflow 1.13.2** 容器 * 用于 **GPU 工具的 Nvidia-Docker2** 容器 * 配备 Nvidia T4 GPU 的 AWS **Ubuntu 16.04 VM**(如果不重新训练预训练的模型,笔记本电脑的 GPU 就足够了) 以及, * “AI 辅助 CT 检测”的演示容器。 * 第三方 Open PACS Viewer 的演示容器。 * HealthShare Clinical Viewer 的演示实例。 以下不在演示范围内: * PyTorch 越来越受欢迎(下次会用到) * TensorFlow 2.0 在演示环境中的运行速度过慢(因此我暂时回转到 1.13 版)  * AutoML 等多模型集成(它们在现实世界中越来越流行,但单一老式模型对这个小数据集来说已经足够了) * 任何现实世界位置的 X 射线和 CT 数据。    ## **免责声明** 这个演示更多是关于技术方法,而不是特定领域的临床试验。 基于 CT 与 X 线等证据的 Covid-19 检测已在网上广泛流传,对其有正面评价,也有负面评价。疫情期间,它在各个国家/地区和文化中发挥着不同的作用。 另外,本文的正文和布局可能会根据需要进行修改。   本文完全是出自“开发者”角度的个人观点。   ## **数据** 本测试的原始图像来自 Joseph Paul Cohen 公开的 [Covid-19 肺部 X 射线集](https://github.com/ieee8023/covid-chestxray-dataset),以及开放的 Kaggle 胸部 X 射线集中的一些干净的肺,由 Adrian Yu 在 GradientCrescent 仓库中收集为一个小型测试集。 我[在这里上传了测试数据](https://github.com/zhongli1990/Covid19-X-Rays),供有兴趣的读者进行快速测试。 到目前为止,它只包含一个小的训练集:  * 60x  Covid-19 肺  * 70x 正常透明肺 * 70x  细菌性肺炎肺 ## **测试** 在以下测试中,我根据自己的情况做了些微调: * Inception V3 模型作为基础,几个 CNN 层作为顶层 * 使用未冻结的底层 Inception 层权重进行迁移学习,以再训练(如果是在笔记本电脑 GPU 上,您只需要冻结预训练的 Inception 层) * 为弥补目前收集到的少量数据集,略微增加了一些内容。 * 3x 类别而不是二元类别:Covid-19、正常与细菌性(或病毒性)肺炎(我将解释为什么是这三类) * 计算基本的 3 类混淆矩阵,作为后续可能步骤的模板。   **注**:选择 InceptionV3 而不是其他流行的基于 CNN 的模型,比如 VGG16 或 ResNet50,并没有什么特别的原因。 我只是碰巧最近在其他模型中用它来演示运行了一个骨折数据集,为方便起见就直接重用了。  您可以使用[任何偏好的模型](https://towardsdatascience.com/illustrated-10-cnn-architectures-95d78ace614d)重新运行以下 Jupyter Notebook 脚本。 我也在这篇帖子中附加了以下 Jupyter Notebook 文件。 下面也是为了快速说明。 ### 1. 导入必要的库: # import the necessary packages from tensorflow.keras.layers import AveragePooling2D, Dropout, Flatten, Dense, Input from tensorflow.keras.models import Model from tensorflow.keras.optimizers import Adam from tensorflow.keras.utils import to_categorical from tensorflow.keras import optimizers, models, layers from tensorflow.keras.applications.inception_v3 import InceptionV3 from tensorflow.keras.applications.resnet50 import ResNet50 from tensorflow.keras.preprocessing.image import ImageDataGenerator from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report, confusion_matrix from imutils import paths import matplotlib.pyplot as plt import numpy as np import cv2 import os ### 2. 加载[此处提供的示例图像文件](https://github.com/zhongli1990/Covid19-X-Rays) # set learning rate, epochs and batch size INIT_LR = 1e-5 <span style="color:#999999;"># This value is specific to what model is chosen: Inception, VGG or ResNet etc.</span> EPOCHS = 50 BS = 8 print("Loading images...") imagePath = "./Covid_M/all/train" # change to your local path for the sample images imagePaths = list(paths.list_images(imagePath)) data = [] labels = [] # read all X-Rays in the specified path, and resize them all to 256x256 for imagePath in imagePaths: label = imagePath.split(os.path.sep)[-2] image = cv2.imread(imagePath) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image = cv2.resize(image, (256, 256)) data.append(image) labels.append(label) #normalise pixel values to real numbers between 0.0 - 1.0 data = np.array(data) / 255.0 labels = np.array(labels) # perform one-hot encoding for a multi-class labeling label_encoder = LabelEncoder() integer_encoded = label_encoder.fit_transform(labels) labels = to_categorical(integer_encoded) print("... ... ", len(data), "images loaded in multiple classes:") print(label_encoder.classes_) Loading images... ... ... 200 images loaded in 3x classes: ['covid' 'normal' 'pneumonia_bac'] ### 3. 添加基本数据增强,重新构建模型,然后开始训练  # split the data between train and validation. (trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.20, stratify=labels, random_state=42) # add on a simple Augmentation. Note: too many Augumentation doesn't actually help in this case - I found during the test. trainAug = ImageDataGenerator(rotation_range=15, fill_mode="nearest") #Use the InveptionV3 model with Transfer Learning of pre-trained "ImageNet"'s weights. #note: If you choose VGG16 or ResNet you may need to reset the initial learning rate at the top. baseModel = InceptionV3(weights="imagenet", include_top=False, input_tensor=Input(shape=(256, 256, 3))) #baseModel = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(256, 256, 3))) #baseModel = ResNet50(weights="imagenet", include_top=False, input_tensor=Input(shape=(256, 256, 3))) #Add on a couple of custom CNN layers on top of the Inception V3 model. headModel = baseModel.output headModel = AveragePooling2D(pool_size=(4, 4))(headModel) headModel = Flatten(name="flatten")(headModel) headModel = Dense(64, activation="relu")(headModel) headModel = Dropout(0.5)(headModel) headModel = Dense(3, activation="softmax")(headModel) # Compose the final model model = Model(inputs=baseModel.input, outputs=headModel) # Unfreeze pre-trained Inception "ImageNet" weights for re-training since I got a Navidia T4 GPU to play with anyway #for layer in baseModel.layers: # layer.trainable = False print("Compiling model...") opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS) model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"]) # train the full model, since we unfroze the pre-trained weights above print("Training the full stack model...") H = model.fit_generator( trainAug.flow(trainX, trainY, batch_size=BS), steps_per_epoch=len(trainX) // BS, validation_data=(testX, testY), validation_steps=len(testX) // BS, epochs=EPOCHS) ... ... Compiling model... Training the full stack model... ... ... Use tf.cast instead. Epoch 1/50 40/40 [==============================] - 1s 33ms/sample - loss: 1.1898 - acc: 0.3000 20/20 [==============================] - 16s 800ms/step - loss: 1.1971 - acc: 0.3812 - val_loss: 1.1898 - val_acc: 0.3000 Epoch 2/50 40/40 [==============================] - 0s 6ms/sample - loss: 1.1483 - acc: 0.3750 20/20 [==============================] - 3s 143ms/step - loss: 1.0693 - acc: 0.4688 - val_loss: 1.1483 - val_acc: 0.3750 Epoch 3/50 ... ... ... ... Epoch 49/50 40/40 [==============================] - 0s 5ms/sample - loss: 0.1020 - acc: 0.9500 20/20 [==============================] - 3s 148ms/step - loss: 0.0680 - acc: 0.9875 - val_loss: 0.1020 - val_acc: 0.9500 Epoch 50/50 40/40 [==============================] - 0s 6ms/sample - loss: 0.0892 - acc: 0.9750 20/20 [==============================] - 3s 148ms/step - loss: 0.0751 - acc: 0.9812 - val_loss: 0.0892 - val_acc: 0.9750   ### 4. 为验证结果绘制混淆矩阵: print("Evaluating the trained model ...") predIdxs = model.predict(testX, batch_size=BS) predIdxs = np.argmax(predIdxs, axis=1) print(classification_report(testY.argmax(axis=1), predIdxs, target_names=label_encoder.classes_)) <span style="color:#999999;"># calculate a basic confusion matrix</span> cm = confusion_matrix(testY.argmax(axis=1), predIdxs) total = sum(sum(cm)) acc = (cm[0, 0] + cm[1, 1] + cm[2, 2]) / total sensitivity = cm[0, 0] / (cm[0, 0] + cm[0, 1] + cm[0, 2]) specificity = (cm[1, 1] + cm[1, 2] + cm[2, 1] + cm[2, 2]) / (cm[1, 0] + cm[1, 1] + cm[1, 2] + cm[2, 0] + cm[2, 1] + cm[2, 2]) <span style="color:#999999;"># show the confusion matrix, accuracy, sensitivity, and specificity</span> print(cm) print("acc: {:.4f}".format(acc)) print("sensitivity: {:.4f}".format(sensitivity)) print("specificity: {:.4f}".format(specificity)) <span style="color:#999999;"># plot the training loss and accuracy</span> N = EPOCHS plt.style.use("ggplot") plt.figure() plt.plot(np.arange(0, N), H.history["loss"], label="train_loss") plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss") plt.plot(np.arange(0, N), H.history["acc"], label="train_acc") plt.plot(np.arange(0, N), H.history["val_acc"], label="val_acc") plt.title("Training Loss and Accuracy on COVID-19 Dataset") plt.xlabel("Epoch #") plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.savefig("./Covid19/s-class-plot.png") 从上图可以看出,得益于“迁移学习”的好处,即使只有很小的数据集和不到 5 分钟的快速训练,得出的结果也并不差:12 个 Covid-19 肺全部正确分类,总共 40 个肺中只有 1 个正常肺被错划为“细菌性肺炎”肺。  ###   ### 5. 为测试真实 X 射线图绘制混淆矩阵 接下来,我们再深入一些,发送真实的 X 射线图测试这个轻度训练的分类器有多有效。  我将上述训练集或验证集中尚未使用的 27 个 X 射线图像上传到模型: 9 个 Covid-19 肺,9 个正常肺,9 个细菌性肺。  (图像也附在本篇帖子中。) 我只在第 2 步中修改了一行代码,确保它从不同路径加载测试图像: ... imagePathTest = "./Covid_M/all/test" ... 使用上面训练好的模型开始预测:  predTest = model.predict(dataTest, batch_size=BS) print(predTest) predClasses = predTest.argmax(axis=-1) print(predClasses) ... 最后,按照第 5 步重新计算混淆矩阵: testX = dataTest testY = labelsTest ... ... 得出一些真实测试结果:  同样,经过训练的模型似乎能够正确分类所有 Covid-19 肺。 对于这么小的数据集来说,这样的结果不算太差。  ### 6. 一些进一步的观察: 我在复活节周末尝试了许多种数据集,注意到从 AI 分类器的角度来看,Covid-19 肺似乎具有一些显著特征,相对更容易与其他正常细菌性或病毒性(流感)肺区分开来。 经过一些快速测试,我还发现,实在很难区分细菌性和病毒性(正常流感)肺。  如果有时间的话,我必须用 Ensemble 集群降低它们之间的差异,就像其他 Kaggle 竞争者在这种情况下可能会做的一样。   以上结果是否切实符合临床的真实情况? Covid-19 肺在 X 射线图上真有一些显著特征吗? 我并不确定。 这要向真正的胸部放射科医生征求意见。 就目前而言,我宁愿假设现在的数据集太小,还无法得出最终结论。   **下一步**:我很想收集更多的真实 X 射线图,用 xgsboot、AutoML 或新的 IRIS IntegratedML 工作台全面观察。  还有,我希望我们能够为临床医生和 A&E 分诊医生将 Covid-19 肺按其严重程度进一步分为如 1 级、2 级和 3 级。 不管怎样,[我还是附上了数据集和 Jupyter Notebook](https://github.com/zhongli1990/Covid19-X-Rays)。   ## **部署** 在这个“医学影像”领域,我们已经触及了一些快速设置的简易起点。 实际上,这个 Covid-19 领域是我在过去一年中用周末时间和长假研究的第 3 个领域。 其他包括“人工智能辅助骨骨折检测”系统和“人工智能辅助眼(眼科)视网膜诊断”系统。  上面的模型也许还太过简陋,但是我们可能很快就必须面对一个常见问题:[我们要如何将其部署为一种“AI 服务”? ](https://community.intersystems.com/post/deploy-mldl-models-consolidated-ai-demo-service-stack) 这涉及技术堆栈和服务生命周期,还涉及实际的“用例” - 我们要解决哪些问题?它可以提供什么样的实际价值?  答案有时并不像技术本身那样清晰。 英国 [RCR (Royal College of Radiologist) 草案](https://www.rcr.ac.uk/sites/default/files/integrating-ai-with-radiology-reportin%20g-workflow-guidance-covid19.pdf)提出了 2 个简单的用例:“放射科医生的 AI 助手”和“A&E 或基层医疗环境中的 AI 分诊”。 我个人表示同意,并认为“AI 分诊”目前来说更有价值。  幸运的是,得益于云、Docker、AI 以及我们的 HealthShare 的支持,如今的开发者可以运用更多资源应对这类用例。  例如,以下屏幕截图显示了 AWS 托管的企业级“Covid-19 肺 AI 辅助 CT 检测”服务,及其如何直接嵌入 HealthShare Clinical Viewer 进行演示。 与 X 射线类似,DICOM 中的 CT 集可以直接上传或发送到这个打开的 PACS Viewer,点击“AI diagnosis”即可在 10 秒内根据训练的模型给出 Covid-19 概率的定量指示,能够全天候用于快速“AI 分诊”用例。 X 射线分类等模型可以在同一患者的相关信息中,以相同的方式在现有 PACS 查看器上部署和调用,帮助一线临床医生。   ![](/sites/default/files/inline/images/images/healthshare_cv_covid19_pacs_ct_ai_embeded.png)   ## **致谢**   测试图像来自 Joseph Paul Cohen 的 [Covid-19 肺部 X 射线集](https://github.com/ieee8023/covid-chestxray-dataset),以及开放的 [Kaggle 胸部 X 射线集](https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia)中的一些干净的肺,由 Adrian Yu 在 [GradientCrescent 仓库](http://github.com/EXJUSTICE/GradientCrescent)中收集。 我还重用了 [PyImageSearch 的 Adrian ](https://github.com/AleGiovanardi/covidhelper)的结构,添加了我自己改进的训练,如“测试”部分所列。 还要感谢 [HYM](http://en.huiyihuiying.com/) 提供[基于 AWS 云的 Open PACS Viewer](http://ec2-3-8-183-64.eu-west-2.compute.amazonaws.com/doctor/index.html#!/login) 以及 X 射线和 CT 图像的 AI 模块,用于研究测试数据集。   **未来计划** 如今,AI 已经“侵入”到人类健康和日常生活的的方方面面。 根据我高度简化的观点,医疗领域的 AI 应用可能主要有以下几个方向: * **医学影像**:包括胸部、心脏、眼睛和大脑等的 X 射线、CT 或 MRI 等图像。 * **NLP 理解**:对海量文本资产和知识库的挖掘、理解和学习。 * **人口健康**:包括流行病学等趋势预测、分析和建模。  * 个性化 AI:一组专为个人训练的 AI/ML/DL 模型,作为个人健康助手与用户一起成长和变老? * 其他 AI:如 AlphaGo,甚至用于 3D 蛋白结构预测来对抗 Covid-19 的 AlphaFold 等,这些前沿突破让人印象深刻。  谁也无法预测我们将来能取得什么样的成果。 而且,这本来就是一个愿望清单,只要我们别在家里待得太久。    **附录** - [文件已上传到此处。 其中包括上文使用的图像和提及的 Jupyter Notebook 文件](https://github.com/zhongli1990/Covid19-X-Rays)。 在周末从头开始设置和运行可能要花费几个小时的时间。  
文章
Hao Ma · 三月 25, 2021

将 Python ODBC 连接到 IRIS 数据库 - 第 2 条快速笔记

**关键字**:PyODBC,unixODBC,IRIS,IntegratedML,Jupyter Notebook,Python 3   ## **目的** 几个月前,我简单谈到了关于“[将 Python JDBC 连接到 IRIS](https://community.intersystems.com/post/python-jdbc-connection-iris-database-quick-note)”的话题。我后来频繁提起它, 因此决定再写一篇 5 分钟的笔记,说明如何“将 Python ODBC 连接到 IRIS”。 在 Windows 客户端中通常很容易设置 ODBC 和 PyODBC,不过我每次在 Linux/Unix 风格的服务器中设置 unixODBC 和 PyODBC 客户端时,都会遇到一些麻烦。 有没有一种简单连贯的方法,可以不安装任何 IRIS,在原版 Linux 客户端中让 PyODBC/unixODBC 针对远程 IRIS 服务器运行?   ## **范围** 最近,我花了点时间研究如何在 Linux Docker 环境的 Jupyter Notebook 中从头开始让一个 PyODBC 演示运行起来, 记录下这篇稍微有些繁琐的笔记,以供日后快速参考。   #### **范围内**:  这篇笔记将涉及以下组件: PyODBC over unixODBC  安装了 TensorFlow 2.2 和 Python 3 的 Jupyter Notebook 服务器 带有 IntegratedML 的 IRIS2020.3 CE 服务器,包括示例测试数据。 在此环境中 安装了 Docker-compose over AWS Ubuntu 16.04 的 Docker Engine  Docker Desktop for MacOS 和 Docker Toolbox for Windows 10 也经过了测试 #### **范围外**: 同样,在此演示环境中不评估非功能性方面。 它们很重要,并且可以针对特定站点,如: 端到端安全和审核 性能和可扩展性 许可和可支持性等   ## **环境** 任何原版 Linux Docker 镜像都可以用于以下配置和测试步骤,但有一个简单的方法可以在 5 分钟内设置这样的环境: 1.  Git **克隆**此[演示模板](https://github.com/tom-dyar/integratedml-demo-template) 2.  在包含 docker-compose.yml 文件的克隆目录中运行“**docker-compose up -d**”。 这将创建一个演示环境,如下面的拓扑所示,其中包含 2 个容器。 一个用于 Jupyter Notebook 服务器作为 PyODBC 客户端,另一个用于 IRIS2020.3 CE 服务器。   在上面的环境中,tf2jupyter 仅包含“Python over JDBC”客户端配置;它尚不包含任何 ODBC 或 PyODBC 客户端配置。 因此,我们将直接在 Jupyter Notebook 内部运行以下设置步骤,以使其易于说明。     ## **步骤** 以下配置和测试由我在 AWS Ubuntu 16.04 服务器中运行, 由我的同事 @Thomas.Dyar 在 MacOS 中运行。 另外在 Docker Toolbox for Windows 中也进行了简单的测试。 不过,如果您遇到任何问题,还是请告诉我们。 以下步骤可以自动化到其 Dockerfile。 我在这里特别记录一下,以防几个月后忘记。 ### **1. 官方文档:** IRIS 的 ODBC 支持 在 Unix 上定义 ODBC 数据源  IRIS 的 PyODBC 支持    ### **2. 连接到 Jupyter 服务器** 我用本地 Putty 的 SSH 隧道连接到远程 AWS Ubuntu 端口 22,然后按照上述拓扑结构映射到端口 8896。 (举个例子,在本地 Docker 环境中,也可以直接直接 http 到 Docker 机器的 IP:8896。)   ### **3. 从 Jupyter Notebook 中运行 ODBC 安装** 直接在 Jupyter 单元格中运行以下代码:  !apt-get update<br>!apt-get install gcc<br>!apt-get install -y tdsodbc unixodbc-dev<br>!apt install unixodbc-bin -y<br>!apt-get clean -y 它将安装 gcc(包括 g++)编译器、FreeTDS、unixODBC 和 unixodbc-dev,以在下一步重新编译 PyODBC 驱动程序。 在原生 Windows 服务器或 PC 上安装 PyODBC 不需要这一步。  ### **4. 从 Jupyter 中运行 PyODBC 安装** !pip install pyodbc Collecting pyodbc Downloading pyodbc-4.0.30.tar.gz (266 kB) |████████████████████████████████| 266 kB 11.3 MB/s eta 0:00:01 Building wheels for collected packages: pyodbc Building wheel for pyodbc (setup.py) ... done Created wheel for pyodbc: filename=pyodbc-4.0.30-cp36-cp36m-linux_x86_64.whl size=273453 sha256=b794c35f41e440441f2e79a95fead36d3aebfa74c0832a92647bb90c934688b3 Stored in directory: /root/.cache/pip/wheels/e3/3f/16/e11367542166d4f8a252c031ac3a4163d3b901b251ec71e905 Successfully built pyodbc Installing collected packages: pyodbc Successfully installed pyodbc-4.0.30 以上是这个 Docker 演示的最简化 pip 安装。 在[官方文档](https://irisdocs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=BNETODBC_support#BNETODBC_support_pyodbc)中,为“MacOS X 安装”提供了更详细的 pip 安装。   ### **5 在 Linux 中重新配置 ODBC INI 文件和链接:** 运行以下命令重新创建 **odbcinst.ini** 和 **odbc.ini** 链接 !rm /etc/odbcinst.ini!rm /etc/odbc.ini !ln -s /tf/odbcinst.ini /etc/odbcinst.ini!ln -s /tf/odbc.ini /etc/odbc.ini 注:这样的原因是,**第 3 步和第 4 步通常会在 \etc\ directory 下创建 2 个空白(因此无效)的 ODBC 文件。**与 Windows 安装不同,这里的空白 ini 文件会导致问题。因此需要先将其删除,然后重新创建一个链接来指向映射的 Docker 卷中提供的真实 ini 文件:/tf/odbcinst.ini 和 /tf/odbc.ini 看一看这两个 ini 文件。在这种情况下,它们是 Linux ODBC 配置的最简形式: !cat /tf/odbcinst.ini [InterSystems ODBC35] UsageCount=1 Driver=/tf/libirisodbcu35.so Setup=/tf/libirisodbcu35.so SQLLevel=1 FileUsage=0 DriverODBCVer=02.10 ConnectFunctions=YYN APILevel=1 DEBUG=1 CPTimeout=<not pooled> !cat /tf/odbc.ini [IRIS PyODBC Demo] Driver=InterSystems ODBC35 Protocol=TCP Host=irisimlsvr Port=51773 Namespace=USER UID=SUPERUSER Password=SYS Description=Sample namespace Query Timeout=0 Static Cursors=0 以上文件都已预先配置,位于映射的驱动器中。 引用的是驱动程序文件 **libirisodbcu35.so**,可以从 IRIS 服务器的容器实例中获取该文件(在其 {iris-installation}/bin 目录下)。 要使上述 ODBC 安装正常运行,**这 3 个文件**必须存在于**具有正确文件权限**的映射驱动器(或任何 Linux 驱动器)中: libirisodbcu35.so odbcinst.ini odbc.ini   **6. 验证 PyODBC 安装 ** !odbcinst -j unixODBC 2.3.4 DRIVERS............: /etc/odbcinst.ini SYSTEM DATA SOURCES: /etc/odbc.ini FILE DATA SOURCES..: /etc/ODBCDataSources USER DATA SOURCES..: /root/.odbc.ini SQLULEN Size.......: 8 SQLLEN Size........: 8 SQLSETPOSIROW Size.: 8 import pyodbcprint(pyodbc.drivers()) ['InterSystems ODBC35'] 以上输出将表明 ODBC 驱动程序目前具有有效链接。 我们应该能够在 Jupyter Notebook 中运行一些 Python ODBC 测试 **7. 运行将 Python ODBC 连接到 IRIS 的示例:**   import pyodbc import time ### 1. Get an ODBC connection #input("Hit any key to start")dsn = 'IRIS PyODBC Demo'server = 'irisimlsvr'   # IRIS server container or the docker machine's IP port = '51773'   # or 8091 if docker machine IP is useddatabase = 'USER' username = 'SUPERUSER' password = 'SYS'  #cnxn = pyodbc.connect('DSN='+dsn+';')   # use the user DSN defined in odbc.ini, or use the connection string belowcnxn = pyodbc.connect('DRIVER={InterSystems ODBC35};SERVER='+server+';PORT='+port+';DATABASE='+database+';UID='+username+';PWD='+ password) ###ensure it reads strings correctly.cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')cnxn.setencoding(encoding='utf8') ### 2. Get a cursor; start the timercursor = cnxn.cursor()start= time.clock() ### 3. specify the training data, and give a model namedataTable = 'DataMining.IrisDataset'dataTablePredict = 'Result12'dataColumn =  'Species'dataColumnPredict = "PredictedSpecies"modelName = "Flower12" #chose a name - must be unique in server end ### 4. Train and predict#cursor.execute("CREATE MODEL %s PREDICTING (%s)  FROM %s" % (modelName, dataColumn, dataTable))#cursor.execute("TRAIN MODEL %s FROM %s" % (modelName, dataTable))#cursor.execute("Create Table %s (%s VARCHAR(100), %s VARCHAR(100))" % (dataTablePredict, dataColumnPredict, dataColumn))#cursor.execute("INSERT INTO %s  SELECT TOP 20 PREDICT(%s) AS %s, %s FROM %s" % (dataTablePredict, modelName, dataColumnPredict, dataColumn, dataTable)) #cnxn.commit() ### 5. show the predict resultcursor.execute("SELECT * from %s ORDER BY ID" % dataTable)   #or use dataTablePredict result by IntegratedML if you run step 4 aboverow = cursor.fetchone() while row:     print(row)     row = cursor.fetchone() ### 6. CLose and clean     cnxn.close()end= time.clock()print ("Total elapsed time: ")print (end-start) (1, 1.4, 0.2, 5.1, 3.5, 'Iris-setosa') (2, 1.4, 0.2, 4.9, 3.0, 'Iris-setosa') (3, 1.3, 0.2, 4.7, 3.2, 'Iris-setosa') (4, 1.5, 0.2, 4.6, 3.1, 'Iris-setosa') (5, 1.4, 0.2, 5.0, 3.6, 'Iris-setosa') ... ... ... ... ... ... (146, 5.2, 2.3, 6.7, 3.0, 'Iris-virginica') (147, 5.0, 1.9, 6.3, 2.5, 'Iris-virginica') (148, 5.2, 2.0, 6.5, 3.0, 'Iris-virginica') (149, 5.4, 2.3, 6.2, 3.4, 'Iris-virginica') (150, 5.1, 1.8, 5.9, 3.0, 'Iris-virginica') Total elapsed time: 0.023873000000000033 这里有一些陷阱: 1. **cnxn = pyodbc.connect() **- 在 Linux 环境下,此调用中传递的连接字符串必须正确无误,不能有任何空格。   2. 正确设置连接编码,例如使用 utf8。  在这里默认值对字符串不起作用。 3. **libirisodbcu35.so** - 理想情况下,此驱动程序文件应与远程 IRIS 服务器的版本保持一致。     ## **未来计划 ** 这样就得到一个带有 Jupyter Notebook 的 Docker 环境,包括 Python3 和 TensorFlow 2.2(无 GPU),通过 PyODBC(以及 JDBC)连接到远程 IRIS 服务器。 所有定制的 SQL 语法应该都可以适用,比如 IRIS Integrated ML 专有的 SQL 语法。那么何不多研究一下 IntegratedML 的功能,用它驱动 ML 生命周期的 SQL 方法以进行一些创新?  另外,我希望接下来能介绍或总结出在 IRIS Native 甚至是 Python 环境中的魔法 SQL 上最简单的 IRIS 服务器挂接方法。 而且,现在有出色的 [Python Gateway](https://github.com/intersystems-community/PythonGateway),我们甚至可以直接从 IRIS 服务器内部调用外部 Python ML 应用和服务。我希望我们也能在这方面多做些尝试。   **附录** 上面的笔记本文件也将被迁入此 Github 存储库以及 Open Exchange 中。    
文章
姚 鑫 · 二月 4, 2022

第四十四章 SQL函数 DATENAME

# 第四十四章 SQL函数 DATENAME 日期/时间函数,它返回一个字符串,表示日期/时间表达式中指定部分的值。 # 参数 - `datepart` - 要返回的日期/时间信息类型。 日期或时间部分的名称(或缩写)。 可以用大写或小写指定该名称,也可以不加引号。 可以将`datepart`指定为文字或主机变量。 - `date-expression` - 要返回`datepart`值的日期、时间或时间戳表达式。 日期表达式必须包含`datepart`类型的值。 # 描述 `DATENAME`函数返回日期/时间值中指定部分的名称(例如`“June”`)。 结果作为数据类型`VARCHAR(20)`返回。 如果结果是数字(例如`“23”`表示当天),它仍然作为`VARCHAR(20)`字符串返回。 要以整数形式返回此信息,请使用`DATEPART`。 要返回包含多个日期部分的字符串,请使用`TO_DATE`。 请注意,`DATENAME`是为Sybase和Microsoft SQL Server兼容性而提供的。 这个函数也可以通过调用`DATENAME()`方法从ObjectScript调用: ``` $SYSTEM.SQL.Functions.DATENAME(datepart,date-expression) ``` # Datepart 参数 `datepart`参数可以是包含一个(且仅包含一个)以下日期/时间组件的字符串,可以是全名(`date Part`列),也可以是缩写(缩写列)。 这些`datepart`组件名称和缩写不区分大小写。 Date Part |Abbreviations| Return Values ---|---|--- year| yyyy, yy| 0001-9999 quarter| qq, q| 1-4 month| mm |January,...December week |wk, ww| 1-53 weekday |dw |Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday dayofyear| dy, y| 1-366 day| dd, d| 1-31 hour| hh| 0-23 minute |mi, n| 0-59 second |ss, s| 0-59 millisecond |ms| 0-999 (with precision of 3) microsecond |mcs| 0–999999 (with precision of 6) nanosecond| ns |0–999999999 (with precision of 9) 如果将无效的`datepart`值指定为文字,则会发出`SQLCODE -8`错误码。 但是,如果提供一个无效的`datepart`值作为主机变量,则不会发出`SQLCODE`错误,并且`DATENAME`函数返回一个`NULL`值。 上表显示了不同日期部分的默认返回值。 通过使用带有不同时间和日期选项的`SET OPTION`命令,可以修改其中几个日期部分的返回值。 `week`:可以配置为使默认算法或ISO 8601标准算法确定给定日期的年度星期。 `weekday`:对于`weekday`的默认设置是将周日指定为一周的第一天(工作日=1)。 但是,可以将一周的第一天配置为另一个值,或者可以应用指定星期一为一周的第一天的ISO 8601标准。 `millisecond`:返回一个包含毫秒数(千分之一秒)的字符串。 如果日期表达式的精度超过`3`个小数位数,将其截断为`3`个数字,并将该数字作为字符串返回。 如果日期表达式具有指定的精度,但精度小于`3`个小数位数,则 `0`将其填充为`3`个数字,并将该数字作为字符串返回。 微秒和纳秒执行类似的截断和填充零。 可以将`datepart`指定为带引号的字符串或不带引号的字符串。 这些语法变体执行的操作略有不同: - 引号:`DATENAME('month','2018-02-25')`:在创建缓存查询时,`datepart`被视为一个字面值。 SQL执行文字替换。 这将产生一个更普遍的可重用的缓存查询。 - 没有引号:`DATENAME(month,'2018-02-25')`:在创建缓存查询时,`datepart`被视为关键字。 没有文字替换。 这将产生一个更具体的缓存查询。 # 日期表达格式 `date-expression`参数可以是以下任何一种格式: - `%Date` logical value (`+$H`) - `%PosixTime` (`%Library.PosixTime`) logical value (an encoded 64-bit signed integer) - `%TimeStamp` (`%Library.TimeStamp`) logical value (`YYYY-MM-DD HH:MM:SS.FFF`), also known as ODBC format. - `%String` (or compatible) value `%String`(或compatible)值可以是以下任何格式: - 99999,99999 ($H format) - Sybase/SQL-Server-date Sybase/SQL-Server-time - Sybase/SQL-Server-time Sybase/SQL-Server-date - Sybase/SQL-Server-date (default time is 00:00:00) - Sybase/SQL-Server-time (default date is 01/01/1900) Sybase/SQL-Server-date是以下五种格式之一: ```sql mmdelimiterdddelimiter[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm] ``` 其中分隔符是斜杠(`/`)、连字符(`-`)或句号(`.`)。 Sybase/SQL-Server-time表示以下三种格式之一: ```sql HH:MM[:SS:SSS][{AM|PM}] HH:MM[:SS.S] HH['']{AM|PM} ``` 如果`date-expression`指定了时间格式但没有指定日期格式,则`DATENAME`的默认值为`1900-01-01`,其中`weekday`的值为`Monday`。 # 范围和值检查 `DATENAME`对输入值执行以下检查。 如果一个值检查失败,则返回`null`字符串。 - 有效的日期表达式可以由日期字符串(`yyyy-mm-dd`)、时间字符串(`hh:mm:ss`)或日期和时间字符串(`yyyy-mm-dd hh:mm:ss`)组成。 如果同时指定日期和时间,则日期和时间都必须有效。 例如,如果没有指定时间字符串,则可以返回`Year`值,但如果指定了无效的时间字符串,则无法返回Year值。 - 日期字符串必须完整,格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。 例如,如果省略了`Day`值,则不能返回`Year`值。 年必须指定为四位数字。 - 时间字符串必须使用适当的分隔符进行适当的格式化。 因为时间值可以为零,所以可以省略一个或多个时间元素(保留或省略分隔符),这些元素将返回值为零。 因此,`“hh: mm: ss”,“hh: mm:”`、`“hh: mm”,“hh:: ss”,“hh::”`、`“hh”`,和`“::”`都是有效的。 若要省略`Hour`元素,`date-expression`必须没有字符串的日期部分,并且必须保留至少一个分隔符(`:`)。 - 日期和时间值必须在有效范围内。 年龄:0001到9999。 月份:1 - 12个月。 天数:1 - 31天。 小时:0到23。 分钟:0到59分钟。 秒:0 ~ 59。 - 一个月中的天数必须与月和年相匹配。 例如,日期`“02-29”`仅在指定的年份为闰年时有效。 - 大多数小于10的日期和时间值可能包括或省略前导零。 但是,小于10的`Hour`值必须包括前导0,如果它是`datetime`字符串的一部分。 不允许使用其他非规范整数值。 因此,`Day`值为`“07”`或`“7”`是有效的,但`“007”`、`“7.0”`或`“7a”`无效。 - 如果`date-expression`指定了时间格式但没有指定日期格式,则`DATENAME`不会对时间组件值执行范围验证。 # 示例 在下面的例子中,每个`DATENAME`返回`'Wednesday'`,因为它是指定日期的星期几(`'dw'`): ```sql SELECT DATENAME('dw','2018-02-21') AS DayName, DATENAME(dw,'02/21/2018') AS DayName, DATENAME('DW',64700) AS DayName Wednesday Wednesday Wednesday ``` 下面的例子返回'`December'`,因为它是指定日期的月份名称(`'mm'`): ```sql SELECT DATENAME('mm','2018-12-20 12:00:00') AS MonthName December ``` 下面的示例返回`'2018'`(字符串形式),因为它是指定日期的年份(`'yy'`): ```sql SELECT DATENAME('yy','2018-12-20 12:00:00') AS Year 2018 ``` 注意,上面的例子使用了日期部分的缩写。 但是,你可以指定全名,如下例所示: ```sql SELECT DATENAME('Q',$HOROLOG) AS Q, DATENAME('WK',$HOROLOG) AS WkCnt, DATENAME('DY',$HOROLOG) AS DayCnt 1 6 35 ``` 下面的嵌入式SQL示例将`datepart`和`date-expression`作为宿主变量传入: ```java ClassMethod DateName() { s a="year" s b=$HOROLOG &sql(SELECT DATENAME(:a,:b) INTO :c) w "this year is: ",c } ``` ``` DHC-APP>d ##class(PHA.TEST.SQLCommand).DateName() this year is: 2022 ``` 下面的示例使用子查询从出生日期为星期三的`Sample.Person`返回记录: ```java SELECT Name AS WednesdaysChild,DOB FROM (SELECT Name,DOB,DATENAME('dw',DOB) AS Wkday FROM Sample.Person) WHERE Wkday='Wednesday' ORDER BY DOB ```
文章
Jingwei Wang · 六月 20, 2022

IRIS/HealthConnect 高可用机制 Mirror 的配置

安装Arbiter 为了将自动故障转移扩展到尽可能广泛的故障情况,InterSystems建议你为每个镜像配置一个仲裁机。 要充当仲裁者,系统必须有一个正在运行的ISCAgent进程。由于ISCAgent是与InterSystems IRIS一起安装的,任何承载一个或多个InterSystems IRIS实例的系统都符合这一要求,可以被配置为仲裁者而无需进一步准备;但是,承载一个或多个故障转移或DR异步镜像成员的系统不应该被配置为该镜像的仲裁者。 没有托管InterSystems IRIS实例的系统可以通过安装Arbiter方式的作为仲裁者。请从InterSystems公司下载适合你的仲裁者系统平台的ISCAgent安装包,然后,安装ISCAgent。 注意:Arbiter的版本要和InterSystems IRIS安装版本保持一致。 在Windows上安装Arbiter 在Windows系统上,只需执行安装文件,例如ISCAgent-2020.1.0.540.0-win_x64.exe。 在Linux上安装Arbiter [root@arbiterhost home]# gunzip ISCAgent-2020.1.0.540.0-lnxrhx64.tar.gz [root@arbiterhost home]# tar -xf ISCAgent-2020.1.0.540.0-lnxrhx64.tar [root@arbiterhost home]# ./ISCAgent/agentinstall 启动、停止、检查ISCAgent状态 systemctl start ISCAgent.service systemctl stop ISCAgent.service systemctl status ISCAgent.service 设置、终止开机自动启动ISCAgent sudo systemctl enable ISCAgent.service sudo systemctl disable ISCAgent.service 启动 ISCAgent 服务 在所有的服务器中(主机,备机,仲裁机),ISCAgent必须被配置为在系统启动时自动启动。 a. 进入管理工具——服务,选择ISCAgent,将启动类型改为自动。点启动ISCAgent。 b. Windows防火墙中允许ISCAgent TCP端口2188,同时新建出站、进站规则。允许web端口 52773,超级端口1972。 入站规则中运行文件和打印机共享(回显请求 - ICMPv4-In) 配置主failover成员(Primary failover成员) a. 进入Management Portal界面,选择菜单 系统管理 – 配置 – 镜像配置 – 创建镜像。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 b. 创建Mirror,输入相关信息并保存。 镜像信息部分 : 镜像名称(Mirror Name) : 有效的名称必须是1至15个字母数字字符;小写字母会自动替换为大写字母的对应物。 要求SSL/TLS (Use SSL/TLS): 指定是否要为镜像内的所有通信要求SSL/TLS安全(建议)。如果你选择了 "需要SSL/TLS",而实例还没有一个有效的SSL/TLS配置用于镜像,在完成这个程序之前,你可以直接点击设置SSL/TLS链接,在这个成员上创建所需的SSL/TLS配置。你也可以取消创建镜像程序,并浏览到SSL/TLS配置页面(系统>安全管理>SSL/TLS配置)。 使用仲裁器(Use Arbiter): 指定你是否要配置一个仲裁器(建议)。如果你选择使用仲裁器,你必须提供你想配置为仲裁器的系统的主机名或IP地址以及其ISCAgent进程使用的端口(默认为2188)。 使用虚拟IP(User Virtual IP):如果你选择使用虚拟IP,系统会提示你提供一个IP地址、无类别域间路由(CIDR)掩码和网络接口。 故障转移成员的压缩模式,异步成员的压缩模式 : 分别指定在从主站向备份和异步成员传输之前是否压缩日志数据,以及对每个成员使用哪种压缩类型;两者的默认设置都是 "系统选择",它优化了故障转移成员之间的响应时间以及主站和异步站之间的网络利用率。 一般使用默认设置。 Allow Paralle Dejournaling :确定哪种类型的镜像成员可以运行并行的Dejournal。Paralle Dejournaling允许多个作业在单个数据库中处理独立的globals,而不是只限于并行处理独立的数据库。 镜像故障转移成员信息: 镜像成员名:为你在这个系统上配置的故障转移成员指定一个名称(默认为系统主机名称和InterSystems IRIS实例名称的组合)。镜像成员名称不能包含空格、制表符或以这些标点符号 : [ ] # ; / * = ^ ~ ,字母字符在保存前会转换为大写字母。镜像成员名称的最大长度是32个字符。 超级服务器地址: 输入外部系统可用于与该故障转移成员通信的 IP 地址或主机名称。 代理端口: 输入此故障转移成员上 ISCAgent 的端口号,接受提示中提供的已安装代理的端口。 配置备failover成员(backup failover成员) 进入Management Portal界面,选择菜单 系统管理 – 配置 – 镜像配置 – 加入为故障转移。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 镜像名称:创建的镜像名称 其他系统上的代理地址: 输入您在配置第一个故障转移成员时指定的超级服务器地址。 代理端口 :输入您在配置第一个故障转移成员时指定的 ISCAgent 的端口。 InterSystems IRIS 实例名称 : 输入配置为第一个故障转移成员的InterSystems IRIS实例的名称。 配置异步镜像成员 选择 系统管理 – 配置 – 镜像设置 – 加入为异步。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 在‘加入为异步’页面填入创建的第一个镜像成员名称、地址、实例名称。 镜像名称:创建的镜像名称 故障转移系统的代理地址 :输入您在配置所选故障转移成员时指定的超级服务器地址。 代理端口 - 输入您为所选故障转移成员指定的 ISCAgent 端口。 InterSystems IRIS 实例名称 - 输入您配置为选定故障转移成员的 InterSystems IRIS 实例的名称。 选择合适的Async镜像成员类型 修改镜像设置 进入菜单 系统管理 – 配置 – 镜像配置 – 编辑镜像 可以修改设置的各个参数: 添加镜像数据库 创建一个镜像数据库 在主failover成员服务器上,选择系统管理– 配置 – 系统配置– 本地数据库 选择 新建数据库,按照提示输入数据库名称、存放数据库文件位置。注意在输入关于数据库的详情页面,镜像数据库? 选择 是。 在每一个failover成员服务器以及异步成员服务器按照上面步骤同样创建本地数据库。注意在输入关于数据库的详情中确保每一个成员的Mirror DB Name相同(本地的数据库名称可以不同)。 将已有数据库配置为镜像数据库 将主机已有数据库加入镜像 在主failover成员management port中,从菜单中选择 配置数据库 选中需要镜像的数据库,点击 添加到镜像 来添加需要mirror 的数据库 选择需要添加进入Mirror 的数据库并点击添加 此时从镜像监视器 中可以看到 镜像数据库 增加了我们刚才添加的数据库 数据库备份 对此主服务器的需要mirror 的数据库进行备份并获取备份文件,并拷贝至备机。执行备份可以通过management portal 运行实现。 management portal -> 系统管理 -> 配置-> 数据库备份 ->备份数据库列表 系统操作-> 备份 -> 完全备份列表 注意:这里需要关注主机本身journal 的保存时间,因为mirror 的同步机制是主机推journal 给备机,所以如果备份的时间为1月1 日零点,主机journal 保存时间为1天,备份需要2天,则中间1天的时间差所产生的数据是没有办法恢复的。 数据库备份恢复 在备Failover成员的%SYS 命名空间下使用^BACKUP routine, 将备份文件恢复至备机,则可在备机中看到恢复的数据库已只读方式被挂载 caught up 数据库 在备机上进入 系统操作 - 镜像监视器 ,可见备机的镜像有need activation 状态,点击Activate,结束后,下一步点击 catchup。 最终可见备机为 active,caught up 状态。 删除镜像配置 删除镜像配置必须按照下面顺序执行:删除异步成员,然后删除备份failover成员,最后删除主failover成员。 删除异步成员 进入菜单 系统管理 – 配置 – 镜像设置 – 编辑异步: 如果想要移除报表服务的异步成员,使用Leave mirror链接。 如果想要移除所有的链接异步成员以及相关配置,使用Remove Mirror Configuration按钮: 移除备failover成员 想要移除failover成员必须在%SYS命名空间下 执行^MIRROR routine。 a. 在 Terminal中切换到%SYS命名空间,执行d ^MIRROR b. 选择Mirror Configuration c. 选择Remove This Failover Member(如果在主failover服务器上操作则选择Remove Other Mirror Member) d. 按照提示操作,最后重启实例. 移除主failover成员 想要移除failover主成员必须在%SYS命名空间下 执行^MIRROR routine。 a. 在 Terminal中切换到%SYS命名空间,执行d ^MIRROR b. 选择Mirror Configuration c. 选择Remove This Failover Member d. 按照提示操作,最后重启实例. e. 选择Remove This Failover Member f. 按照提示操作,最后重启实例. 移除镜像数据库 从Async成员中移除数据库不会对failover成员的数据库有任何影响,但是如果从failover成员中移除数据库,也必须从其他failover成员以及Async成员中移除相应的数据库。想要从镜像配置中整体移除数据库需要遵循下面的顺序:主Primary failover成员 -> 备份Backup failover成员 -> Async成员。 a. 进入菜单 系统操作 – 镜像监视器 b. 在镜像数据库中点击 移除 断开连接/开始连接镜像成员 可以临时断开备failover镜像成员或者Async镜像成员。 进入菜单 系统操作 – 镜像监视器 选择 在这个成员上终止镜像 在虚拟环境下配置镜像操作 在虚拟环境下进行镜像配置,同时建议进行下面配置以提高可靠性: · 应该为每一个failover成员进行虚拟主机(virtual host)的配置,保证每一个failover成员不会指向同一个物理上的host。 · 为了避免单一指向存储的损坏,每一个failover成员上Caché实例使用的存储应该固定分配到相互隔离的磁盘阵列或者磁盘组中。 · 有些虚拟架构下自动执行的操作,比如虚拟主机迁移到备用存储,可能造成failover成员间的短暂连接中断。如果在记录中竟让发现类似这样的中断警告,可以进入修改镜像配置的页面,在Advanced Mirror Settings下适当提高QoS Timeout设置的时间。 · 当进行计划维护操作(比如快照snapshot管理)时,会引起镜像成员中的连接中断,可以在备机的Mirror Monitor页面选择Stop Mirror on this server,临时断开备份backup成员,以避免相应的mirror警告信息。 · 在配置Mirror主备服务器中,不建议使用systemctl 设置开机自动启动IRIS。因为在主备切换过程中,如果使用systemd启动关闭IRIS不是成对出现,或者使用iris start/stop instance 不是成对出现,则有可能出现不可预知错误。 配置成功状态 主机状态: 备机状态:
文章
Claire Zheng · 三月 1, 2021

欢迎为中文社区参赛者投票!

本周进入 InterSystems 编程大奖赛 的投票时间! 此次中国有多位参赛者,我们将其项目罗列在此,欢迎投票! 项目一: Dictionary comparison scheme of cache database Author: Weiwei Yang 概述:现场需要将各个科室部门内的数据统一汇总到医院总部,但是汇总后发现各个科室使用的字典并不统一,需要将表中的现存的字典统一更换为医院制定字典。例如:A科室中人员的性别字典使用0/1/2表示各种性别,B科室中性别字典使用F/M/O表示各种性别,但是现在医院要求所有性别字典保存Female/Male/Other性别信息,此时就需要替换原有的性别字典为新用字典。当初,此处只是列举了一个使用场景,未来有多个需要对照字典的工作都可以考虑此项目的设计和实现思想。 点击投票 项目二: HealthInfoQueryLayer Author: Botai Zhang 基于Intersystems IRIS平台整合医院信息查询业务解决方案 概述:随着医院信息化建设的逐步完善,医院子系统越来越多,系统间接口越来越多,同时接口费用不断增加,管理工作变得越来越复杂。其中,查询类业务接口根据业务类型分化,数量也是逐步递增,带来接口量大、开发工作繁重、代码冗余、维护困难等等问题。针对这一困境,我们基于Intersystems IRIS数据平台整合医院信息查询业务解决方案。该应用程序可通过配置完成查询业务接口实现,大大缩小开发、维护、实施等项目关键运转周期。 点击投票 项目三: Integration scheme for heterogeneous messages in heterogeneous systems Author: Deming Xu 异构系统和异构消息的集成方案 概述:随着现代医院建设的信息化程度越来越高,对接的子系统数量也越来越多,系统的架构、接口类型、消息结构越来越复杂,对医院系统之间的信息传递造成很大不便。为了解决该问题,我们采用HL7、XML等标准,使用Ensemble内置的数据转换工具(DT),将异构系统的接口进行标准化(通常引用Soap、REST、TCP/IP等标准协议),使得不同架构的系统,即时接口类型不同、消息模型不同,也能进行数据的传输。 关键词:HL7、XML、Settings、DataTransform、JDBC、SQL 点击投票 项目四: Create a unified hospital data extraction scheme based on IRIS for Health Author: Deming Xu 基于 IRIS for Health 创建医院数据统一提取方案 概述:随着医院信息化建设内容不断丰富,业务面覆盖越来越广,相关科研项目的数据需求也越来越多,医院对各个业务系统的数据管理提出了新的要求。由于科研项目背景多样,需求中的数据模型也不尽相同,各个系统的接口开发、接口管理、代码维护工作也变得越来越繁杂。针对这一困境,我们采用IRIS创建医院数据统一提取方案 。该应用程序提供一个公共的数据提取服务(BS),可通过配置完成获取多个不同数据源的接口开发(多个BO),大大缩小开发、维护、实施等成本。 点击投票 项目五: RESTFUL_API_For_Hotel_OverBooking_System Author: jingqi LIu Develop RESTFUL Data API in InterSystems IRIS Data Platform Development for Hotel Overbooking Management System. PS:The overbooking management system combines the unique conditions of the hotel, such as room prices, order channels, customer needs (etc...). System uses machine learning algorithms (such as: KNN/ES-RNN...) to accurately predict the daily no-show and occupancy rate of the hotel, and further combines with the revenue equation to find the best largest room sales volume, which can significantly increase the hotel marginal revenue. 这是一个在InterSystems IRIS中用ObjectScript构建的REST API应用的演示。它也有OPEN API规范,可以用Docker和VSCode开发,可以作为ZPM模块部署,可以作为Overbooking系统数据的REST api使用。 点击投票 Useful! 新用户投票前必读哦:如何成为社区活跃用户(Active user) 这几个医疗行业应用都非常不错,学习到很多! 欢迎为您喜欢的选手投票! 欢迎新加入的朋友们发言、评论、回复成为活跃用户后为中国参赛选手投票,每人可以投3票! @Hao.Wang @z.c @Zhaoying.Li @Neal.Wu @liu.yaquan @qu.qu @wang.wei @guo.meiya @yajing.xu @yue.li @权权.苏 @xiaohu.xiong @yadong.zhao @Yi.Han @Wen.Zhou @jie.zhang @张.恒 @guo.wenheng @Jing.Li3826 @迪.文 这个贴子很棒!完美的解决了我的问题! 欢迎新朋友,请大家发表内容时尽量在中文社区发表,多发表高质量内容,为中文社区多做贡献, 包括但不限于回答问题,撰写文章,贡献软件库、代码、工具等等,多谢支持! @young.zheng @an.xingqi2532 @jinhui.hu @wenyang.zhang @guoguo.wang @shikai.ren @chaolong.huang @yabin.duan @鹏飞.楚 @智辉.李 @shan.hu @Wendy.Wu 好的,谢谢 马上投票 发布完还要等24小时 你好,第一次发帖24小时后就可以投票吗 准备投票 是的 原来是这样,明白了 期望多一些应用,多多学习! 能够学习到具体的应用,很棒!👍 学习IRIS在国内多行业应用,棒👍 好的,谢谢! 感谢提醒,👍
文章
Michael Lei · 十一月 12, 2021

企业软件的“大众点评”之最新Gartner 云数据管理系统对比,国内医疗信息行业主流的Hadoop(Cloudera)vs Oracle vs Sql Server vs InterSystems Cache

Gartner Peer Insight 一直持续公开对各类第三方软硬件的对比,是IT行业的“大众点评“。综合转载如下,仅供参考。 原文链接:https://www.gartner.com/reviews/market/cloud-database-management-systems/compare/product/cloudera-enterprise-data-hub-vs-intersystems-cache-vs-microsoft-sql-server-vs-oracle-database Gartner Peer Insights 是Gartner 提供的由专业最终用户用来对企业级技术解决方案进行打分和评估供企业使用的平台。Gartner 会将用户意见和他们的专业意见综合起来形成魔力象限。 Cloudera EDH(Hadoop企业版) MS SQL Server Oracle ISC Caché 总分--Overall Ratings 4.4 4.5 4.4 4.6 分项评分--Overall Capacity整体技术能力 4.5 4.6 4.6 4.6 分项评分--评估与合同(商务)Evaluation & Contracting 4.2 4.3 4.1 4.5 分项评分--集成与部署Integration & Deployment 4.2 4.5 4.3 4.6 分项评分--服务与支持Service&Support 4.3 4.4 4.2 4.7