跳转到主要内容

概览

在 Mirobody 中,“数据映射”是三个各自独立的关注点:
  1. 域映射 —— vendor 把它的端点映射到归一化的 DataDomain 枚举,让调用方按类别请求数据。
  2. 单位归一化 —— 自由文本的单位被折叠为规范的 UCUM(已上线)。
  3. FHIR 表示 —— 一切最终汇聚到的规范资源形态是 FHIR R4(测量值用 Observation)。
fetch 返回该 vendor 自己的 JSON(FHIR 原生源则返回 FHIR JSON);规范存储是内嵌的 FHIR R4 端点。

1 —— 域映射

每次 fetch 都接收一个 DataDomain,每个 vendor 把它映射到它实际中转的端点:
enum class DataDomain {
    Activity, Sleep, HeartRate, Glucose,
    Nutrition, BodyMetrics, Labs, Clinical
};
一个 REST vendor 在域上 switch 以选择路径(Fitbit):
switch (d) {
    case DataDomain::Activity:    return "/1/user/" + u + "/activities/steps/date/" + s + "/" + e + ".json";
    case DataDomain::HeartRate:   return "/1/user/" + u + "/activities/heart/date/" + s + "/" + e + ".json";
    case DataDomain::Sleep:       return "/1.2/user/" + u + "/sleep/date/" + s + "/" + e + ".json";
    case DataDomain::BodyMetrics: return "/1/user/" + u + "/body/log/weight/date/" + s + "/" + e + ".json";
    default: throw VendorError("fitbit: unsupported domain (activity, heart_rate, sleep, body_metrics)");
}
一个 FHIR vendor 则把域映射到 FHIR Observationcategory token(ehr SMART-on-FHIR 客户端):
case DataDomain::HeartRate:   return "vital-signs";
case DataDomain::BodyMetrics: return "vital-signs";
case DataDomain::Glucose:     return "laboratory";
case DataDomain::Labs:        return "laboratory";
case DataDomain::Activity:    return "activity";
case DataDomain::Clinical:    return nullptr;   // unfiltered: the full observation set
vendor 会对它不中转的域抛错,而非返回空 —— 让调用方了解该源的范围。

2 —— 单位归一化(UCUM)

src/fhir/units/ 中的术语引擎把一段自由文本的”数值 + 单位”字符串变成一个规范的 UCUM 单位,外加用于消歧的 LOINC PROPERTY 族。纯本地计算 —— 无数据库、无 embedding API。
#include "fhir/units/normalize.hpp"
#include "fhir/units/families.hpp"
using namespace mirobody::fhir::units;

normalize_unit("MG/DL");        // "mg/dL"
normalize_unit(u8"毫摩尔每升");  // "mmol/L"
normalize_unit("mmHg");         // "mm[Hg]"

ParsedQuantity q = parse_value_unit("<5.6 mg/dL");
// q.comparator == "<", q.value == 5.6, q.unit == "mg/dL"

unit_family("mmol/L");          // "SCnc"
unit_family("mg/dL");           // "MCnc"
流水线:NFKC-lite(全角形态、上标)→ 符号折叠 → 别名查找 → 注释剥离 → 贪婪的语素分词-组合。大小写被保留(UCUM 区分大小写)。支持多语言输入:en、zh、ja、ko、ru、de、fr、es。由 tests/fhir/units_test.cpp 覆盖。

3 —— FHIR R4 表示

规范存储是 FHIR R4(src/fhir/)。FHIR 原生的 vendor —— 通用 ehr 客户端,以及 Vitalera / HealthConnect / Redox / Particle Health / Metriport-Medical —— 已直接返回 FHIR 资源;设备本地存储 POST Observation。一个测量值是一个 Observation,带一个归一化(UCUM)的 valueQuantity
{
  "resourceType": "Observation",
  "status": "final",
  "category": [{ "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs" }] }],
  "code": { "text": "Heart rate" },
  "valueQuantity": { "value": 72, "unit": "/min", "system": "http://unitsofmeasure.org", "code": "/min" }
}
资源按用户以通用的、经校验的 JSON 存储,并通过 /fhir 提供(参见数据流)。
把一个指标映射到带编码Observation.code(SNOMED CT / LOINC / RxNorm)—— 即术语解析以及文档 → 带编码 FHIR 的写回 —— 尚在进行中。UCUM 归一化与 RESTful FHIR 存储已上线;完整的术语映射尚在计划中(参见 src/fhir/README.md 的第 3–4 阶段)。在此之前,Observation.code 可能携带一个 text 而非解析出的编码。(verify)

映射一个新数据源

当你添加一个 vendor::VendorProvider 集成)时:
  1. 确定该源中转哪些 DataDomain;在 VendorInfo.domains 中列出它们。
  2. fetch 中,把每个域映射到该源的端点(REST 路径)或 FHIR category(FHIR 源);对不支持的域抛错。
  3. 返回该源的 JSON(或 FHIR JSON)。不要预先归一化 —— 归一化 / FHIR 转换是下游的、共享的关注点。
  4. 若你暴露单位,把它们经 parse_value_unit / normalize_unit 处理,使其落地为 UCUM。

下一步

Provider 集成

实现 fetch 与域映射

数据流

从 vendor JSON 到 FHIR 存储

文件处理

文档数值的 UCUM 归一化

Provider 测试

验证你的 fetch 输出