3. FHIR数据类型的工程含义

在FHIR交换工程中,真正决定接口能否稳定对接的,往往不是资源的大类,而是资源内部这些“小类型”。它们看起来只是字段格式,实际上承载了唯一性、语义、指向、计量、时间窗和排程等关键约束。一旦理解偏差,轻则映射错位,重则导致临床决策依据被误读。本节从工程视角逐一拆解六类高频数据类型,并给出可落地的处理策略。

Identifier:唯一标识不是“随便一个字符串”

Identifier用于表达业务系统中的标识符,如病历号、医保号、检验申请单号。它由system(命名空间URI)、value(值)、type(标识类型)、use(用途,如official、usual)等组成。工程上最常见的陷阱是:只传value不传system,导致两个不同医院的“12345”被系统误判为同一患者。正确做法是把system视为强制语义锚点,例如urn:oid:1.2.156.1001这类机构OID。另一个陷阱是use与type混用:use描述“这个标识在当前场景下是否正式”,type描述“它是什么种类的号”,二者不可互相替代。在患者主索引(EMPI)匹配时,建议把system+value作为联合主键参与比对,而不是仅比对value。

CodeableConcept:编码的“多轨并行”与语义选择

CodeableConcept是一个可携带多个coding的容器,每个coding包含system、code、display,还可带text作为自由文本兜底。它的设计初衷是允许同一概念同时用LOINC、SNOMED CT、ICD-10等不同编码体系表达。工程陷阱集中在三点:第一,把text当作主数据使用,下游无法做结构化统计;第二,多个coding之间语义不一致,例如一个coding写“高血压”,另一个写“糖尿病”,接收方无法判断以哪个为准;第三,忽略system的URI规范,写成“LOINC”而非http://loinc.org。建议在接口契约中明确“首选编码体系+允许的备选体系”,并在映射层做一次语义一致性校验:若多个coding的display差异过大,应触发人工复核而非静默通过。

Reference:指向资源的“软链接”及其完整性风险

Reference用于指向另一个资源,常见形式为Reference(Patient/123)或绝对URL。它可以是“包含式”引用(被引资源随本条一起提交)或“独立式”引用(仅给指针)。工程上最危险的是悬空引用:接收方拿到Observation.subject = Reference(Patient/999),但本地并无Patient/999。FHIR本身不强制引用完整性,这需要交换双方约定。实务中建议:对关键临床资源(如Observation、MedicationRequest)采用包含式提交,或在批量交换前先做资源依赖拓扑排序,确保被引资源先落地。此外,reference中的相对路径依赖服务器基址,跨机构交换时应优先使用绝对URL或逻辑标识(如identifier型引用),避免基址变化导致解析失败。

Quantity:数值、单位与比较语义

Quantity包含value、unit、system、code。陷阱在于“单位看起来一样,语义却不同”:unit是给人看的显示单位,code+system才是机器可比的规范单位。例如血糖value=5.6,若code为mmol/L与mg/dL,临床含义相差近18倍。工程上必须要求system=http://unitsofmeasure.org且code使用UCUM规范写法。另一个易错点是比较类Quantity(如Comparator为<、>),例如“体温<38.5℃”,若忽略comparator直接当等值处理,会丢失临床判断。建议在数据校验层对Quantity做“单位可换算性检查”,无法换算时拒绝入库并告警。

Period与Timing:时间窗与排程的两种表达

Period用start和end表达一个连续时间区间,适合“用药起止”“住院时段”。Timing则用repeat(频率、周期、次数、时长)和event表达离散或重复事件,适合“每日三次、连服七天”。工程陷阱是:把Timing硬塞进Period,或把Period拆成多个event导致语义丢失。例如医嘱“bid×7天”,正确表达是Timing.repeat.frequency=2、period=1、periodUnit=d、boundsDuration=7天;若只写两个event,接收方无法还原“持续七天”的意图。此外,Period的end缺失表示“仍在进行”,不能默认补当前时间;Timing的时区处理也需统一,建议所有时间戳带时区偏移,避免跨时区排程漂移。

FHIR 六类核心数据类型的工程约束与陷阱 Identifier 标识符 system + value 联合唯一 use:official / usual type:MRN / SS / DL 陷阱:缺 system → 跨院误匹配 CodeableConcept 编码概念 多 coding 并行:LOINC / SNOMED text 仅作兜底,不作主数据 system 必须为规范 URI 陷阱:多 coding 语义冲突 Reference 资源引用 相对路径 / 绝对 URL 包含式 vs 独立式提交 依赖拓扑排序后落地 陷阱:悬空引用 / 基址漂移 Quantity 数量 value + unit + code + system UCUM 规范:mmol/L vs mg/dL Comparator:< > 比较语义 陷阱:单位不可换算仍入库 Period 时间区间 start / end 连续区间 end 缺失 = 仍在进行 适用:用药起止、住院时段 陷阱:end 缺失被补当前时间 Timing 排程 repeat:frequency / period / bounds event:离散事件时间点 示例:bid × 7 天 陷阱:拆成 event 丢失持续语义 交换链路中的类型校验顺序 1. 标识锚定 system+value 校验 2. 语义编码 coding 一致性 3. 引用完整性 依赖拓扑排序 4. 单位与时间 UCUM / 时区统一 5. 告警 人工复核

工程落地:把类型约束写进接口契约

上述六类类型的问题,单靠开发人员记忆很难保证一致。建议在接口契约(如OpenAPI或FHIR CapabilityStatement)中显式声明:Identifier必须携带system;CodeableConcept至少一个coding且system为白名单URI;Reference在批量交换时采用包含式;Quantity必须使用UCUM code;Period的end缺失语义为“持续中”;Timing优先使用repeat而非event。同时,在数据接入层设置校验规则,对不满足约束的消息返回OperationOutcome并标注具体路径,而不是静默丢弃或强行转换。

实践建议:在联调阶段准备一组“类型陷阱测试用例”,例如同一患者两个不同system的相同value、单位不可换算的Quantity、悬空Reference、end缺失的Period,观察接收方是否按预期告警。这比只测正常流程更能暴露真实交换风险。

总结来看,Identifier解决“是谁”,CodeableConcept解决“是什么”,Reference解决“指向谁”,Quantity解决“多少”,Period与Timing解决“何时”。把这六类类型的约束前置到契约和校验层,FHIR交换才能从“能通”走向“可信”。