搜索​​​​

清除过滤器
文章
Veerarajan Karunanithi · 二月 28, 2024

使用 SQL 文本搜索从非结构化数据中获取见解

什么是非结构化数据?非结构化数据是指缺乏预定义数据模型或组织的信息。与数据库中具有清晰结构(例如表和字段)的结构化数据相比,非结构化数据缺乏固定的模式。此类数据包括文本、图像、视频、音频文件、社交媒体帖子、电子邮件等。 为什么来自非结构化数据的见解很重要?根据 IDC(国际数据公司)的报告,预计到 2025 年,全球 80% 的数据将是非结构化的,这将成为 95% 企业的重大担忧。 福布斯文章 人工智能世界如何解决这个问题?在人工智能领域,生成式人工智能在为非结构化数据提供解决方案方面发挥着至关重要的作用。它擅长从文本/图像/视频中提取有价值的信息、文本摘要和处理文档等任务。 Intersystems 非结构化数据解决方案Intersystems IRIS 提供了一种称为“SQL 文本搜索”的特殊解决方案,用于搜索非结构化数据。此功能有助于对多种语言的非结构化文本数据进行语义上下文搜索。 使用 SQL 文本搜索有什么优点? 快速搜索: InterSystems IRIS SQL 搜索利用优化的索引生成快速导航大量数据,避免对数据本身进行顺序搜索。 单词感知搜索:与基本字符串搜索不同,SQL 搜索依赖于文本中的语义结构,以单词为基本单位。这种方法最大限度地减少了嵌入字符串或跨越两个单词的字符串引起的误报。 实体感知搜索: SQL 搜索考虑语义关系以将多个单词分组为实体。它可以搜索指定的单词序列、邻近的单词(无论顺序如何)以及实体开头或结尾的单词,从而实现精确的上下文搜索。 语言感知搜索:识别语义关系是特定于语言的,SQL 搜索合并了十种自然语言的语言模型。它还支持其他语言,无需创建词典或本体。 模式匹配: SQL 搜索为字符模式提供通配符和正则表达式 (RegEx) 匹配。 模糊匹配: SQL 搜索包括近似匹配的模糊搜索功能,考虑到搜索字符串的计算变异程度。即使出现拼写错误,这也有助于匹配。 派生匹配: SQL 搜索采用分解来匹配根词和组成词,并利用同义词表来匹配同义词和短语。 如何使用非结构化数据实现 SQL 文本搜索:MIND 的实际示例 为了演示 SQL 文本搜索对非结构化数据的实现,我们将使用 Microsoft 新闻数据集 (MIND) 作为示例,重点关注小型训练集。 注意:提供的示例使用 User 命名空间,但您可以将其替换为您选择的任何合适的命名空间,确保所有操作都发生在同一命名空间内。 第 1 步:下载并提取训练数据从 MIND 下载 MIND 训练数据集MIND (msnews.github.io)并从存档中提取 news.tsv 文件。该文件以制表符分隔,我们将主要关注“类别”、“标题”和“描述”字段。 第 2 步:创建持久类创建一个名为“Test.JSON”的持久类,其属性为“Title”(字符串)、“Category”(字符串)和“Description”(字符串)。专门为“Description”属性创建 %IFind.Basic 索引,以增强文本搜索性能。创建索引后,编译该类。 第 3 步:加载 MIND 数据集将 MIND 数据集加载到新创建的类中。您可以使用类和对象方法或 SQL 来填充该表。以下代码演示了使用类和对象方法加载数据集。 第 4 步:验证数据集加载加载数据集后,查询表以确保它准确包含预期的行。您可以使用终端中的 SQL 管理门户或 SQL Shell 进行此验证。 第 5 步:利用索引进行查询现在,利用特定索引来设计查询并提取见解。例如,您可以使用以下查询: 检索微软公司新闻: SELECT %iFind.Highlight(Description, '"microsoft*"' ) FROM Test.JSON WHERE % ID %FIND search_index(DescriptionIdx, '"microsoft*"' , 0 , 'en' ) 检索Google公司新闻: SELECT %iFind.Highlight(Description, '"google*"' ) FROM Test.JSON WHERE % ID %FIND search_index(DescriptionIdx, '"google*"' , 0 , 'en' ) 检索 Google 和 Microsoft 的合并新闻: SELECT %iFind.Highlight(Description, '"microsoft*" "google*"' ) FROM Test.JSON WHERE % ID %FIND search_index(DescriptionIdx, '"microsoft*" "google*"' , 0 , 'en' ) 免责声明:请务必注意,语义和分析 SQL 搜索索引使用 InterSystems IRIS 自然语言处理 (NLP),而 InterSystems 已弃用该技术。截至最新社区版版本(2023.3.0),该功能仍然有效,但在未来版本中可能会被删除。使用 SQL 文本搜索的风险由您自行承担。 我将使用已弃用的 SQL 文本搜索的替代选项来撰写本文的续篇。如果您喜欢我的文章,请在下面投票并提出您的宝贵建议。谢谢你! 解说视频 Thank you and looking fwd to more posting in CN !
文章
姚 鑫 · 四月 7, 2021

第十九章 存储和使用流数据(BLOBs和CLOBs)

# 第十九章 存储和使用流数据(BLOBs和CLOBs) Intersystems SQL支持将流数据存储为Intersystems Iris ®DataPlatform数据库中的 `BLOBs`(二进制大对象)或 `CLOBs`(字符大对象)的功能。 # 流字段和SQL Intersystems SQL支持两种流字段: - 字符流 `Character streams`,用于大量文本。 - 二进制流 `Binary streams`,用于图像,音频或视频。 ## BLOBs and CLOBs Intersystems SQL支持将`BLOBs`(二进制大对象)和`CLOBs`(字符大对象)存储为流对象的功能。 `BLOBs`用于存储二进制信息,例如图像,而`CLOBs`用于存储字符信息。 **`BLOBs`和`CLOBs`可以存储多达4千兆字节的数据(JDBC和ODBC规范所强加的限制)。** 在各种方面,诸多方面的操作在通过ODBC或JDBC客户端访问时处理字符编码转换(例如Unicode到多字节):`BLOB`中的数据被视为二进制数据,从未转换为二进制数据另一个编码,而`CLOB`中的数据被视为字符数据并根据需要转换。 如果二进制流文件(`BLOB`)包含单个非打印字符`$CHAR(0)`,则被认为是空二进制流。它相当于`""`空二进制流程值:它存在(不是`null`),但长度为0。 ## 定义流数据字段 Intersystems SQL支持流字段的各种数据类型名称。这些Intersystems数据类型名称是与以下内容对应的同义词: - 字符流:数据类型`LONGVARCHAR`,映射到`%stream.globalcharacter`类和ODBC / JDBC数据类型`-1`。 - 字符流:数据类型`LONGVARBINARY`,映射到`%Stream.GlobalBinary`类和ODBC / JDBC数据类型`-4`。 某些Intersystems流数据类型允许指定数据精度值。此值是no-op,对流数据的允许大小没有影响。提供它以允许用户记录预期的未来数据大小。 以下示例定义包含两个流字段的表: ```sql CREATE TABLE Sample.MyTable ( Name VARCHAR(50) NOT NULL, Notes LONGVARCHAR, Photo LONGVARBINARY) ``` 分片表不能包含流数据类型字段。 ### 流字段约束 Stream字段的定义符合以下字段数据约束: 流字段可以定义为 `NOT NULL`。 流字段可以占用默认值,更新值或计算码值。 流字段不能定义为唯一,主键字段或`idkey`。试图这样做导致`SQLCode -400`致命错误,其中%MSG如下:` ERROR #5414: Invalid index attribute: Sample.MyTable::MYTABLEUNIQUE2::Notes, Stream property is not allowed in a unique/primary key/idkey index > ERROR #5030: An error occurred while compiling class 'Sample.MyTable'.` 无法使用指定的`COLLATE` 值定义流字段。试图这样做导致`SQLCode -400`致命错误,其中`%MSG`如下:` ERROR #5480: Property parameter not declared: Sample.MyTable:Photo:COLLATION > ERROR #5030: An error occurred while compiling class 'Sample.MyTable'.` ## 将数据插入流数据字段 将数据插入流字段有三种方法: - `%Stream.Globalcharacter`字段:可以直接插入字符流数据。例如, ```sql INSERT INTO Sample.MyTable (Name,Notes) VALUES ('Fred','These are extensive notes about Fred') ``` ![image](/sites/default/files/inline/images/1_31.png) ```java Class Sample.MyTable Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {yx}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = MyTable ] { Property Name As %Library.String(MAXLEN = 50) [ Required, SqlColumnNumber = 2 ]; Property Notes As %Stream.GlobalCharacter [ SqlColumnNumber = 3 ]; Property Photo As %Stream.GlobalBinary [ SqlColumnNumber = 4 ]; /// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement. Do not edit the SqlName of this index. Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ]; Storage Default { Name Notes Photo ^Sample.MyTableD MyTableDefaultData sequence ^Sample.MyTableD ^Sample.MyTableI ^Sample.MyTableS %Library.CacheStorage } } ``` - `%stream.globalcharacter`和`%stream.globalbinary`字段:可以使用oref插入流数据。可以使用`Write()`方法将字符串附加到字符流,或者写入的方法,以将具有行终结器的字符串附加到字符流。默认情况下,行终结器是`$CHAR(13,10)`(回车返回/线路);可以通过设置`LineTerminator` 属性来更改行终结器。在以下示例中,示例的第一部分创建由两个字符串和其终端组组成的字符流,然后使用嵌入的SQL将其插入流字段。示例的第二部分返回字符流长度,并显示显示终结器的字符流数据: ```java /// d ##class(PHA.TEST.SQL).StreamField() ClassMethod StreamField() { CreateAndInsertCharacterStream SET gcoref=##class(%Stream.GlobalCharacter).%New() DO gcoref.WriteLine("First Line") DO gcoref.WriteLine("Second Line") &sql(INSERT INTO Sample.MyTable (Name,Notes) VALUES ('Fred',:gcoref)) IF SQLCODEd ##class(PHA.TEST.SQL).StreamField() 插入成功 1 ^CacheStream=1 ^CacheStream(1)=1 ^CacheStream(1,0)=25 ^CacheStream(1,1)="First Line"_$c(13,10)_"Second Line"_$c(13,10) ``` ![image](/sites/default/files/inline/images/2_19.png) - `%stream.globalcharacter`和`%stream.globalbinary`字段:可以通过从文件读取它来插入流数据。例如, ```java /// d ##class(PHA.TEST.SQL).StreamField1() ClassMethod StreamField1() { SET myf="E:\temp\game.jpg" OPEN myf:("RF"):10 USE myf:0 READ x(1):10 &sql(INSERT INTO Sample.MyTable (Name,Photo) VALUES ('George',:x(1))) IF SQLCODEd ##class(PHA.TEST.SQL).StreamField1() WRITE "插入成功",! ^ zStreamField1+11^PHA.TEST.SQL.1 DHC-APP 2d0>g WRITE "插入成功",! ^ zStreamField1+11^PHA.TEST.SQL.1 DHC-APP 2d0>g DHC-APP> ``` ![image](/sites/default/files/inline/images/3_14.png) 作为默认值或计算值插入的字符串数据以适合于流字段的格式存储。 ## 查询流字段数据 选择流字段的查询选择项返回流对象的完全形成的OID(对象ID)值,如下例所示: ```sql SELECT Name,Photo,Notes FROM Sample.MyTable WHERE Photo IS NOT NULL ``` ![image](/sites/default/files/inline/images/4_11.png) OID是一个 `%List` 格式化数据地址,如以下内容:`$lb("1","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`。 - OID的第一个元素是一个连续的正整数(从1开始),它被分配给每个插入到表中的流数据值。 例如,如果第1行插入流字段`Photo`和`Notes`的值,则将它们赋值为1和2。 如果第2行插入了一个`Notes`值,则将该值赋给3。 如果用`Photo`和`Notes`的值插入第3行,则将它们赋值为4和5。 分配顺序是表定义中列出字段的顺序,而不是`INSERT`命令中指定字段的顺序。 默认情况下,使用单个整数序列,它对应于流位置全局计数器。 然而,一个表可能有多个流计数器,如下所述。 - 更新操作不会改变初始整数值。 `DELETE`操作可以在整型序列中创建空白,但不会改变这些整型值。 使用`DELETE`删除所有记录不会重置此整数计数器。 如果所有表流字段都使用默认的`StreamLocation`值,则使用`TRUNCATE TABLE`删除所有记录将重置此整数计数器。 不能使用`TRUNCATE`表为嵌入式对象(`%SerialObject`)类重置流整数计数器。 - OID的第二个元素是流数据类型,可以是`%Stream.GlobalCharacter` 或`%Stream.GlobalBinary`。 - OID的第三个元素是一个全局变量。 默认情况下,它的名称是从与表对应的包名和持久类名生成的。 一个`“S”`(用于流)被追加。 - 如果表是使用SQL `CREATE TABLE`命令创建的,这些包和持久化类名称将被散列为每个4个字符(例如,`^EW3K.Cn9X.S`)。 这个全局变量包含流数据插入计数器最近分配的值。 如果没有插入流字段数据,或者使用`TRUNCATE TABLE`删除所有表数据,那么这个全局变量是未定义的。 - 如果表是作为一个持久化类创建的,那么这些包和持久化类名不会被散列(例如`^Sample.MyTableS`)。 默认情况下,这是`StreamLocation`存储关键字`^Sample.MyTableS` 价值。 默认流位置是全局位置,如`^Sample.MyTableS`。此全局变量用于计算插入到没有自定义位置的所有流属性(字段)的次数。例如,如果`Sample.MyTable`中的所有流属性都使用默认流位置,则在`Sample.MyTable`的流属性中插入了10个流数据值时,`^Sample.MyTableS`全局变量包含值10。此全局变量包含最近分配的流数据插入计数器的值。如果没有插入流字段数据,或者使用截断表删除了所有表数据,则此全局变量未定义。 定义流字段属性时,可以定义自定义位置,如下所示:`Property Note2 As %Stream.GlobalCharacter (LOCATION="^MyCustomGlobalS")`;。在这种情况下,`^MyCustomGlobalS`全局用作指定此位置的流属性(或多个属性)的流数据插入计数器;未指定位置的流属性使用默认流位置全局(`^Sample.MyTableS`)作为流数据插入计数器。每个全局计数与该位置相关联的流属性的插入。如果没有插入流场数据,则位置`GLOBAL`是未定义的。如果一个或多个流属性定义了位置,则截断表不重置流计数器。 这些流位置全局变量的下标包含每个流字段的数据。例如,`^EW3K.Cn9X.S(3)`表示第三个插入的流数据项。`^EW3K.Cn9X.S(3,0)`是数据的长度。`^EW3K.Cn9X.S(3,1)`是实际的流数据值。 注意:流字段的`OID`与`RowID`或`Reference`字段返回的`OID`不同。`%OID`函数返回`RowID`或引用字段的`OID`;`%OID`不能与流字段一起使用。试图将流字段用作`%OID`的参数会导致`SQLCODE-37`错误。 在查询的`WHERE`子句或`HAVING`子句中使用流字段受到严格限制。不能将相等条件或其他关系运算符(`=, !=, `)或包含运算符(`]`)或跟随运算符(`[`)与流字段一起使用。尝试将这些运算符与流字段一起使用会导致`SQLCODE-313`错误。 ### Result Set Display - 从程序执行的动态SQL以`$lb("6","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`.格式返回`OID`。 - SQL Shell作为动态SQL执行,并以`$lb("6","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`格式返回`OID`。 - 嵌入式SQL返回相同的`OID`,但以编码`%LIST`的形式返回。可以使用`$LISTTOSTRING`函数将`OID`显示为元素以逗号分隔的字符串:`6,%Stream.GlobalBinary,^EW3K.Cn9X.S`。 从管理门户SQL执行界面运行查询时,不返回`OID`。取而代之的是: - 字符流字段返回字符流数据的前100个字符。如果字符流数据超过100个字符,则用省略号(`...`)表示。在第100个字符之后。这等效于`SUBSTRING(cstream field,1,100)`。 - 二进制流字段返回字符串``。 在表数据的管理门户SQL界面打开表显示中显示相同的值。 要从管理门户SQL执行界面显示`OID`值,请将空字符串连接到流值,如下所示:`SELECT Name, ''||Photo, ''||Notes FROM Sample.MyTable`。 ![image](/sites/default/files/inline/images/5_5.png) ## `DISTINCT`, `GROUP BY`, and `ORDER BY` 每个流数据字段的`OID`值是唯一的,即使数据本身包含重复。 这些`SELECT`子句操作的是流的`OID`值,而不是数据值。 因此,当应用到查询中的流字段时: - 不同的子句对重复的流数据值没有影响。 `DISTINCT`子句将流字段为`NULL`的记录数减少为一个`NULL`记录。 - `GROUP BY`子句对重复的流数据值没有影响。 `GROUP BY`子句将流字段为空的记录数量减少为一个空记录。 - `ORDER BY`子句根据数据流的`OID`值来排序数据,而不是数据值。 `ORDER BY`子句列出流字段为空的记录,然后列出带有流字段数据值的记录。 ## 谓词条件和流 `IS [NOT] NULL`谓词可以应用于流字段的数据值,示例如下: ```sql SELECT Name,Notes FROM Sample.MyTable WHERE Notes IS NOT NULL ``` `BETWEEN`, `EXISTS`, `IN`, `%INLIST`, `LIKE`, `%MATCHES`, and `%PATTERN` 谓词可以应用于流对象的`OID`值,示例如下: ```sql SELECT Name,Notes FROM Sample.MyTable WHERE Notes %MATCHES '*1[0-9]*GlobalChar*' ``` 尝试在流字段上使用任何其他谓词条件会导致`SQLCODE -313`错误。 ## 聚合函数和流 `COUNT`聚合函数接受一个流字段,并对该字段中包含非空值的行进行计数,示例如下: ```sql SELECT COUNT(Photo) AS PicRows,COUNT(Notes) AS NoteRows FROM Sample.MyTable ``` ![image](/sites/default/files/inline/images/6_4.png) 但是,流字段不支持`COUNT`(`DISTINCT`)。 对于流字段不支持其他聚合函数。 尝试将流字段与任何其他聚合函数一起使用会导致`SQLCODE -37`错误。 ## 标量函数和流 除了`%OBJECT`、`CHARACTER_LENGTH`(或`CHAR_LENGTH或DATALENGTH`)、`SUBSTRING`、`CONVERT`、`XMLCONCAT`、`XMLELEMENT`、`XMLFOREST`和`%INTERNAL`函数外,InterSystems SQL不能对流字段应用任何函数。 尝试使用流字段作为任何其他SQL函数的参数会导致`SQLCODE -37`错误。 尝试使用流字段作为任何其他SQL函数的参数会导致`SQLCODE -37`错误。 - `%OBJECT`函数打开一个流对象(接受一个`OID`)并返回oref(对象引用),示例如下: ```sql SELECT Name,Notes,%OBJECT(Notes) AS NotesOref FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/7_1.png) - `CHARACTER_LENGTH`、`CHAR_LENGTH`和`DATALENGTH`函数接受流字段并返回实际的数据长度,如下面的示例所示: ```sql SELECT Name,DATALENGTH(Notes) AS NotesNumChars,DATALENGTH(Photo) AS PhotoNumChars FROM Sample.MyTable ``` ![image](/sites/default/files/inline/images/8_2.png) `SUBSTRING`函数接受一个流字段,并返回流字段的实际数据值的指定子字符串,如下面的示例所示: ```sql SELECT Name,SUBSTRING(Notes,1,10) AS Notes1st10Chars FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/9_1.png) 当从管理门户SQL Execute接口发出时,子字符串函数返回流字段数据最多100个字符的子字符串。 如果流数据的指定子字符串大于100个字符,则在第100个字符后用省略号(`…`)表示。 - `CONVERT`函数可用于将流数据类型转换为`VARCHAR`,示例如下: ```sql SELECT Name,CONVERT(VARCHAR(100),Notes) AS NotesTextAsStr FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/111.png) `CONVERT(datatype,expression)`语法支持流数据转换。 如果`VARCHAR`精度小于实际流数据的长度,则将返回值截断为`VARCHAR`精度。 如果`VARCHAR`精度大于实际流数据的长度,则返回值为实际流数据的长度。 不执行填充。 `{fn CONVERT(expression,datatype)}`语法不支持流数据转换; 它发出一个`SQLCODE -37`错误。 - `%INTERNAL`函数可以用于流字段,但不执行任何操作。 # 流字段并发锁 InterSystems IRIS通过取出流数据上的锁来保护流数据值不被另一个进程并发操作。 InterSystems IRIS在执行写操作之前取出一个排他锁。 排他锁在写操作完成后立即释放。 当第一个读操作发生时,InterSystems IRIS取出共享锁。 只有当流实际被读取时才会获取共享锁,并且在整个流从磁盘读取到内部临时输入缓冲区后立即释放共享锁。 # 在Intersystems中使用流字段IRIS方法 不能在Intersystems Iris方法中直接使用嵌入式SQL或动态SQL使用`BLOB`或`CLOB`值;相反,使用SQL来查找`Blob`或`Clob`的流标识符,然后创建`%AbstractStream`对象的实例以访问数据。 # 使用来自ODBC的流字段 ODBC规范不提供对`BLOB`和`CLOB`字段的任何识别或特殊处理。 InterSystems SQL将ODBC中的`CLOB`字段表示为具有`LONGVARCHAR(-1)`类型。 BLOB字段表示为类型为`LONGVARBINARY(-4)`。 对于流数据类型的ODBC/JDBC数据类型映射,请参考InterSystems SQL reference中的数据类型引用页中的数据类型整数代码。 ODBC驱动程序/服务器使用一种特殊协议来访问`BLOB`和`CLOB`字段。 通常,必须在ODBC应用程序中编写特殊的代码来使用`CLOB`和`BLOB`字段; 标准的报告工具通常不支持它们。 # 使用来自JDBC的流字段 在Java程序中,可以使用标准的JDBC `BLOB`和`CLOB`接口从`BLOB`或`CLOB`检索或设置数据。 例如: ```java Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("SELECT MyCLOB,MyBLOB FROM MyTable"); rs.next(); // fetch the Blob/Clob java.sql.Clob clob = rs.getClob(1); java.sql.Blob blob = rs.getBlob(2); // Length System.out.println("Clob length = " + clob.length()); System.out.println("Blob length = " + blob.length()); // ... ``` 注意:当使用`BLOB`或`CLOB`结束时,必须显式调用`free()`方法来关闭Java中的对象,并向服务器发送消息以释放流资源(对象和锁)。 仅仅让Java对象超出范围并不会发送清理服务器资源的消息。
文章
Johnny Wang · 十一月 21, 2021

适合工作的工具:我们聆听了医疗行业开发人员的声音

在医疗领域,开发创新可以挽救更多的生命。 这也是为什么我们更需要去倾听负责构建未来的人:开发人员。 他们需要什么工具才能更有效地使应用程序更加高效? 他们面对着什么样的障碍? InterSystems 不想去做无用的猜测,因此我们推动进行了一项研究,该研究综合了 200 名医疗行业开发者的反馈,深入了解了他们的最大需求。我们认为,这些研究结果为医疗单位和医疗技术公司提供了一个机会,可以帮助他们的开发团队为业务带来新机遇,同样也为临床医生和患者带来更光明的未来。 以下是三个关键要点: 1. 开发人员想要一个统一的医疗平台。 在接受本次研究采访的 200 名开发人员中,有88% 的受访者表示他们是医疗 IT 领域的专家或该领域的技术人员——他们都希望能有最好的、为他们的行业量身定制的开发工具。 这就是为什么一半的受访者将统一的、专注于医疗的数据平台列为购买新开发工具的关键原因。 一个合适的医疗行业开发平台应该包括互操作性/集成引擎、分析工具、面向医疗行业的自然语言处理功能、机器学习工具和 FHIR 服务器,以及其他组件。 如果一家公司能够提供一个包含所有上述组件的平台,那么超过 90% 的开发人员将对这项技术非常感兴趣。 2. 临床数据模型必不可少 近 90% 的开发人员表示,技术供应商提供的临床数据模型是必不可少的,如果按照 10 分制来统计,这个需求会达到8 分甚至更高。 来自 EHR 的临床数据被 60% 的开发人员列为最优先的一类。而其他数据还包括CRM、医疗设备、健康的社会决定因素、索赔、财务和运营的数据。 3. 健康数据是实现价值的最快途径 干净、健康的数据将高质量企业与其他企业区分开来。 在开发人员希望技术供应商提供更干净、更健康数据的大背景下,这次研究的受访者表示,选择能够提供最干净数据的平台尤为重要。 一站式医疗保健平台 根据该报告,一线开发人员及管理层都想要这样一个医疗保健数据平台: (1)专注于医疗IT行业 (2)可扩展性 (3)与现有的开发工具兼容 (4)安全 (5)便于使用 我们推动进行这项研究是为了帮助我们确定 InterSystems IRIS for Health™ 的发展方向,而这也是一个专门设计用于从医疗数据中提取价值的数据平台。 开发人员使用该平台、使用这些旨在满足现代医疗需求的、安全的工具来创建和扩展医疗应用程序。 我们对这次的研究结果感到鼓舞,我们也将继续专注以使平台变得更好! 医疗 IT 软件开发人员面临的关键问题。 点击阅读最新研究结果! 想试用 InterSystems IRIS 数据平台吗?立刻免费编码! 关于作者:Chris Walker 领导 InterSystems 的业务开发团队,该团队正在帮助合作伙伴使用软件工具和服务来加速和增强他们推向市场的数字解决方案。 在他职业生涯的早期,他为麻省总医院开发了临床信息系统,并在健康和生命科学信息管理方面拥有超过 25 年的经验。 点击查看原文
文章
姚 鑫 · 一月 5, 2024

第十六章 调用Callout Library函数

# 第十六章 调用Callout Library函数 `Callout` 库是一个共享库(`DLL` 或 `SO` 文件),其中包含 `$ZF Callout` 接口的挂钩,允许各种 $ZF 函数在运行时加载它并调用其函数。 `$ZF Callout` 接口提供了四种不同的接口,可用于在运行时加载 `Callout` 库并从该库调用函数。这些接口的主要区别在于如何识别库并将其加载到内存中: - 使用 `$ZF()` 访问 `iriszf` 标注库描述了如何使用名为 `iriszf` 的特殊共享库。当该库可用时,可以通过 `$ZF("funcname",args)` 形式的调用来访问其函数,而无需事先加载该库或指定库名称。 - 使用 `$ZF(-3)` 进行简单库函数调用描述了如何通过指定库文件路径和函数名来加载库并调用函数。它使用简单,但虚拟内存中一次只能有一个库。与其他接口不同,它在调用库函数之前不需要任何初始化。 - 使用 `$ZF(-5)` 通过系统 `ID` 访问库描述了一种可用于一次有效维护和访问多个库的接口。可以同时加载和使用多个库,每个库所需的处理开销比 `$ZF(-3)` 少得多。内存中的库由加载库时生成的系统定义的 `ID` 来标识。 - 使用 `$ZF(-6)` 按用户索引访问库描述了处理大量标注库的最有效接口。该接口通过`Global`定义的索引表提供对库的访问。该索引可供 `IRIS` 实例中的所有进程使用,并且多个库可以同时位于内存中。每个索引库都被赋予一个唯一的、用户定义的索引号,并且可以在运行时定义和修改索引表。当库文件被重命名或重新定位时,与给定库 `ID` 关联的文件名可以更改,并且此更改对于按索引号加载库的应用程序来说是透明的。 # 使用 `$ZF()` 访问 `iriszf` 标注库 当名为 `iriszf` 的 `Callout` 库在实例的 `/bin` 目录中可用时,可以通过仅指定函数名称和参数的 `$ZF` 调用来调用其函数(例如,`$ZF("functionName",arg1, arg2))`.。无需事先加载库即可调用 `iriszf` 函数,并且实例中的所有进程都可以使用 `iriszf` 函数。 自定义 `iriszf` 库是通过创建标准 `Callout` 库、将其移动到实例的 `/bin` 目录并将其重命名为 `iriszf`(具体为 `iriszf.dll` 或 `iriszf.so`,具体取决于平台)来定义的。 以下是编译 `simplecallout.c` 示例(请参阅“创建 `Callout` 库”)并将其设置为 `iriszf` 库的步骤。这些示例假设实例在 `Linux` 下运行,安装在名为 `/intersystems/iris` 的目录中,但所有平台上的过程基本相同: 1. 编写并保存 `simplecallout.c`: ```java #define ZF_DLL #include "iris-cdzf.h" int AddTwoIntegers(int a, int b, int *outsum) { *outsum = a+b; /* set value to be returned by $ZF function call */ return IRIS_SUCCESS; /* set the exit status code */ } ZFBEGIN ZFENTRY("AddInt","iiP",AddTwoIntegers) ZFEND ``` 2. 生成`Callout`库文件(`simplecallout.so`): ```java gcc -c -fPIC simplecallout.c -I /intersystems/iris/dev/iris-callin/include/ -o simplecallout.o gcc simplecallout.o -shared -o simplecallout.so ``` 3. 从 `IRIS` 终端会话中使用 `$ZF(-3)` 测试库: ```java USER>write $ZF(-3,"/mytest/simplecallout.so","AddInt",1,4) 5 ``` 4. 现在安装该库以与 `$ZF()` 一起使用。将 `simplecallout.so` 复制到 `/bin`中,并将其重命名为 `iriszf.so`: ```java cp simplecallout.so /intersystems/iris/bin/iriszf.so ``` 5. 确认可以从 `IRIS` 会话中使用 `$ZF()` 调用代码: ```java USER>write $zf("AddInt",1,4) 5 ``` `iriszf` 库在首次使用时加载一次,并且永远不会卸载。它完全独立于本章前面描述的其他 `$ZF` 加载和卸载操作。 注意:静态链接库 `$ZF Callout Interface` 的早期版本允许将代码静态链接到 `InterSystems` 内核并使用 `$ZF()` 进行调用。不再支持静态链接,但 `irisz` 库提供相同的功能,无需重新链接内核。
文章
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! 很棒的应用! 非常棒!很好的应用!
问题
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服务
公告
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”。
问题
wei su · 九月 25, 2024

活动量

请问一下,活动量仪表盘这个界面怎么激活,实例怎么展现?我的服务器展开没有数据,但是是有消息记录的。 你好,这个界面的内容基于活动量监控,需要在production中加入BO Ens.Activity.Operation.Local,可参考https://cn.community.intersystems.com/post/%E9%9B%86%E6%88%90%E4%BA%A7%E5%93%81%E7%9A%84%E4%B8%9A%E5%8A%A1%E8%A1%8C%E4%B8%BA%E7%9B%91%E6%8E%A7 以及 https://cn.community.intersystems.com/post/intersystems-%E6%95%B0%E6%8D%AE%E5%B9%B3%E5%8F%B0%E4%BA%92%E6%93%8D%E4%BD%9C%E5%8A%9F%E8%83%BD%E8%BF%90%E8%A1%8C%E7%BB%B4%E6%8A%A4%E7%AE%A1%E7%90%86%E5%9F%BA%E7%A1%80-production%E7%AE%A1%E7%90%86%E4%B8%8E%E4%BC%98%E5%8C%96
文章
Qiao Peng · 一月 10, 2021

iOS平台上的FHIR和IRIS医疗版

# Swift-FHIR-Iris iOS应用程序支持将HealthKit数据导入InterSystems IRIS医疗版(或任何FHIR资源仓库库) ![main](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/FHIR.png) # 目录 * [演示目的](#goal) * [如何运行此演示](#rundemo) * [先决条件](#prerequisites) * [安装Xcode](#installxcode) * [打开SwiftUi](#openswiftui) * [配置模拟器](#simulator) * [启动InterSystems FHIR服务器](#lunchfhir) * [在iOS应用程序上操作](#iosplay) * [工作原理](#howtos) * [iOS](#howtosios) * [如何检查健康数据的授权](#authorisation) * [如何连接FHIR资源仓库](#howtoFhir) * [如何将患者信息保存到FHIR资源仓库](#howtoPatientFhir) * [如何从HealthKit中提取数据](#queryHK) * [如何将HealthKit数据转换为FHIR](#HKtoFHIR) * [后端 (FHIR)](#backend) * [前端](#frontend) * [ToDos](#todo) # 演示目的 目的是创建FHIR协议的端到端演示。 这里的端到端指的是从一个信息源到另一个信息源,例如iPhone。 苹果HealthKit将收集到的健康数据转换为FHIR,再发送到InterSystems IRIS 医疗版存储库。 必须通过web接口访问这些信息。 **TL;DR**: iPhone -> InterSystems FHIR -> web界面. # 如何运行此演示 ## 先决条件 * 客户端 (iOS) * Xcode 12 * 服务器和Web应用程序 * Docker ## 安装 Xcode 这里没有太多要说的,打开AppStore,搜索Xcode,安装。 ## 打开SwiftUi project Swift是苹果在iOS、Mac、Apple TV和Apple Watch中使用的一种编程语言,是objective-C的替代品。 双击Swift-FHIR-Iris.xcodeproj 单击左上角的箭头打开模拟器。 ![xcode](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/xcode_and_simulator.gif) ## 配置模拟器 打开Health 点击“Steps” 添加数据 ![simulator](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/configuration_simulator.gif) ## 启动InterSystems FHIR服务器 在该git的根目录下,运行以下命令: ```sh docker-compose up -d ``` 构建过程结束时,你将连接到FHIR资源仓库: http://localhost:32783/fhir/portal/patientlist.html ![portal](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_default.png) 该门户网站由@diashenrique创建. 为处理Apple活动足迹,进行了一些修改。 ## 在iOS应用程序上操作 iOS应用程序首先会请求你同意分享部分信息。 点击授权 ![authorize](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_authorize.gif) 然后点击“Save and test server”对FHIR服务器进行测试 默认设置指向docker配置。 操作成功后,就可以输入患者信息。 名字、姓氏、生日、性别。 将患者信息保存到Fhir。弹出窗口将显示唯一的Fhir ID。 ![savepatient](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/save_patient.gif) 可在门户网站查阅该患者信息: 访问: http://localhost:32783/fhir/portal/patientlist.html 在这里我们可以看到,增加了一个新的病人“Toto”,0个活动。 ![patient portal](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/patient_toto.png) 发送她的活动信息: 回到iOS应用程序,点击“Step count”。 这里显示的是一周的步数。在我们的案例中有2条记录。 现在可以单击发送,将这些数据发送到InterSystems IRIS FHIR。 ![ios send](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_send.gif) 从门户网站上查询新的活动记录: 现在我们可以看到Toto有两条新的观察和活动消息。 ![portal activites](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_activities.gif) 你还可以单击“chart”按钮以图表格式显示。 ![portal charts](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_chart.gif) # 工作原理 ## iOS 该demo大部分是基于SwiftUI构建的。 https://developer.apple.com/xcode/swiftui/ iOS和co的最新框架。 ### 如何检查健康数据的授权 它在SwiftFhirIrisManager 类中。 该类采用单例模式,可使用@EnvironmentObject对应用程序中进行的所有操作进行注释。 更多信息请访问 : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views 调用requestAuthorization的方法如下: ```swift // Request authorization to access HealthKit. func requestAuthorization() { // Requesting authorization. /// - Tag: RequestAuthorization let writeDataTypes: Set = dataTypesToWrite() let readDataTypes: Set = dataTypesToRead() // requset authorization healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (success, error) in if !success { // Handle the error here. } else { DispatchQueue.main.async { self.authorizedHK = true } } } } ``` 其中healthStore是HKHealthStore()的对象。 HKHealthStore类似于iOS中的healthdata数据库。 dataTypesToWrite和dataTypesToRead是我们想要在数据库中查询的对象。 授权的目的可以通过在Info.plist xml文件中添加以下内容完成: ```xml NSHealthClinicalHealthRecordsShareUsageDescription Read data for IrisExporter NSHealthShareUsageDescription Send data to IRIS NSHealthUpdateUsageDescription Write date for IrisExporter ``` ### 如何连接FHIR资源仓库 对于这一部分,我使用了从Smart-On-FHIR网站下载的FHIR包 : https://github.com/smart-on-fhir/Swift-FHIR 使用的类是FHIROpenServer。. ```swift private func test() { progress = true let url = URL(string: self.url) swiftIrisManager.fhirServer = FHIROpenServer(baseURL : url! , auth: nil) swiftIrisManager.fhirServer.getCapabilityStatement() { FHIRError in progress = false showingPopup = true if FHIRError == nil { showingSuccess = true textSuccess = "Connected to the fhir repository" } else { textError = FHIRError?.description ?? "Unknow error" showingSuccess = false } return } } ``` 这一步将在单例swiftIrisManager中创建一个新的对象fhirServer。 接下来使用getCapabilityStatement() 如果能够检索到FHIR服务器的capabilityStatement,则意味着已成功连接到FHIR资源仓库。 这个资源仓库不在HTTPS下,默认情况下Apple会阻止这种通信。 想要获取HTTP支持,可以对Info.plist xml文件进行如下编辑: ```xml NSAppTransportSecurity NSExceptionDomains localhost NSIncludesSubdomains NSExceptionAllowsInsecureHTTPLoads ``` ### 如何将患者信息保存到FHIR资源仓库 基本操作:首先检查存储库中是否已经存在该患者的信息 ```swift Patient.search(["family": "\(self.lastName)"]).perform(fhirServer) ``` 搜索具有相同姓氏的患者。 在这里,我们可以想象一下其他场景,比如使用Oauth2和JWT令牌加入patientId及其令牌。但在这个演示中,我们简单操作即可。 如果该患者信息已经存在,可以对其进行检索;否则,则创建新的患者信息 : ```swift func createPatient(callback: @escaping (Patient?, Error?) -> Void) { // Create the new patient resource let patient = Patient.createPatient(given: firstName, family: lastName, dateOfBirth: birthDay, gender: gender) patient?.create(fhirServer, callback: { (error) in callback(patient, error) }) } ``` ### 如何从HealthKit中提取数据 通过查询healthkit商店 store(HKHealthStore())即可完成。 这里我们查询一下步数。 使用predicate做好查询准备。 ```swift //Last week let startDate = swiftFhirIrisManager.startDate //Now let endDate = swiftFhirIrisManager.endDate print("Collecting workouts between \(startDate) and \(endDate)") let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate) ``` 然后,会根据数据类型(HKQuantityType.quantityType(forIdentifier: .stepCount))和predicate内容进行查询。 ```swift func queryStepCount(){ //Last week let startDate = swiftFhirIrisManager.startDate //Now let endDate = swiftFhirIrisManager.endDate print("Collecting workouts between \(startDate) and \(endDate)") let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate) let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .stepCount)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, results, error) in guard let results = results as? [HKQuantitySample] else { return } process(results, type: .stepCount) } healthStore.execute(query) } ``` ### 如何将HealthKit数据转换为FHIR 在这部分,我们使用了微软软件包HealthKitToFHIR https://github.com/microsoft/healthkit-to-fhir 这个包很有用,为开发商提供了将HKQuantitySample转换为FHIR Observation的功能。 ```swift let observation = try! ObservationFactory().observation(from: item) let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"]) observation.category = try! [CodeableConcept(json: [ "coding": [ [ "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "activity", "display": "Activity" ] ] ])] observation.subject = patientReference observation.status = .final print(observation) observation.create(self.fhirServer,callback: { (error) in if error != nil { completion(error) } }) ``` 其中item是HKQuantitySample,在我们的例子中是stepCount类型。 这个factory完成了大部分工作,将“unit”和“type”转换为FHIR codeableConcept,并将“value”转换为FHIR valueQuantity。 对PatientId的引用是通过强制转换json fhir引用手动完成的。 ```swift let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"]) ``` 对类别进行同样的操作 : ```swift observation.category = try! [CodeableConcept(json: [ "coding": [ [ "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "activity", "display": "Activity" ] ] ])] ``` 最后,在fhir资源仓库中创建observation : ```swift observation.create(self.fhirServer,callback: { (error) in if error != nil { completion(error) } }) ``` ## 后端 (FHIR) 没什么好说的,它基于InterSystems社区的fhir模板 : https://openexchange.intersystems.com/package/iris-fhir-template ## 前端 基于Henrique作品,Henrique是使用jquery制作的FHIR资源仓库的一个很好的前端。 https://openexchange.intersystems.com/package/iris-fhir-portal
文章
Lilian Huang · 八月 1, 2023

FHIR 应用系列--虚拟实验室: 基于VR和AI的重症监护室模拟培训

VR ICU® 是 InterSystems FHIR 创新孵化器 Caelestinus 的参与者。这篇文章将向您介绍我们利用 InterSystems FHIR Server 为医疗保健提供的 VR 解决方案。 我们是一家技术初创企业虚拟实验室,利用先进的 VR/AR 技术开发解决方案。VR ICU® 是一个针对重症监护室医务人员的培训平台,是在 Covid 时代为满足医院需求而创建的。 与InterSystems合作的优势 我们的 VR ICU® 解决方案符合实践需求,是与医院合作开发的。 除了技术解决方案和技能学习本身,记录培训课程、培训进度和成功率对于医院或麻醉学和重症监护部门的有效管理也至关重要。医务长可以通过了解谁在何时接受了培训,清楚地掌握能够在重症监护室使用设备的人员数量,从而有效地对他们进行培训,以保持技能、有控制地规划人员技能储备并提高他们的能力。 在这方面,与 InterSystems 的合作对我们来说至关重要,它使我们能够在应用程序中存储每次培训期间的数据。目前,我们会记录参与者的姓名、培训日期和时长、培训类型、设备类型、错误数量和类型,必要时还会记录培训成功完成的信息。 如何使用?用户登录应用程序并选择一个账户。 根据 HL7 标准,该账户作为从业人员存在于数据库的资源下。培训课程开始时,会在应用程序中创建一个新的 "任务"--在这里输入培训课程的开始时间和培训课程的类型,课程结束时,再次输入培训课程的结束时间。错误会写入输出表。培训完成后,任务中的数据将序列化为 JSON 格式,并使用 FHIR API 发送到云端。为了使 VR 应用程序之外的数据可视化,我们开发了一款平板电脑应用程序。该应用程序与存储在云端的数据相连,并显示特定用户的个人训练课程。 人力资源部门通过培训数据了解受训人员完成培训的总体情况和水平,从而有效地规划他们的进一步培训,并跟踪了解员工的能力及其在重症监护室护理过程中的替换性。您可以点击这里:https://www.youtube.com/watch?v=3oO0uuHy0kg&t=8s 如今,医院、大学和模拟中心都在使用 VR ICU®。 虚拟现实技术将教育和培训提升到了一个新的水平。通过体验学习,可以提高培训效果和记忆力。 在 VR ICU® 中使用 InterSystems 的 FHIR 云服务器作为存储培训进度数据的工具,并使用 FHIR API 进行通信,这也对我们进军国外市场产生了积极影响,尤其是在德国,FHIR 标准是一种广为接受的解决方案,用于与人力资源部门传输信息,并与第三方调度系统进行通信。 麻醉学和重症监护审查参考:https://www.youtube.com/embed/Qve5xEm89cU?feature=oembed 它是如何开始的? 2020 年,一场大流行病袭击了我国。医院人满为患,人手短缺,尤其是重症监护室。麻醉、复苏和重症医学科主任在晚间新闻中解释说,如果更多的医生被隔离或生病,他就没有足够的合格人员来操作肺部呼吸机。其他医院也证实了同样的情况。我们萌生了制作一个专门用于培训的肺部呼吸机数字拷贝,帮助医院培训其他科室医生的想法。 我们找到了麻醉复苏部(ARO)的负责人、模拟中心的专家。医生们支持我们的想法,有些人还参与了开发工作。我们还得到了医疗设备制造商的支持,他们看到了虚拟现实培训的附加值。 我们是如何开展项目的,解决方案的重要性何在? 1. 我们评估了重症监护室的现状: - 在没有真实病人和/或医疗设备的情况下,50% 以上的重症监护室程序无法进行培训。 - 医疗设备制造商难以将医务人员集中到一处进行培训(只有 30% 的受训人员能坚持到培训结束) - 过去两年中,麻醉学和重症监护部门的人员流动率约为 20%。 2. 问题的解决方案: - 虚拟现实自动培训平台 - 模拟重症监护室的手术过程,无需真实病人,也无需使用真实医疗设备 - 节省技术和医疗用品 - 也可用于远程培训,从不同地点/工作场所进入同一个虚拟空间 - 在安全的环境中进行风险情况演练 - 将人为错误的风险降至最低 3. 潜力: - 利用人工智能(AI)模拟和练习危急情况,确定正确的程序 - 人工智能可模拟病人-设备-病人之间的互动 - 制造商的设备集中在一个虚拟空间,使医院的培训更加容易 愿景 VR ICU® 的目标是作为一个平台,让医院从实际使用的设备目录中选择 3D 设备,并从中创建培训环境。 我们向医疗设备制造商提出的愿景最初得到了 BBraun、费森尤斯和 Linet 的支持。随后,其他公司也纷纷效仿这些大胆的先行者。我们还根据所进入的市场扩大我们的设备组合。目前,我们在美国、亚洲和南美都有合作伙伴,他们正在补充信息并与制造商进行谈判。 我们正在全球会议上展示 VR ICU®,我们很高兴能成为 Caelestinus 孵化器的一部分。由于我们与 InterSystems 的合作,我们有机会参加在西雅图举行的 InterSystems 2022 年全球峰会,现在我们正在拉斯维加斯参加 HLTH 2022。 VR ICU® 已经赢得了许多奖项,最近在奥地利林茨,我们凭借该解决方案赢得了最佳初创企业奖。 这些成功的展示吸引了投资者的关注。我们欢迎那些希望进一步开发我们产品的人向我们推荐他们。我们计划在 2023 年向捷克、斯洛伐克和德国的医院出售许可证。我们欢迎商业合作伙伴以及能够加快 VR ICU® 实际应用--市场进入进程或希望为人工智能/VR 版本的开发做出贡献的合作伙伴。 原文来自这里:https://community.intersystems.com/node/529381
文章
姚 鑫 · 二月 22, 2021

第四十四章 Caché 变量大全 $ZTRAP 变量

# 第四十四章 Caché 变量大全 $ZTRAP 变量 包含当前错误陷阱处理程序的名称。 # 大纲 ``` $ZTRAP $ZT ``` # 描述 `$ZTRAP`包含当前错误陷阱处理程序的行标签名和/或例程名。有三种方法可以设置`$ZTRAP`: - `SET $ZTRAP=“location”` - `SET $ZTRAP=“*location”` - `SET $ZTRAP=“^%ET” or “^%ETN”` 在这里,位置可以指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。 **然而,`$ZTRAP=label^routine`不能用于程序块。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置**。 ## Location 使用设置命令,可以将位置指定为带引号的字符串。 - 在例程中,可以将位置指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。不要在引用过程或过程中的标签的例程中指定位置。这是一个无效位置;当InterSystems IRIS试图执行`$ZTRAP`时,会导致运行时错误。 - 在过程中,可以将位置指定为标签;过程块中私有标签。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置。因此,在过程中,不能将`$ZTRAP`设置为`^routine`或`label^routine`.尝试这样做将导致``错误。 在过程中,将`$ZTRAP`设置为私有标签名,但是`$ZTRAP`值不是私有标签名;它是从过程标签(过程的顶部)到私有标签的行位置的偏移量。例如,`+17^myproc`. 注意:`$ZTRAP`在某些情况下(而不是在过程中)为`label + offset`提供传统支持。这个可选的`+ offset`是一个整数,指定要从`label`偏移的行数。标签必须在相同的例程中。不建议使用`+offset`,它可能会导致编译警告错误。 InterSystems建议您在指定位置时避免使用行偏移量。 调用过程或IRIS `SYS`%例程时,不能指定`+`偏移量。如果尝试这样做,则InterSystems IRIS会发出错误。 `$ZTRAP`位置必须在当前名称空间中。 `$ZTRAP`不支持扩展的例程引用。 如果指定了不存在的行标签(当前例程中不存在的位置),则会发生以下情况: - 显示`$ZTRAP`:在例程中,`$ZTRAP`包含`label ^ routine`。例如,`DummyLabel^MyRou`。在一个过程中,`$TRAP`包含最大可能的偏移量:`+ 34463 ^ MyProc`。 - 调用$ZTRAP:InterSystems IRIS发出``错误消息。 每个堆栈级别可以有其自己的`$ZTRAP`值。设置`$ZTRAP`时,系统会将`$ZTRAP`的值保存为先前的堆栈级别。当前堆栈级别结束时,InterSystems IRIS会恢复该值。要在当前堆栈级别启用错误陷阱,请通过指定`$ZTRAP`的位置将其设置为错误陷阱处理程序。例如: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { IF $ZTRAP="" { WRITE !,"$ZTRAP not set" } ELSE { WRITE !,"$ZTRAP already set: ",$ZTRAP SET oldtrap=$ZTRAP } SET $ZTRAP="Etrap1^Handler" WRITE !,"$ZTRAP set to: ",$ZTRAP // program code SET $ZTRAP=oldtrap WRITE !,"$ZTRAP restored to: ",$ZTRAP } ``` 发生错误时,此格式将展开调用堆栈,并将控制权转移到指定的错误陷阱处理程序。 在SqlComputeCode中,不要设置`$ZTRAP = $ZTRAP`。这可能导致事务处理和错误报告方面的重大问题。 要禁用错误捕获,请将`$ZTRAP`设置为空字符串(`“”`)。这将清除在当前DO堆栈级别设置的所有错误陷阱。 注意:在“终端”提示符下使用$ZTRAP仅限于当前代码行。 `SET $ZTRAP`命令和生成错误的命令必须在同一行代码中。终端在每个命令行的开头将`$ZTRAP`还原为系统默认值。 ## *Location 在例程中,可以选择在发生错误后保留调用堆栈。为此,请在位置之前和双引号内放置一个星号(`*`)。该表格不适用于程序。尝试这样做会导致`` 错误。只能在不是过程的子例程中使用此示例中的: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { Main SET $ZTRAP="*OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP // program code OnError // Error handling code QUIT } ``` 这种格式只会导致转到`$ZTRAP`中指定的行标签;`$STACK`和`$ESTACK`保持不变。`$ZTRAP`错误处理例程的上下文框架与发生错误的上下文框架相同。但是,InterSystems IRIS会将`$ROLES`重置为设置`$ZTRAP`的执行级别的有效值;这会阻止`$ZTRAP`错误处理程序使用在建立错误处理程序后授予例程的提升权限。完成`$ZTRAP`错误处理例程后,InterSystems IRIS将堆栈展开到上一个上下文级。这种形式的`$ZTRAP`对于分析意外错误特别有用。 请注意,星号设置`$ZTRAP`选项;它不是位置的一部分。因此,在`$ZTRAP`上执行`WRITE`或`ZZDUMP`时不会显示此星号。 ## ^%ETN 在例程中,`set $ZTRAP=“^%ETN”`将系统提供的错误例程`%ETN`建立为当前错误捕获处理程序。`%ETN`在调用它的发生错误的上下文中执行。(`%et`是`%etn`的旧名称。它们的功能相同,但`%ETN`的效率略高一些。)。`^%ETN`错误处理程序的行为总是前缀星号(`*`)。 因为过程块中的`$ZTRAP`不能用于转到过程主体之外的位置,所以不能在过程中使用`SET $ZTRAP=“^%ETN”`。尝试这样做会导致``错误。 ## TRY / CATCH 与 $ZTRAP 不能在`TRY`块内设置`$ZTRAP`。尝试这样做会生成编译错误。可以在`TRY`块之前或在`CATCH`块内设置`$ZTRAP`。 **无论之前是否设置了`$ZTRAP`,`TRY`块中发生的错误都由`CATCH`块处理。`CATCH`块内发生的错误由当前错误捕获处理程序处理。** 下面的第一个示例显示了`TRY`块中发生的错误。下面的第二个示例显示了`try`块中引发的异常。在这两种情况下,都会采用`CATCH`块,而不是`$ZTRAP`: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { SET $ZTRAP="Ztrap" TRY { WRITE 1/0 } /* divide-by-zero error */ CATCH { WRITE "Catch taken" } QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP() Catch taken ``` ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP1() ClassMethod ZTRAP1() { SET $ZTRAP="Ztrap" TRY { SET myvar=##class(Sample.MyException).%New("Example Error",999,,errdatazero) WRITE !,"Throwing an exception!",! THROW myvar QUIT } CATCH { WRITE "Catch taken" } QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP1() Catch taken ``` 但是,`try`块可以调用设置和使用`$ZTRAP`的代码。在下面的示例中,`$ZTRAP`而不是`CATCH`块捕获被零除错误: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP2() ClassMethod ZTRAP2() { TRY { DO Errsub } CATCH { WRITE "Catch taken" } QUIT Errsub SET $ZTRAP="Ztrap" WRITE 1/0 /* divide-by-zero error */ QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP2() $ZTRAP taken ``` CATCH块中的`Throw`命令还可以调用`$ZTRAP`错误处理程序。 # 示例 下面的示例将`$ZTRAP`设置为此程序中的`OnError`例程。然后,它调用发生错误的`Suba`(尝试将数字除以0)。当错误发生时,InterSystems IRIS调用`$ZTRAP`中指定的`OnError`例程。`OnError`在设置`$ZTRAP`的上下文级别调用。因为`OnError`与`Main`处于相同的上下文级别,所以执行不会返回`Main`。 ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP3() ClassMethod ZTRAP3() { Main NEW $ESTACK SET $ZTRAP="OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP WRITE !,"Main $ESTACK= ",$ESTACK // 0 WRITE !,"Main $ECODE= ",$ECODE DO SubA WRITE !,"Returned from SubA" // not executed WRITE !,"MainReturn $ECODE= ",$ECODE QUIT SubA WRITE !,"SubA $ESTACK= ",$ESTACK // 1 WRITE !,6/0 // Error: division by zero WRITE !,"fine with me" QUIT OnError WRITE !,"OnError $ESTACK= ",$ESTACK // 0 WRITE !,"$ECODE= ",$ECODE QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP3() $ZTRAP set to: +970^PHA.TEST.SpecialVariables.1 Main $ESTACK= 0 Main $ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9, SubA $ESTACK= 1 OnError $ESTACK= 0 $ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9,M9, ``` 下面的示例与前面的示例相同,但有一个例外:`$ZTRAP`位置前面有一个星号(`*`)。当错误发生在`SUBA`中时,此星号会导致InterSystems IRIS在`SUBA`(发生错误的地方)的上下文级调用`OnError`例程,而不是在`Main`(设置`$ZTRAP`的地方)的上下文级调用`OnError`例程。因此,当`OnError`完成时,执行将在`do`命令之后的行返回到`Main`。 ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP4() ClassMethod ZTRAP4() { Main NEW $ESTACK SET $ZTRAP="*OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP WRITE !,"Main $ESTACK= ",$ESTACK // 0 WRITE !,"Main $ECODE= ",$ECODE DO SubA WRITE !,"Returned from SubA" // executed WRITE !,"MainReturn $ECODE= ",$ECODE QUIT SubA WRITE !,"SubA $ESTACK= ",$ESTACK // 1 WRITE !,6/0 // Error: division by zero WRITE !,"fine with me" QUIT OnError WRITE !,"OnError $ESTACK= ",$ESTACK // 1 WRITE !,"$ECODE= ",$ECODE QUIT } ```
文章
姚 鑫 · 三月 15, 2021

第十章 SQL排序(二)

# 第十章 SQL排序(二) # 查询排序 InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。 # 第十章 SQL排序(二) # 查询排序 InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。 ## 查询明细排序 将排序功能应用于查询选择项会更改该项目的显示。 - 字母大小写:默认情况下,查询显示带有大写和小写字母的字符串。例外情况是对排序规则类型`SQLUPPER`的字段进行`DISTINCT`或`GROUP BY`操作。这些操作以所有大写字母显示该字段。可以使用`%EXACT`排序功能来反转此字母大小写转换,并以大写和小写字母显示该字段。不应在选择项列表中使用`%SQLUPPER`排序规则函数以所有大写字母显示字段。**这是因为`%SQLUPPER`在字符串的长度上添加了一个空格字符。请改用`UPPER`函数:** ```SQL SELECT TOP 5 Name,$LENGTH(Name) AS NLen, %SQLUPPER(Name) AS UpCollN,$LENGTH(%SQLUPPER(Name)) AS UpCollLen, UPPER(Name) AS UpN,$LENGTH(UPPER(Name)) AS UpLen FROM Sample.Person ``` ![image](/sites/default/files/inline/images/1_26.png) - 字符串截断:可以使用`%TRUNCATE`排序函数来限制显示的字符串数据的长度。 `%TRUNCATE`比`%SQLUPPER`更可取,后者会在字符串的长度上添加一个空格字符。 ```SQL SELECT TOP 5 Name,$LENGTH(Name) AS NLen, %TRUNCATE(Name,8) AS TruncN,$LENGTH(%TRUNCATE(Name,8)) AS TruncLen FROM Sample.Person ``` ![image](/sites/default/files/inline/images/2_15.png) 请注意,不能嵌套排序规则函数或大小写转换函数。 - `WHERE`子句比较:大多数`WHERE`子句谓词条件比较使用字段/属性的排序规则类型。因为字符串字段默认为`SQLUPPER`,所以这些比较通常不区分大小写。可以使用`%EXACT`排序规则功能使它们区分大小写: - 下面的示例返回`Home_City`字符串匹配项,无论字母大小写如何: ```SQL SELECT Home_City FROM Sample.Person WHERE Home_City = 'albany' ``` ![image](/sites/default/files/inline/images/3_13.png) 以下示例返回区分大小写的`Home_City`字符串匹配: ```SQL SELECT Home_City FROM Sample.Person WHERE %EXACT(Home_City) = 'albany' ``` ![image](/sites/default/files/inline/images/4_9.png) `SQL Follows`运算符(`]`)使用字段/属性归类类型。 但是,无论字段/属性的排序规则类型如何,SQL `Contains`运算符(`[`)都使用EXACT排序规则: ```SQL SELECT Home_City FROM Sample.Person WHERE Home_City [ 'c' ORDER BY Home_City ``` ![image](/sites/default/files/inline/images/5_3.png) `%MATCHES`和`%PATTERN`谓词条件使用EXACT排序规则,而不管字段/属性的排序规则类型如何。 `%PATTERN`谓词提供区分大小写的通配符和不区分大小写的通配符(`'A'`)。 `ORDER BY`子句:`ORDER BY`子句使用名称空间默认排序规则对字符串值进行排序。因此,`ORDER BY`不会基于字母大小写进行排序。可以使用`%EXACT`排序规则根据字母大小写对字符串进行排序。 ## `DISTINCT`和`GROUP BY`排序规则 默认情况下,这些操作使用当前的名称空间排序。默认的名称空间排序规则是`SQLUPPER`。 - `DISTINCT`:`DISTINCT`关键字使用名称空间默认排序规则来消除重复值。因此,`DISTINCT Name`返回所有大写字母的值。可以使用`EXACT`排序规则返回大小写混合的值。 `DISTINCT`消除仅字母大小写不同的重复项。**要保留大小写不同的重复项,但要消除确切的重复项,请使用`EXACT`排序规则。** 以下示例消除了精确的重复项(但不消除字母大写的变体),并以混合的大写和小写形式返回所有值: ```SQL SELECT DISTINCT %EXACT(Name) FROM Sample.Person ``` ![image](/sites/default/files/inline/images/6_2.png) `UNION`涉及隐式`DISTINCT`操作。 - `GROUP BY`:`GROUP BY`子句使用名称空间默认排序规则来消除重复的值。因此,`GROUP BY Name`返回所有大写字母的值。**可以使用`EXACT`排序规则返回大小写混合的值。** `GROUP BY`消除仅字母大小写不同的重复项。若要保留大小写不同的重复项,但要消除完全相同的重复项,必须在`GROUP BY`子句(而不是`select-item`)上指定`%EXACT`归类函数。 下面的示例返回大小写混合的值; `GROUP BY`消除重复项,包括字母大小写不同的重复项: ```SQL SELECT %EXACT(Name) FROM Sample.Person GROUP BY Name ``` ![image](/sites/default/files/inline/images/7_0.png) 下面的示例返回大小写混合的值; `GROUP BY`消除了精确的重复项(但不消除字母大写的变体): ```SQL SELECT Name FROM Sample.Person GROUP BY %EXACT(Name) ``` ![image](/sites/default/files/inline/images/8_1.png) # 旧版排序类型 InterSystems SQL支持多种旧式排序规则类型。它们已被弃用,不建议与新代码一起使用,因为它们的目的是为遗留系统提供持续的支持。他们是: - **`%ALPHAUP` — 除去问号(`“?”`)和逗号(`“,”`)之外的所有标点符号,并将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。** - **`%STRING` —将逻辑值转换为大写,去除所有标点符号和空格(逗号除外),并在字符串的开头添加一个前导空格。它将所有仅包含空格(空格,制表符等)的值作为SQL空字符串进行整理。由`SQLUPPER`代替。** - **`%UPPER` —将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。** - `SPACE` — `SPACE`排序将单个前导空格附加到一个值,强制将其作为字符串求值。要建立`SPACE`排序规则,`CREATE TABL`E提供一个`SPACE`排序规则关键字,而ObjectScript在`%SYSTEM.Util`类的`Collation()`方法中提供一个`SPACE`选项。没有相应的SQL排序规则功能。 **注意:如果使用`EXACT`,`UPPER`或`ALPHAUP`排序定义了字符串数据类型字段,并且查询在此字段上应用了`%STARTSWITH`条件,则可能导致不一致的行为。如果指定给`%STARTSWITH`的子字符串是规范数字(尤其是负数和/或小数),则`%STARTSWITH`可能会根据字段是否被索引而给出不同的结果。如果未对列进行索引,则`%STARTSWITH`应该会按预期执行。如果该列已建立索引,则可能会发生意外的结果。** # SQL和NLS排序 上面描述的SQL排序规则不应与InterSystems IRIS NLS排序规则功能混淆,后者提供符合特定本国语言排序规则要求的下标级别编码。这是提供分页的两个独立系统,它们在产品的不同级别上工作。 InterSystems IRIS NLS排序可以具有当前过程的过程级别排序,并且可以具有特定全局变量的不同排序。 为了确保使用InterSystems SQL时的正常运行,要求进程级NLS排序规则与所涉及的所有全局变量的NLS排序规则完全匹配,包括表所使用的全局变量以及用于临时文件(例如进程专用全局变量和IRIS TEMP)的全局变量。否则,查询处理器设计的不同处理计划可能会得出不同的结果。在发生排序的情况下,例如`ORDER BY`子句或范围条件,查询处理器将选择最有效的排序策略。它可以使用索引,可以在进程专用的全局文件中使用临时文件,可以在本地数组中排序,也可以使用`“]]”`(之后排序)比较。所有这些都是下标类型的比较,遵循有效的InterSystems IRIS NLS归类,这就是为什么所有这些类型的全局变量都必须使用完全相同的NLS归类的原因。 系统使用数据库默认排序规则创建全局变量。可以使用`%Library.GlobalEdit`类的`Create()`方法来创建具有不同排序规则的全局变量。唯一的要求是指定的归类可以是内置的(例如InterSystems IRIS标准),也可以是当前语言环境中可用的国家归类之一。
公告
Jeff Liu · 三月 30, 2022

2022年3月开发者社区更新

大家好,欢迎来到2022年3月开发者社区更新! 我们最近在InterSystems社区对开发者们的体验做了一些改进: 全新的社区内容搜索功能 综合社区数据 链接你的脸书账号 帖子页面更新:标签、作者块、草稿突出显示 下面让我们仔细看看。 社区搜 我们已经在社区网站上部署了一个全新的搜索引擎。有两个搜索选项: 快速搜索 高级搜索 通过DC快速搜索,你可以很容易地找到一个帖子/标签/用户并直接进入该网页。 在建议的选项中没有找到合适的东西? 试着通过点击🔍按钮使用DC高级搜索: 在这里,你可以轻松地为你的搜索查询添加高级参数: 按特定用户的帖子搜索 通过特定标签搜索 按特定的帖子类型或只按你的帖子搜索 你还可以按时间段和相关性对结果进行排序: 综合社区数据 现在你可以看到InterSystems开发社区的数据统计了: 链接你的脸书账号 在你的DC资料中添加Facebook链接,以认识新朋友,拉近彼此的距离。 进入你的DC用户资料-->编辑-->其他信息-->Facebook资料 帖子页面更新:标签、作者块、草稿突出显示 你问了 - 我们做到了! 现在DC标签出现在帖子的正文中。 另外,在帖子页面,你现在可以在右边的块中看到作者的联系信息: DC网站上的草稿现在是蓝色突出显示: 希望你喜欢我们的更新 在DC GitHub上提交您的改进请求和错误报告。或者在本帖的评论中发表您的建议。 请继续关注!
公告
Claire Zheng · 一月 10, 2023

欢迎中文社区新版主@牛宇翔

亲爱的社区开发者们, 我很高兴地向大家介绍一位我们的新版主 @牛宇翔! @牛宇翔 目前担任首都医科大学附属北京友谊医院信息中心临床组组长。 以下是@牛宇翔 的自我介绍: 本人有接近10年的医疗信息化经验,目前在我院,带领一个微型小团队,基于Ensemble数据库做医院信息系统(Hospital Information System, HIS)应用端研发,我们团队熟悉HTML、CSS、JavaScript及衍生前端语言,日常工作主要根据用户需求开发对应功能,结合临床业务难点痛点,不断优化程序功能。经过两年的学习和努力,我们团队已完成临床新增功能和优化需求共计一千余条,随着科室人力的发展,我们的开发力量会越来越强,可以更好地保证临床需求的及时响应,不断优化和完善系统BUG,提高临床工作效率。与此同时,我还担任应急小组成员,负责进行数据库运维和问题处理,保证第一时间排查故障。 InterSystems 提供了一个非常优秀的集成平台,借助该技术,给我们业务带来了非常大的便利。我也希望这么优秀的技术,能给更多的兄弟单位和合作伙伴创造价值。我也希望能够在社区与大家一起交流,分享自己的一些实践经验;同时也希望借助这个平台,向大家学习一些优秀的实践。我们一起成长,共同进步! 再次欢迎我们的新版主 @牛宇翔👏🏼👏🏼👏🏼👏🏼👏🏼 期待你在InterSystems开发者社区成长为一名优秀版主! 热烈欢迎!期待更多大作!@牛宇翔
文章
姚 鑫 · 五月 3, 2021

第二章 全局变量结构(一)

# 第二章 全局变量结构(一) 本章描述全局变量的逻辑视图,并概述全局变量是如何在磁盘上物理存储的。 # 全局变量的逻辑结构 全局变量是存储在物理InterSystems IRIS®数据库中的命名多维数组。 在应用程序中,全局变量到物理数据库的映射基于当前名称空间——名称空间提供一个或多个物理数据库的逻辑统一视图。 ## 全局命名约定和限制 全局名称指定其目标和用途。有两种类型的全局变量和一组单独的变量,称为“进程私有全局变量”: - 全局变量 - 这就是所谓的标准全局变量;通常,这些变量被简称为全局变量。它是驻留在当前命名空间中的永久性多维数组。 - **扩展全局引用-这是位于当前命名空间以外的命名空间中的全局引用。** - **进程私有全局变量-这是一个数组变量,只有创建它的进程才能访问。** 全局变量的命名约定如下: - 全局变量名称以脱字符(`^`)前缀开头。这个插入符号区分全局变量和局部变量。 - 全局变量名称中脱字符(`^`)前缀后的第一个字符可以是: - 字母或百分号字符(%)-仅适用于标准全局变量。对于全局变量名称,字母被定义为`ASCII 65`到`ASCII 255`范围内的字母字符。如果全局名称以`“%”`开头(但不是`“%Z”`或`“%z”`),则此全局名称供InterSystems IRIS系统使用。`%GLOBAL`通常存储在IRISSYS或IRISLIB数据库中。 - 竖线(`|`)或左方括号(`[`)-表示扩展全局引用或进程专用全局变量。使用取决于后续字符。 - 全局变量名称的其他字符可以是字母、数字或句号(`.`)字符。 百分比(`%`)字符不能使用,除非作为全局名称的第一个字符。 `“.”`字符不能作为全局名称的最后一个字符。 - **全局名称最长可达31个字符(不包括脱字符前缀)。可以指定更长的全局名称,但InterSystems IRIS只将前31个字符视为重要字符。** - 全局名称区分大小写。 - InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。 **在IRISSYS数据库中,InterSystems将除以`“z”`、`“Z”`、`“%z”`和`“%Z”`开头的所有全局变量名称保留给自己。在所有其他数据库中,InterSystems保留所有以`“ISC”`开头的全局名称。和`“%isc.”`。** ## 示例全局名称及其用法 以下是各种全局名称的示例以及每种名称的用法: - `^globalname` - 标准全局变量 - `^|"environment"|globalname` - 扩展全局变量引用的环境语法 - `^||globalname` - 进程私有全局变量 - `^|"^"|` - 进程私有全局变量 - `^[namespace]globalname` - 扩展全局变量引用中显式命名空间的括号语法 - `^[directory,system]globalname` - 扩展全局变量引用中隐含命名空间的括号语法 - `^["^"]globalname` - 进程私有全局变量 - `^["^",""]globalname` - 进程私有全局变量 注意:全局名称只能包含有效的标识符字符;默认情况下,这些字符如上所述。但是,NLS(国家语言支持)定义了一组不同的有效标识符字符集。全局名称不能包含`Unicode`字符。 因此,以下都是有效的全局名称: ```java SET ^a="The quick " SET ^A="brown fox " SET ^A7="jumped over " SET ^A.7="the lazy " SET ^A1B2C3="dog's back." WRITE ^a,^A,^A7,!,^A.7,^A1B2C3 KILL ^a,^A,^A7,^A.7,^A1B2C3 // keeps the database clean ``` ## 全局节点和下标简介 全局通常有多个节点,通常由一个下标或一组下标标识。下面是一个基本示例: ```java set ^Demo(1)="Cleopatra" ``` 此语句引用全局节点`^Demo(1)`,它是`^Demo`全局节点中的一个节点。此节点由一个下标标识。 再举一个例子: ```java set ^Demo("subscript1","subscript2","subscript3")=12 ``` 该语句指的是全局节点`^Demo("subscript1","subscript2","subscript3")`,它是同一全局中的另一个节点。此节点由三个下标标识。 再举一个例子: ```java set ^Demo="hello world" ``` 该语句引用不使用任何下标的全局节点`^Demo`。 全局的节点形成分层结构。ObjectScript提供了利用此结构的命令。例如,可以删除节点或删除节点及其所有子节点。 ## 全局变量下标 下标有以下规则: - 下标数值区分大小写。 - **下标值可以是任何ObjectScript表达式,前提是该表达式的计算结果不是空字符串(`""`)。** **该值可以包括所有类型的字符,包括空格、非打印字符和Unicode字符。(请注意,非打印字符在下标数值中不太实用。)** - 在解析全局引用之前,InterSystems IRIS计算每个下标的方式与计算任何其他表达式的方式相同。在下面的示例中,我们设置了`^Demo`全局的一个节点,然后以几种等效的方式引用该节点: ```java DHC-APP>s ^Demo(1+2+3)="a value" DHC-APP>w ^Demo(3+3) a value DHC-APP>w ^Demo(03+03) a value DHC-APP>w ^Demo(03.0+03.0) a value DHC-APP>set x=6 DHC-APP>w ^Demo(x) a value ``` - InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。 **注意:上述规则适用于IRIS支持的所有排序规则。对于出于兼容性原因仍在使用的旧归类,如`“pre-ISM-6.1”`,下标的规则有更多限制。例如,字符下标不能以控制字符作为其初始字符;整数下标中可以使用的位数也有限制。** ## 全局变量节点 在应用程序中,节点通常包含以下类型的结构: 1. 字符串或数字数据,包括本机`Unicode`字符。 2. 具有由特殊字符分隔的多个字段的字符串: ```java SET ^Data(10) = "Smith^John^Boston" ``` 可以使用ObjectScript `$PIECE` 函数来拆分这些数据。 3. InterSystems IRIS `$LIST` 结构中包含多个字段。`$LIST`结构是包含多个长度编码值的字符串。它不需要特殊的分隔符。 4. 空字符串 (`""`)。在下标本身用作数据的情况下,实际节点中不存储任何数据。 5. 一个位串。如果全局变量用于存储位图索引的一部分,那么存储在节点中的值就是位字符串。位串是包含`1`和`0`值的逻辑压缩集的字符串。可以使用`$BIT`函数构造位串。 6. 更大的数据集的一部分。例如,对象和SQL引擎将流(`BLOB`)存储为全局中连续的`32K`节点系列。通过流接口,流的用户不知道流是以这种方式存储的。 请注意,任何全局节点都不能包含长度超过字符串长度限制的字符串,字符串长度限制非常长。 ## 全局变量排序规则 在全局中,节点按排序(排序)顺序存储。 **应用程序通常通过将转换应用于用作下标的值来控制节点的排序顺序。例如,SQL引擎在为字符串值创建索引时,会将所有字符串值转换为大写字母,并在前面加上一个空格字符,以确保索引不区分大小写并且以文本形式排序(即使数值存储为字符串)。** # 全局变量引用的最大长度 **全局变量引用(即对特定全局节点或子树的引用)的总长度限制为`511`个编码字符(少于`511`个键入字符)。** 要保守地确定给定全局变量引用的大小,请使用以下准则: 1. 全局变量名称:每个字符加`1`。 2. 对于纯数字下标:每个数字、符号或小数点加`1`。 3. 对于包含非数字字符的下标:为每个字符添加`3`。 如果下标不是纯数字的,则根据用于编码字符串的字符集的不同,下标的实际长度会有所不同。一个多字节字符最多可以占用`3`个字节。 请注意,ASCII字符可能占用`1`或`2`字节。 如果排序规则进行大小写折叠,那么`ASCII`字符可以使用`1`个字节表示字符,`1`个字节表示消除歧义字节。 如果排序不执行大小写折叠,`ASCII`字符占用`1`字节。 4. 每个下标加`1`。 如果这些数字的总和大于`511`,则引用太长。 由于确定限制的方式,如果必须使用长下标或全局名称,这有助于避免使用大量下标级别。 相反,如果使用多个下标级别,则应避免长全局名称和长下标。 因为无法控制正在使用的字符集,所以保持全局名称和下标更短是很有用的。 当对特定引用有疑问时,创建与最长预期全局变量引用长度相等(甚至稍长一点)的全局变量引用的测试版本是有用的。 这些测试的数据为构建应用程序之前可能修订的命名约定提供了指导。