FHIR Terminology Service

来自HL7ChinaWiki
跳转至: 导航搜索

本页面内容是一份草案,并且打算编入FHIR技术规范的第二次试行版(DSTU 2)。

引言

FHIR技术规范之中包括了对于提供利用方层次的术语服务(consumer level terminology service)的支持。其中,提供了下列功能/工具(facilities)

本页面描述的是如何提供这些用于支持服务器和客户端的服务。支持所有在此所描述的功能性的服务器,即可被称为“FHIR术语服务(FHIR Terminology Service)”,并且必须遵循[这份符合性声明(conformance_statement)——链接待提供]。

注释符合性声明(遵从性声明、符合声明、遵从声明):是一套对于所期望的实施(实施项目、实施形式、实施工作)的要求,或者是关于特定的目标应用程序在特定实施(实施项目、实施形式、实施工作)当中对于这些要求的符合程度的描述。
A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation.
原始定义来源FHIR符合性声明资源conformance.xsd

安全性

对于这些操作服务(operational service,业务服务),OAuth一般来说并不是适合于术语服务器(terminology server)之类基础结构服务(infrastructural service)安全性(security)的恰当形式。术语服务器可以选择不采用任何方式对客户端进行身份验证;但是,为了限制使用或者说对使用情况负责,也可以进行身份验证。术语服务器并不直接处理具体患者的信息,因而没有必要采用SSL去保护相应的通讯,但黑客却可能能够通过观察所获取到代码的种类,来推断关于患者的信息。因此,加密可能依然是个好主意,并且可能采用的是客户端证书验证

对于取值集合维护服务器(value set maintenance server),OAuth则可能是合适的选择,或者,也可能会采取其他某种登录方法。

代码系统与取值集合

FHIR技术规范的基础之中包括两个关键的概念:

  • 代码系统(code system) - 用于定义一套带有相应含义的代码(又称为“枚举<enumeration,列举,枚举列表>”、“术语集<terminology,术语系统,术语标准>”、“分类系统<classification,分类>”、“本体<ontology,本体论>”)
  • 取值集合(value set) - 是从一部或多部代码系统所定义的代码之中所挑选出来的一套代码

注释

代码系统与取值集合之间的正确区分是件重要的事情。例如,由一套LOINC代码与另外一些自编代码所组成的混合式代码列表,而且对这两种代码也不加以明确区分,这种情况并不罕见;然而,事实上,其中那些看似LOINC代码的代码却违背了原本LOINC的规则。

另一方面,在FHIR之中,定义代码的每部代码系统分别都有着各自的一条URL,并且它们所定义的代码都是一个“代码对(Code Pair)”,即名称+命名空间。这样一来,对于上述例子,就有了两部代码系统:LOINC (http://loinc.org) 和本地代码系统(如http://example.com/codesystems/additional-test-codes)。这时,也就有了一部取值集合,即一套代码对;其中,所收录的代码分别来自于这两个命名空间(分别代表着上述的代码系统)。同时,该取值集合本身也获得了一条作为其标识符的URL(如http://example.com/fhir/ValueSet/test-codes)——用于标识这套代码对;但是,并不能将该标识符作为上述参与组成代码对的命名空间来使用。

在FHIR之中,代码对始终被表示为"代码"加上相应"代码系统"的形式(文中又称为“code+system”),除非是对于一种FHIR简单类型——代码型数据类型"code"。对于代码型数据类型"code",其命名空间在相应的Schema之中已是固定的,在代码对之中并不加以明确表示。系统元素system之中的URL始终引用的是特定的代码系统,而不是引用取值集合。

希望进一步了解基本原则的用户可以参阅[核心原则(链接待提供)]。

FHIR取值集合资源ValueSet

FHIR技术规范之中定义了单独一种称为“ValueSet”(取值集合)的资源。取值集合旨在用于定义特定的一套代码对。取值集合资源ValueSet之中可以收录他处所定义的代码对

  • 导入(import)若干套分别来自于其他取值集合的代码对
  • 通过罗列(枚举)来自于若干部代码系统的相应代码,将这些代码包括(include)进来(即所谓的“外延型定义<extensional definition>”)
  • 利用相应代码系统之中的相关属性(properties),将来自于若干部代码系统的相应代码包括(include)进来(即所谓的“内涵型定义<intensional definition>”)

此外,取值集合还可以自行定义其自己的代码系统。对于这种嵌入式代码系统(inline code system)之中所定义的代码,也将采用该取值集合之中所明确赋予该代码系统的URL,把相应的代码收录到该取值集合当中。

对于术语服务器来说,取值集合资源属于基础性的构件——术语服务器将负责管理取值集合的存储库,允许特定用户编辑取值集合,并且依据这些取值集合之中的定义来提供服务。

外部代码系统

为了采取取值集合的方式来使用代码,必须首先在某个地方对代码加以定义。可以将代码作为嵌入式代码系统定义的组成部分来加以定义,或者也可以在他处(在其他代码系统之中)进行定义;接下来,就可以通过正确引用相应代码系统的命名空间,在某部取值集合当中使用相应的代码。FHIR为常见的那些代码系统定义了一套命名空间(参见这里),并且还规定了其中一些代码系统应当(如SNOMED CT、LOINC、RxNorm)如何与FHIR配合使用(链接待提供)。这些代码系统往往规模较为庞大,并且还备有许多内部所定义的,参与构建概念的形式化定义(formal definition)的属性(properties)。嵌入式代码系统不适合于此类代码系统。对此,FHIR技术规范并未提供任何的形式化表达方法(formal representation)。不过,FHIR技术规范假设这些属性和形式化定义在其外部都是已知的东西。

大多数术语服务器将会提供一部或多部这些外部代码系统,以便在其所管理的那些取值集合内部能够利用这些代码系统。除了此类取值集合之中所定义的那些代码系统之外,用于向客户端发布特定术语服务器所支持的其他术语集的列表的工作机制还有待确定

实施注释

当特定术语服务器公开某部外部代码系统时,它将会在其内部提供一套可用的服务,用来服务于如下相应的操作接口(operational interfaces) 。内部服务器依赖于下列关于特定术语集的逻辑声明(logical statement)

  • 外部代码系统的URL(命名空间以及如何进行版本控制)
  • 哪些代码是有效的
  • 哪些属性(properties)可用于选择或者说筛选代码
  • 究竟存在哪些隐含式的取值集合(implicit value sets)

FHIR技术规范本身已经为一些著名的外部代码系统(如SNOMED CT、LOINC、RxNorm)[链接待提供]定义了这些方面。

注释: 更为广义/通用的术语服务(terminology service)可以选择提供外部代码系统所特有的相关功能, 如术语集探索(exploration,导航)或结构化搜索(structured search), 但此类服务超出了FHIR术语服务的范围。

概念映射

除了上述的取值集合,有助于FHIR术语服务的另一种FHIR资源就是概念映射(concept map)。概念映射能够对两种结构或两部取值集合进行转换(translation);不过,只有取值集合之间的转换才与术语服务器相关。概念映射负责将一部取值集合映射(map)到另一部取值集合。请注意,映射关系(mappings)是单向的——即从来源代码系统(source code system)到目标代码系统(destination/target code system),而且,只能在既定的来源代码系统和目标代码系统的语境下定义相应的映射关系。这些映射关系在其他语境下也可能会有用,但这必须依据相应的应用语境(context of use)和含义来确定;不能自动地将认为是理所当然的事情。在每条从来源到目标的映射关系之中,还包括有一个称为“概念等价性(equivalence)”的属性(用于说明所映射双方的相似程度);或者,在某些情况下,根本不存在任何有效的映射关系。

术语服务器可以利用概念映射来补充和加强借助于取值集合和那些内部已知的术语集所提供的信息。

术语集维护

FHIR术语服务将利用其系统上所定义的那些取值集合资源——既包括那些与外部代码系统相关联的隐含式取值集合(implicit value sets),也包括/ValueSet端点上明确现成可用的那些取值集合。所有这些取值集合资源均用于满足如下所定义的那些操作接口(operational interfaces) 。随着取值集合的创建、更新或删除,这些操作服务的结果也会发生相应的变化。术语服务器应当验证入站资源(incoming resources),并保证各项术语服务的完整性(integrity)。通常情况下,服务器都会提供测试环境和生产环境,但在接口本身当中,并没有关于这方面的明确概念。

取值集合展开形式

如上所述,每个取值集合分别描述的都是一套关于认为哪些代码或概念应收录在该取值集合之中的规则。这些规则既可能会非常简单——即直接罗列若干的代码,或者,也可能会相当复杂。FHIR客户端(或其他过程)则可以只是要求FHIR服务器自己去计算处理特定取值集合的所有细节,并由此为其提供一张该取值集合之中现行代码的列表。这一过程就是所谓的取值集合的“展开(expanding)”,而最终所获得的那张现行代码列表则被称为取值集合的“展开形式(expansion,展开式)”或者说“展开型取值集合(expanded value set)”。为此,FHIR客户端需要向FHIR服务器发送下列信息:

  • 特定取值集合的标识(identity)(或者,也可以直接传送该取值集合
  • 用于限制所要返回代码的文本型筛选条件(text filter)(如用户所输入的文字)
  • 所应当产生的展开形式的日期(date)(通常为当前日期/时间,但在某些情况下,可能并不适合采用当前日期/时间)

最终,FHIR服务器返回的将是一部其中含有相应现行代码列表的取值集合,或者是带有某种错误的操作结果(Operation Outcome)。请注意 :某些取值集合会展开出成千上万条,甚至是无穷多的代码;对于此类取值集合,FHIR服务器则会返回错误代码“too-costly”(系统资源耗费过大)。在此类情况下,客户端则可以采用更为具体的文本型筛选条件再行尝试。

如下是关于取值集合展开操作的一些用途示例:

  • 获取一张用于在某个用户界面当中显示的代码列表(如界面当中的下拉式选项列表)
  • 上述用途的一个变化形式就是,提供一个可让用户键入的文本框。随着用户的键入,立刻调用展开操作,随即为用户提供一张由匹配代码/概念所组成的代码列表(类似于及时提示式的浏览器搜索功能)
  • 获取一张供生成软件程序代码时使用的代码列表
  • 获取一张代码列表,以便特定软件能够在特定语境下检查特定代码是否有效

取值集合验证

如上所述,确定某条代码是否在特定取值集合之中(或者说,该代码是否为该取值集合的成员)的方法之一就是,将该取值集合展开,并检查该代码是否在其展开形式之中。不过,这并不是确定代码相对于特定取值集合是否有效的有效方法;并且,对于某些取值集合来说,这种方法也是行不通的。对此,FHIR术语服务器则提供有一项“验证(validate)”操作,而FHIR客户端可以利用如下2个参数来调用该操作:

  • 相应的取值集合(或者是采用它在接口上的URL,或者是采用其逻辑标识符<logical identifier>,或者是作为调用的一个参数
  • 相应的代码取值(或者是取值为code+system,或者是FHIR编码型数据类型Coding的取值,或者是FHIR可编码概念型数据类型CodeableConcept的取值)

FHIR术语服务器返回的则是一个布尔值(true/false)(表示该代码/概念究竟是否有效)以及与之相关联的一系列错误和警告。作为验证操作的组成部分,服务器还应当返回与该代码相关联的所有显示名称(display names)。

请注意,如果向服务器所传送的是一个CodeableConcept型的取值,服务器将能够依据相应的取值集合来检查其中任何的那些代码是否有效,并且还会检查是否允许多个编码型条目(codings)和/或它们是否彼此相互一致(关于CodeableConcept,请参见这里)。

包摄关系测试

展开操作Expand和验证操作Validate可以一起用来完成包摄关系测试(subsumption testing,归类关系测试,包含关系测试,类属关系测试)。要测试代码A是否包摄代码B,首先利用代码A所包摄的所有代码建立一部具体的取值集合(即取值集合的展开),然后再验证代码A是否包摄代码B(即检查代码B是否属于是上述取值集合之中的有效代码)。请注意,在进行包摄关系测试时,允许服务器将概念映射(concept maps)考虑在内(它应当这么做,但并不做强制要求)。例如,假定代码A为一条LOINC代码,且它具有一条指向某条SNOMED CT代码的等价型映射关系,而该SNOMED CT代码又包摄代码B,那么,服务器就可以认为并表示代码A包摄代码B。

为了便于进行包摄关系测试,那些负责定义了包摄关系层级结构(subsumption heirarchies,归类关系层级结构,包含关系层级结构,类属关系层级结构)的代码系统则应当定义简单的URLs,用于表示那些其中收录的是某条代码所包摄的所有代码的取值集合。例如,对于SNOMED CT来说,URL http://snomed.info/sct?fhir_vs=isa/[sctid]就表示,该取值集合之中收录的是[sctid]所包摄的所有SNOMED CT代码。

转换

客户端可以要求FHIR服务器将某个概念从一部取值集合转换(translate)到另一部取值集合。通常,这用于不同代码系统之间的转换(如从LOINC到 SNOMED CT,或者从CDA代码到v2代码)。客户端利用下列3个参数来调用转换操作translate

  • 一个code+systemCoding(FHIR编码型取值)或CodeableConcept(FHIR可编码概念型取值)
  • 转换来源代码系统(source)语境下的相应取值集合
  • 转换目标代码系统(destination)语境下的相应取值集合

如果没有特定的语境,则合适的取值集合将是整个当前编码系统(coding system)的那些取值集合(比如,从代码系统命名空间 http://snomed.info/sct 到代码系统命名空间 http://loinc.org/vs)。

闭包表的维护

译者注:
闭包表(closure table,闭合表)是一种简单而又优雅的方法,用于在关系型数据库管理系统当中存储和查询层级结构式数据(hierarchical data)。这里,层级结构式数据指的是其中含有某种父子关系(parent – child relationship,上下级关系,层级结构式关系)的一套数据。通常,我们采用的是“树状结构(tree)”一词,而不是“层级结构(hierarchy)”。例如,在诸如“国家”、“省份(直辖市)/州别”、“城市或行政区”之类的地理位置之间,我们可能就会采用这种关系。 (详情可参见注释来源:采用闭包表存储层级结构式数据

展开Expand、验证Validate和转换Translate,这三项操作可以解决与术语集使用相关的大多数操作需求。然而,还有一种困难但又重要的用例却是它们所无法解决的,那就是将术语集逻辑(terminology logic,术语学逻辑,术语逻辑)集成到应用程序搜索(application search,应用搜索)当中。

举个典型的例子,现在有位用户希望找出那些符合下列条件的患者的任何观察结果:性别为男性,年龄大于50岁,在2周的特定时间段之内在特定门诊就过医,诊断中有痛风,并且曾经出现过血清肌酐增高。

在这个例子当中,“血清肌酐”和作为诊断的“痛风”都涉及到了包摄关系(比如,二者分别对应的是SNOMED CT和LOINC)。这项搜索的执行就不得不利用某种逻辑处理引擎(logical processing engine),而且后者要知道如何在特定的持久性存储(persistence store,持久存储层)当中找出相应的数据。尽管目前有许多其他现成的技术选项可用,但往往采用的还是某种SQL查询。然而,要完成这项工作,此类操作所面临的难题就是,要将术语集知识(terminological knowledge,术语学知识,术语知识)与搜索的执行集成起来。利用上述的展开操作,负责执行这种搜索的系统可以生成相应的展开形式,并继而对这些展开形式加以搜索。不过,这其中还存在着两个问题:

  • 被包摄代码所组成的列表可能会很长,因而搜索操作会相应地变得效率低下
  • 包摄关系(subsumption)的展开形式可能并不是闭包型(closed,闭合型),因而搜索操作不可能是正确的(或者说,不可能获得正确的执行结果)

另一种替代的方法就是,生成一张包摄关系闭包表,在其中列出所有的可能关系,从而便于快速执行此类查询。不过,这种方法又会碰到其他的问题:

  • 即便是仅仅使用代码系统之中很少的代码,这种包摄关系表(subsumption table)也可能会非常庞大(以SNOMED CT为例,可达>500,000条记录)
  • 包摄关系表一般都是提前构建好的,因而无法很好地处理新增代码
  • 此类包摄关系表依然无法为非闭包型(non-closed,非闭合型)展开形式提供解决方案

这就是之所以大多数系统不支持后组配(post-coordination,后组合)或其他形式的编码型表达式(coded expressions)的原因。

在FHIR技术规范之中,对于这个难题的解决办法就是,一旦发现新增代码,就在运行中随即(on the fly)构建闭包表。这种方法的思路就是,让FHIR术语服务器负责术语集推理(terminological reasoning,术语学推理),而让客户端来负责闭包表的维护。对于客户端来说,并不在乎相应的概念是否属于后组配型(post-coordinated,后组合型)。如下描述的是究竟如何进行这一过程:

  1. 客户端负责定义一个与特定语境(它希望在此语境下维护特定一张基于包摄关系的闭包表)相关联的名称
  2. 客户端利用闭包操作$closure(参见下文描述)向FHIR术语服务器注册该名称,并且其中仅仅采用了唯一一个参数,即上述语境的名称
  3. 每当客户端系统遇到一个新增的,尚未录入到相应闭包表之中的编码型取值Coding时,它就利用上述的语境名称以及它所碰到的那个编码型取值Coding,来调用闭包操作$closure
  4. FHIR术语服务器则会相应地返回一个带有一系列新增条目的概念映射资源ConceptMap(大体形式为code : system -> code : system),而客户端则应当将这些新增条目添加到其闭包表当中
    1. FHIR术语服务器还可以通过提供带有不匹配型等价性(equivalence "unmatched",不匹配型等价关系)的映射关系(大体形式为code : system -> code : system),表示应当从该闭包表当中删除相应的条目(尽管FHIR术语服务器实际上并不清楚为何要删除它们)
  5. 客户端将这些新增条目添加到其相应的闭包表当中,或者从其中删除相应的条目
  6. 为了促进相应的初始化过程,FHIR术语服务器还可以事先利用多个编码型取值(Coding values)来调用闭包操作$closure

闭包操作$closure采用如下2个参数:

  • 闭包表语境名称
  • 欲录入到闭包表之中的编码型取值(Coding value)(零个或多个——零个编码型取值表示请求初始化相应的闭包表)

闭包操作$closure返回的是一个概念映射资源ConceptMap,且其中的一系列映射关系代表的是要添加到相应闭包表当中的新增条目,或者是要从其中删除的相应条目。

通过额外提供一个版本参数(其取值取自于那些变更响应<delta responses,变更集响应>之一当中的相应版本),还可以对闭包表加以重新同步化。这也是一种请求,旨在重新发送(replay,重放)自从发送了相应变更集(delta)以来的所有映射关系变更。

参阅

外部链接