2. FHIR术语资源全景

FHIR的术语能力不是由单一资源承担的,而是由一组职责清晰、彼此引用的资源共同构成。理解这套资源全景,关键不是背下每个资源的字段,而是弄清“谁定义编码、谁挑选编码、谁翻译编码、谁声明服务能力、谁登记系统身份”这五件事分别落在哪个资源上。下面按数据流方向逐一展开。

CodeSystem:编码的“定义源”

CodeSystem(代码系统)回答的是“这个编码体系里有哪些概念”。它由 url 唯一标识,content 字段声明内容完整度:complete 表示本资源包含全部概念,fragment 表示只含部分,not-present 表示只声明系统存在而不列出概念。每个概念用 concept.code 和 concept.display 表达,层级通过嵌套 concept 实现。

例如一个院内检验项目代码系统,可以这样声明:

{
  "resourceType": "CodeSystem",
  "url": "http://hospital.example.org/CodeSystem/lab-items",
  "version": "2024.1",
  "content": "complete",
  "concept": [
    { "code": "WBC", "display": "白细胞计数" },
    { "code": "HGB", "display": "血红蛋白" },
    { "code": "PLT", "display": "血小板计数" }
  ]
}

注意 content 的选择直接影响后续校验:若标为 complete,则任何不在列表中的编码都应被判为无效;若标为 fragment,校验器就不能据此否定未知编码。这是工程中最容易出错的地方之一。

ValueSet:编码的“选择集”

ValueSet(值集)回答的是“在某个具体场景下,允许用哪些编码”。它不重新定义概念,而是通过 compose 从 CodeSystem 中挑选。挑选方式有两类:include 显式列出或按过滤器引入,exclude 排除。过滤器用 filter.property、filter.op、filter.value 表达,例如只取某层级下的子概念。

{
  "resourceType": "ValueSet",
  "url": "http://hospital.example.org/ValueSet/orderable-lab",
  "compose": {
    "include": [{
      "system": "http://hospital.example.org/CodeSystem/lab-items",
      "concept": [{ "code": "WBC" }, { "code": "HGB" }]
    }]
  }
}

ValueSet 的 expansion 是“展开结果”,即把 include/exclude 和过滤器实际计算后得到的编码清单。工程上要区分“逻辑定义”和“展开快照”:前者随源 CodeSystem 变化而变化,后者是某一时刻的固定结果,适合做审计和离线校验。

ConceptMap:编码之间的“翻译桥”

ConceptMap(概念映射)回答的是“A系统的编码对应B系统的哪个编码”。它由 sourceUri/targetUri 或 sourceScope/targetScope 声明两端,用 group.element.target 表达映射,equivalence 描述等价程度,如 equivalent、wider、narrower、relatedto。这个字段非常关键:equivalent 才能用于自动替换,wider/narrower 只能提示人工复核。

{
  "resourceType": "ConceptMap",
  "sourceScopeUri": "http://hospital.example.org/CodeSystem/lab-items",
  "targetScopeUri": "http://loinc.org",
  "group": [{
    "source": "http://hospital.example.org/CodeSystem/lab-items",
    "target": "http://loinc.org",
    "element": [{
      "code": "WBC",
      "target": [{ "code": "6690-2", "equivalence": "equivalent" }]
    }]
  }]
}

TerminologyCapabilities:服务能力的“自述”

TerminologyCapabilities 回答的是“这个术语服务器支持哪些操作、哪些系统、哪些参数”。它声明 codeSystem 列表、是否支持 $expand、$validate-code、$lookup、$translate,以及分页、批量等能力。客户端在集成前应先读取它,避免调用服务器未实现的操作。

NamingSystem:系统身份的“登记簿”

NamingSystem 回答的是“某个标识系统的规范身份是什么”。它用 uniqueId 记录不同形式的标识(如 uri、oid、uuid),并声明 kind(codesystem、identifier、root)和 status。当同一套编码在不同系统中以 OID 和 URL 两种形式出现时,NamingSystem 提供权威对应关系,避免“同物异名”。

五类资源的相互关系

把五者串起来看:NamingSystem 登记系统身份,CodeSystem 定义概念,ValueSet 从 CodeSystem 中挑选可用编码,ConceptMap 在 CodeSystem 之间建立翻译,TerminologyCapabilities 声明服务器对上述资源的操作能力。它们不是并列的五个盒子,而是一条从“身份—定义—选择—翻译—服务”的依赖链。

FHIR 术语资源依赖链 身份 → 定义 → 选择 → 翻译 → 服务能力 NamingSystem 登记系统身份 uri / oid / uuid kind · status CodeSystem 定义概念集合 url · content concept.code / display ValueSet 场景可用编码选择集 compose.include / exclude expansion 展开快照 ConceptMap 跨系统编码翻译 source / target equivalence 等价程度 TerminologyCapabilities 服务器术语能力自述 $expand · $validate-code $lookup · $translate 标识 挑选 映射源 翻译能力 操作对象 校验链:ValueSet 展开 → 取 CodeSystem 概念 → 若跨系统则查 ConceptMap → 由 TerminologyCapabilities 确认服务器支持该操作 身份链:NamingSystem 保证同一系统在 OID / URL / UUID 下指向同一 CodeSystem,避免重复定义

工程落地时的三个判断点

第一,content 完整度决定校验强度。若 CodeSystem 标为 complete,ValueSet 展开和 $validate-code 才能给出确定的“无效”结论;标为 fragment 时只能返回“未找到”,不能断言无效。

第二,equivalence 决定能否自动转换。只有 equivalent 适合在接口层自动替换编码;wider、narrower、relatedto 必须进入人工复核队列,否则会造成语义漂移。

第三,先读 TerminologyCapabilities 再调用。例如服务器未声明支持 $translate,客户端就不应把 ConceptMap 翻译作为在线依赖,而应改为本地映射表或离线批处理。

建议在集成前先做一次“资源清点”:列出本系统涉及的 CodeSystem URL、对应 ValueSet、需要的 ConceptMap,以及目标服务器 TerminologyCapabilities 中声明的操作集合。这份清单能直接暴露“定义了但没选、选了但没映射、映射了但服务器不支持”三类缺口。