3. 患者档案与时间轴建模

在患者全生命周期管理平台中,患者档案不是一张静态的“基本信息表”,而是一条随时间不断生长的健康记录链。传统以业务单据为中心的设计(挂号单、检验单、处方单各自独立)会导致同一个患者的病史被切碎在几十张表里,跨机构、跨时间查询时只能靠姓名和身份证号做模糊拼接,既慢又容易出错。本节要解决的核心问题是:如何用一套以患者为中心的数据模型,把分散的临床事件组织成可追溯、可回放、可纵向对比的健康记录。

一、以患者为中心的数据模型:主体与事件分离

建模的第一步是确立“患者主体”与“临床事件”的分离。患者主体(Patient)只承载相对稳定的身份与人口学信息:患者主索引 EMPI 号、姓名、性别、出生日期、证件号、联系方式、血型、过敏史摘要等。这些字段变化频率低,但一旦变更需要留痕。临床事件(ClinicalEvent)则承载所有随时间发生的事实:一次门诊、一次检验、一次用药、一次住院、一次随访。

两者通过 patient_id 关联,事件本身不再重复存储患者姓名等冗余信息,而是通过外键引用主体。这样做的直接收益是:患者改名、换手机号时只需更新一处,历史事件自动继承最新身份信息;同时,事件表可以按时间分区,支撑千万级记录的纵向查询。

一个可落地的核心表结构示例如下:

patient(
  patient_id      BIGINT PRIMARY KEY,   -- EMPI 主索引
  name            VARCHAR(64),
  gender          CHAR(1),
  birth_date      DATE,
  id_card_hash    CHAR(64),             -- 证件号哈希,用于匹配
  allergy_summary TEXT,
  updated_at      TIMESTAMP
)

clinical_event(
  event_id     BIGINT PRIMARY KEY,
  patient_id   BIGINT,                  -- 外键指向 patient
  event_type   VARCHAR(32),             -- encounter/lab/med/vital/...
  event_time   TIMESTAMP,               -- 事件发生时间(临床时间)
  recorded_at  TIMESTAMP,               -- 记录写入时间(系统时间)
  source_system VARCHAR(32),            -- HIS/LIS/EMR/随访App
  payload      JSONB,                   -- 事件明细
  version      INT
)

这里有两个时间字段必须区分:event_time 是临床上事件真正发生的时间,recorded_at 是数据进入平台的时间。补录一份三年前的检验报告时,两者会相差很大,时间轴排序应以 event_time 为准,而审计追溯则看 recorded_at。

二、事件溯源:让档案可回放、可纠错

事件溯源(Event Sourcing)的核心思想是:不直接保存“当前状态”,而是保存导致状态变化的一系列事件,当前状态由事件按顺序重放得到。对患者档案而言,这意味着我们不存“患者当前是否在服用二甲双胍”这样一个布尔值,而是存“2024-03-01 开具二甲双胍”“2024-06-10 停药”两条事件,需要时重放出用药状态。

这种方式的工程价值体现在三方面。第一是可追溯:任何一条档案数据都能回答“它从哪来、谁在什么时候写的”。第二是可纠错:录入错误时不物理删除,而是追加一条更正事件(如 event_type=lab_correction),原始记录保留,符合医疗数据不可篡改的合规要求。第三是可回放:可以重建“患者在某年某月某日的完整健康快照”,用于回顾性研究或纠纷举证。

事件溯源不等于“只追加不查询”。实践中通常配合物化视图或读模型(Read Model),把事件流投影成便于查询的宽表,写入走事件、读取走投影,兼顾一致性与性能。

三、纵向健康记录的组织方式

有了主体和事件,还需要一种组织方式把事件串成“时间轴”。常见做法是三层组织:时间轴层按 event_time 倒序排列所有事件,形成患者完整时间线;分类层按事件类型聚合为就诊、检验、用药、影像、随访等视图;摘要层提炼关键指标(如最近一次血压、糖化血红蛋白趋势)供快速浏览。

时间轴建模中一个容易被忽视的问题是事件归并。同一次门诊可能产生挂号、开单、缴费、取药多个系统事件,如果全部平铺,时间轴会被噪声淹没。通常引入“就诊会话(Encounter)”作为聚合根,把同一 encounter_id 下的事件折叠为一个节点,展开后才是明细。这样时间轴既保持纵向连续性,又具备可下钻的层次。

下面这张图展示了从多源系统事件到患者纵向时间轴的组织关系:左侧是各业务系统产生的事件,中间经事件归并与溯源处理,右侧形成以患者为中心、按就诊会话聚合的纵向时间轴。

多源临床事件 HIS 门诊/住院 LIS 检验 RIS/PACS 影像 随访 App 可穿戴设备 事件归并与溯源 EMPI 患者主索引匹配 event_time 排序 就诊会话 Encounter 归并 更正事件追加(不删除) 版本号 version 递增 读模型投影(宽表) 审计留痕 recorded_at 患者纵向时间轴 2024-03-01 门诊 · 高血压初诊 2024-03-01 检验 · 血脂四项 2024-06-10 用药 · 氨氯地平 5mg qd 2024-09-20 随访 · 血压 138/86 时间轴按 event_time 倒序,节点可下钻至事件明细

四、建模中的关键取舍

第一,事件粒度。粒度过粗(一次住院一条事件)会丢失细节,粒度过细(每个生命体征一条)会让时间轴爆炸。经验做法是:以“临床上有独立意义的动作”为粒度,如一次检验报告、一次用药医嘱、一次随访记录,而把连续监测数据放入独立的时序表,仅在时间轴上做趋势摘要。

第二,标识匹配。跨机构数据接入时,同一患者可能在不同系统有不同 ID。EMPI 匹配通常采用“证件号哈希精确匹配 + 姓名/性别/出生日期模糊匹配 + 人工确认”三级策略,匹配结果写入 patient_id 映射表,避免直接改写源系统数据。

第三,隐私与合规。患者主体表中的证件号、联系方式属于敏感字段,应加密存储或哈希化,时间轴查询接口按角色返回脱敏视图。事件溯源保留全部历史版本,但对外暴露时需按权限过滤。

不要用“最后写入覆盖”的方式更新患者档案。医疗数据的合规底线是可追溯,任何覆盖都会导致历史记录丢失,一旦发生医疗纠纷将无法举证。

综合来看,以患者为中心的数据模型解决了“数据归属谁”的问题,事件溯源解决了“数据怎么变、怎么查来源”的问题,纵向时间轴解决了“数据怎么组织给人看”的问题。三者叠加,患者档案才真正从一张表变成一条可生长的健康记录链,为后续的风险评估、随访提醒、科研检索提供统一的数据底座。