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 声明服务器对上述资源的操作能力。它们不是并列的五个盒子,而是一条从“身份—定义—选择—翻译—服务”的依赖链。
工程落地时的三个判断点
第一,content 完整度决定校验强度。若 CodeSystem 标为 complete,ValueSet 展开和 $validate-code 才能给出确定的“无效”结论;标为 fragment 时只能返回“未找到”,不能断言无效。
第二,equivalence 决定能否自动转换。只有 equivalent 适合在接口层自动替换编码;wider、narrower、relatedto 必须进入人工复核队列,否则会造成语义漂移。
第三,先读 TerminologyCapabilities 再调用。例如服务器未声明支持 $translate,客户端就不应把 ConceptMap 翻译作为在线依赖,而应改为本地映射表或离线批处理。