3. 编码系统与标识符工程
在FHIR中,编码系统不是“一个字段填个码”那么简单。任何一个 Coding 都由三要素构成:system(系统标识,通常是URI)、code(该系统内的码值)、display(人类可读显示名)。其中 system 是工程上最容易出错、也最需要统一治理的部分。本节聚焦五类高频系统——SNOMED CT、LOINC、ICD-10、RxNorm、UCUM——讲清它们的标识、版本、URI策略,以及在FHIR资源中的具体表达方式。
一、system 到底填什么:URI 是“系统身份”,不是“版本号”
FHIR规范要求 Coding.system 使用URI形式,且该URI标识的是“编码系统本身”,而不是某一次发布的版本。版本信息应放在 Coding.version 中。这是初学者最常见的混淆点:把版本号拼进 system,会导致同一系统在不同版本下产生多个“伪系统”,破坏术语映射与校验。
以SNOMED CT为例,其国际版系统URI为:
http://snomed.info/sct
如果要指定某个国家版本或某个具体版本,FHIR推荐使用“模块化URI”方式,把版本信息编码进URI路径,而不是塞进 version 字段之外的地方。例如指定2024年1月国际版:
http://snomed.info/sct/900000000000207008/version/20240131
其中 900000000000207008 是SNOMED CT国际版的模块标识。这种“基础URI + 模块 + 版本”的写法,是SNOMED CT在FHIR中最规范的表达策略。
二、五大系统的标识与URI策略对照
下表给出本节五个系统的标准 system 值、版本表达方式与典型码值示例。注意:ICD-10在不同国家有不同变体(如ICD-10-CM),其URI必须区分,不能混用。
| 系统 | 标准 system(URI) | 版本表达 | 码值示例 |
|---|---|---|---|
| SNOMED CT | http://snomed.info/sct | URI路径或 version 字段 | 73211009(糖尿病) |
| LOINC | http://loinc.org | version 字段,如 2.77 | 2339-0(血糖) |
| ICD-10 | http://hl7.org/fhir/sid/icd-10 | version 字段 | E11(2型糖尿病) |
| ICD-10-CM | http://hl7.org/fhir/sid/icd-10-cm | version 字段 | E11.9 |
| RxNorm | http://www.nlm.nih.gov/research/umls/rxnorm | version 字段 | 860975(二甲双胍) |
| UCUM | http://unitsofmeasure.org | 通常不标版本 | mg/dL、mmol/L |
这里有一个关键工程约定:UCUM 的 system 是固定的,码值就是单位表达式本身,如 mg/dL。UCUM 是“单位语法系统”,不是“枚举码表”,因此它的 code 是大小写敏感的,mg 与 Mg 含义不同(后者是兆克)。在FHIR的 Quantity 中,单位必须用UCUM表达,才能被跨系统正确解析。
三、在FHIR资源中的表达:CodeableConcept 与 Coding 的层级关系
FHIR中绝大多数“编码型”字段使用 CodeableConcept。它的结构是:一个 CodeableConcept 包含 0..* 个 Coding,外加一个 text。这意味着同一个临床概念可以同时携带多个系统的编码,例如一个“2型糖尿病”诊断,可以同时给出SNOMED CT码和ICD-10码,供不同接收方按需取用。
下面是一个真实的FHIR JSON片段,展示同一概念的多系统编码:
{
"coding": [
{
"system": "http://snomed.info/sct",
"code": "44054006",
"display": "Diabetes mellitus type 2"
},
{
"system": "http://hl7.org/fhir/sid/icd-10",
"code": "E11",
"display": "Type 2 diabetes mellitus"
}
],
"text": "2型糖尿病"
}
注意:text 是兜底显示,不能替代编码。工程上应保证至少一个 Coding 的 system 与 code 组合是有效的,否则接收方无法做术语校验。
四、版本治理:为什么 version 不能省
编码系统会持续更新:LOINC每年两次大版本,SNOMED CT每月国际版发布,ICD-10各国修订节奏不同。如果 Coding.version 缺失,接收方无法判断该码值是在哪个版本下有效的,可能导致“码值存在但语义已变更”的静默错误。
推荐策略是:在数据交换中,凡是涉及临床决策或计费的编码,必须带 version。对于UCUM,由于其语法稳定,通常可省略版本;对于SNOMED CT,若使用模块化URI,版本已隐含在URI中,version 字段可留空,但需在系统层面统一约定,避免同一系统两种写法混用。
工程建议:建立一份“系统URI注册表”,把每个编码系统的标准URI、版本字段名、是否大小写敏感、是否允许本地扩展等属性固化下来,作为接口开发和数据校验的唯一依据。任何新增系统都必须先注册,再使用。
五、URI策略的常见陷阱与校验方法
实际项目中最常见的三类错误:一是把版本号写进 system,如 http://loinc.org/2.77;二是ICD-10与ICD-10-CM混用同一URI;三是UCUM单位写成非标准形式,如 mg/dl(应为 mg/dL)。
校验方法可以分三步:第一步,用正则或白名单校验 system 是否属于已注册URI集合;第二步,校验 code 是否符合该系统的基本格式(如LOINC为数字-数字,UCUM为合法单位表达式);第三步,若带 version,校验 version 是否在允许的版本列表中。这三步可以在FHIR验证器或接口网关中实现。
把这张图当作接口评审时的对照卡:左侧是FHIR数据结构的层级,右侧是必须注册的系统URI清单,底部是校验顺序。只要 system 不在白名单、code 格式不符、version 不在允许列表,就应在入库前拦截,而不是等到下游消费时才暴露问题。
六、本地扩展与映射的边界
当标准系统无法覆盖本地概念时,FHIR允许使用本地编码系统,但URI必须使用机构自有域名,例如 http://example.org/fhir/CodeSystem/local-lab。本地码不能伪装成标准系统码,也不能把本地码直接塞进SNOMED CT的system下。正确做法是:本地码单独成系统,再通过 ConceptMap 建立与标准系统的映射关系,映射结果标注等价程度(equivalent、wider、narrower等)。
总结本节要点:system 是系统身份,不是版本;version 是版本治理的关键字段;UCUM 的 code 是大小写敏感的单位表达式;多系统编码通过 CodeableConcept 的多个 Coding 并行表达;本地扩展必须独立URI并走 ConceptMap 映射。把这四条落到接口契约和校验规则里,术语集成的稳定性就有了基础。