2. 健康数据模型设计
健康评估与干预计划平台的数据来源天然是异构的:可穿戴设备持续上报心率、步数、睡眠分期;院内设备产生血压、血糖、体重等体征记录;用户填写PHQ-9、GAD-7等量表问卷;App埋点记录饮食、运动、用药等行为事件;环境传感器或第三方接口提供温湿度、空气质量、地理位置。若把这些数据直接堆进一张宽表,很快会遇到三个问题:同一指标单位与采集口径不一致、同一患者多次测量无法表达时间语义、问卷总分与条目得分无法同时保留。因此数据模型设计要同时解决实体关系、时序表达和标准映射三件事。
一、实体关系建模:以“人—事件—观测”为主干
推荐的主干结构是:Patient(受试者/患者)通过 Encounter(接触/评估场次)关联到 Observation(观测),观测再通过 ObservationComponent 表达多分量结果(如血压的收缩压/舒张压),通过 QuestionnaireResponse 表达问卷作答,通过 Device 表达采集来源。核心原则有三条:
- 观测与定义分离:
Observation只存“谁、何时、什么值、什么单位、来自哪个设备/表单”,指标的定义(编码、正常范围、数据类型)放在ObservationDefinition或术语表中,避免每个观测重复携带元数据。 - 问卷与量表分层:
Questionnaire定义题目与选项,QuestionnaireResponse存单次作答,条目得分与总分分别落库,便于后续重算与审计。 - 行为与环境作为事件流:行为(步数、饮食、用药)和环境(温湿度、PM2.5)本质是带时间戳的事件,用
Event或Observation统一承载,避免为每类数据单独建表。
下面这张图给出多源数据到统一模型的映射关系,以及时序存储与标准映射的分层结构。
二、时序数据建模:把“时间”作为一等公民
体征、行为、环境数据都是高频或中频时序数据。建模时不要只存“最新值”,而要保留完整时间序列。推荐采用“窄表 + 维度表”的方式:事实表只存 patient_id、code、effective_time、value_numeric、value_text、unit、source_id,维度表存指标定义、单位、正常范围、采集频率。这样新增指标不需要改表结构。
时序建模要明确三个约定:
- 时间语义:区分
effective_time(生理事件发生时间)与recorded_time(系统写入时间)。设备离线补传时两者可能相差数小时,评估时必须用effective_time做窗口聚合。 - 采样与聚合:原始数据按设备采样频率存储,分析层再按小时/天聚合。例如心率原始值每5秒一条,日粒度分析时聚合为日均值、最大值、静息心率。
- 缺失与异常:缺失值不补零,用 NULL 表示;异常值保留原始值并打质量标记(如
quality_flag = 'outlier'),避免清洗后无法追溯。
以血压为例,一次测量产生两条分量记录:收缩压 code=8480-6、舒张压 code=8462-4,共享同一 effective_time 和 encounter_id。查询“最近7天晨间血压均值”时,按 effective_time 过滤 06:00–10:00,按 patient_id + code 分组求均值,即可得到可用于干预计划判断的指标。
三、FHIR 与 OMOP 参考:映射而非照搬
FHIR 适合作为交换与接口层的参考模型。平台对外提供数据时,把内部 Observation 映射为 FHIR Observation 资源,字段对应关系为:内部 code → Observation.code(LOINC 编码),value_numeric + unit → valueQuantity,effective_time → effectiveDateTime,patient_id → subject.reference。问卷则映射为 QuestionnaireResponse,条目得分放在 item.answer.valueInteger,总分放在 item.linkId='total' 的扩展中。
OMOP CDM 适合作为分析层的参考模型。体征和实验室指标映射到 MEASUREMENT 表,问卷总分映射到 OBSERVATION 表,行为事件映射到 OBSERVATION 或 PROCEDURE_OCCURRENCE,环境暴露可映射到 OBSERVATION。关键字段是 person_id、measurement_concept_id、measurement_date、value_as_number、unit_concept_id。映射时要用标准术语集(LOINC、SNOMED、UCUM)做 concept_id 对齐,而不是自造编码。
四、一个可落地的建模检查清单
| 检查项 | 判断标准 | 常见问题 |
|---|---|---|
| 实体主键 | Patient、Encounter、Observation 均有稳定业务主键 | 用自增ID做跨系统主键,导致合并困难 |
| 时间字段 | effective_time 与 recorded_time 分离且均带时区 | 只存字符串时间,无法做窗口聚合 |
| 单位与编码 | 指标编码用 LOINC,单位用 UCUM | 同一指标多套编码,无法跨源合并 |
| 问卷分层 | 条目得分与总分分别存储,保留量表版本 | 只存总分,无法重算或审计 |
| 映射可追溯 | 每条记录可回溯到原始来源与映射规则版本 | 映射后丢失来源,异常无法定位 |
完成上述设计后,平台在接入新数据源时只需回答三个问题:它属于哪类实体(观测、问卷、事件)?时间语义是什么?映射到哪个标准编码?把这三个问题固化到接入规范中,多源健康数据就能在统一模型下持续积累,为后续的健康评估与干预计划生成提供稳定、可追溯的数据底座。