对于AI助手:文档索引位于 https://www.mongodb.com/zh-cn/docs/llms.txt — 通过将 .md 附加到任何URL路径,可以获得所有页面的降价版本。
Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs 菜单

文档优先的 openEHR 持久层

使用案例: 应用驱动型分析互操作性现代化

行业: 医疗保健政府卫生服务生命科学

产品: MongoDB AtlasMongoDB Atlas Search

合作伙伴: openEHR

openEHR 是一种结构化临床记录的方法,即使应用程序和数据库不断演变,也能让记录的医学含义保持一致。它将记录中稳定的技术结构,与用于对观察、用药或诊断等现实概念建模的临床定义分离开来。

从技术层面来说,openEHR 是一种基于模型的 EHR 架构。其参考模型定义了临床记录的稳定结构,而原型和模板则添加临床意义和实现约束。其主要记录单元是 COMPOSITION,这是一种分层临床文档,其内容通过 AQL 查询。AQL 与存储模型无关。它将类似 SQL 的子句、分层路径以及嵌套临床结构上的 CONTAINS 谓词结合起来。要高效扩展这类查询可能颇具挑战。

在实践中,openEHR 存储库通常需要支持以下查询类别。第一类对应于单患者检索,例如打开已知患者的病历,或在一个电子健康记录 (EHR) 中检索特定临床文档。第二类涉及跨患者操作型检索,例如建立队列、查找满足安全规则的患者、生成工作列表,或在诊疗服务过程中识别相似病例。这些操作型查询必须紧贴应用程序工作流执行,并保持低且可预测的延迟。

许多实现很难有效地支持这两种查询模式。关系型方法可以很好地支持患者范围内检索,但大规模跨患者查询往往会因连接、模式频繁变化和模板差异而承压。将这些工作负载卸载到独立的分析平台有助于回顾性分析,但这会导致数据重复、增加延迟、分散治理和审计跟踪,并削弱统一 AQL 查询接口这一目标。如果文档被过度扁平化,还可能丢失相关临床上下文。

本解决方案通过 MongoDB 上的文档优先、半扁平化持久化模型解决了这一问题。半扁平化意味着将每个元素扁平化为数组中的一个节点,但每个节点都保留了原始结构中的完整 JSON 负载。文档优先意味着每个 openEHR 组合都会作为一个 MongoDB 文档保留,而不是被分解为每个原型一张表或每条路径一行。同时,该组合会被物化为一个可重构的节点数组,从而在不放弃组合作为操作单元的情况下,实现基于路径的高效查询。

每个存储节点都包含以下关键元素:

  • 局部临床子树,使原始含义和上下文仍然可用。

  • 位置元数据,使结构和顺序可以重建。

  • 反向 AQL 路径,可实现可变深度路径约束的高效匹配。

反向路径是一种通用查询键,用于在患者范围内和跨患者执行路径中高效评估结构谓词。它支持不同执行策略的路径约束匹配,包括基于正则表达式的匹配和搜索索引中的通配符式路径解析。当谓词使用其他文本路径组件或文本条件时,可以应用相同的查询模式。

使用此模型,可以将 AQL 子句确定性地编译为 MongoDB 查询阶段。FROMCONTAINSWHERE 约束会变成针对节点路径和值的目标谓词。这种方法可保持组合作为主要临床容器的完整性,同时仍让操作型检索在规模化场景下切实可行。

半扁平化合成的表示

图 1. 半扁平化组合的表示形式,其中每个节点都携带自身上下文和值,以及反向 AQL 路径

注意

如需查看已发布的架构和评估简明摘要,请阅读经同行评审的会议摘要。如需了解完整设计(包括半扁平化持久化模型、确定性 AQL 到 MQL 编译以及基准测试详情),请阅读完整技术论文。

对于许多存储库,单个半扁平化集合和通配符索引就足够了。对于更大规模的部署,该模型可以使用精简搜索投影,其中仅包含大范围跨患者过滤所需的数据。然后,查询执行按范围路由。精简搜索投影是一个较小的派生集合,仅存储大范围跨患者过滤所需的节点字段。它不会取代主组合文档。它可以减少大范围操作型查询的索引范围和搜索成本。

因此,该模型支持以下模式:

  • 患者范围内查询在主组合集合上运行,并使用目标索引,例如基于 ehr_idreversed_path 等字段的复合索引。

  • 跨患者查询会针对更精简的投影运行,将路径约束编译为通配符或反向路径上的匹配,并将值谓词编译为等值、范围或搜索运算符。

这种执行模型提供单一查询接口,可根据工作负载大小和选择性采用不同的物理访问路径。

现代临床应用程序越来越需要在同一平台上支持这两种查询系列。临床医生可能需要立即打开一个患者记录并提出以下问题:

  • 哪些患者在给定时间窗口内接受了某种药物?

  • 哪些患者符合某项协议或安全规则?

  • 之前有哪些案例与当前病例在临床上相似?

这些操作型问题需要在不经过重复 ETL 周期将数据推送到单独系统的情况下得到解答。

文档优先的半扁平化模型保留了 openEHR 的优势,并让这些工作负载变得切实可行。它将组合保留为权威操作单元,通过可重构结构保留临床保真度,并避免迫使应用程序团队在以患者为中心的存储和独立的跨患者平台之间做出选择。较小的存储库可以保持简单,使用一个半扁平化集合。较大的存储库可以添加较小的投影,以降低大范围操作型过滤的成本。

在我们的评估中,这种方法在两种工作负载类型上都保持了较低的端到端延迟,即使在大规模场景下,患者范围内查询和跨患者查询的响应时间也很短。这种效率证明,该方法可以作为 openEHR 存储库的实用基础;这类存储库需要在同一平台上支持操作型检索、来源感知处理、语义增强和 AI 驱动型工作流。

注意

生产环境验证依据:该架构已在生产环境中的一个存储库上得到验证,该存储库包含超过 12 亿个持久化文档。

您可以借助 kehrnel 探索这种模式。kehrnel 是一个实验性参考运行时和工具包,适用于文档优先的临床数据策略。

采用这种方法可带来以下实际益处:

  • 可重构的半扁平化模型,可保留组合保真度。

  • 无需强制对临床文档进行关系型拆分,即可高效进行患者范围内查询。

  • 支持跨患者操作型检索,而无需默认采用数据仓库优先架构。

  • 为应用团队提供统一的操作型查询入口,而不是依赖重复的存储和碎片化逻辑。

  • 一条可降低 ETL 开销、治理漂移和总体拥有成本的路径。

Kehrnel 是一个策略运行时,可将医疗保健数据模型转化为操作型能力。Kehrnel 存在的原因在于,仅定义医疗保健数据模型还不够。团队还需要一种可重复的方法来验证数据,将其转换为操作型表示,摄取、查询和维护数据,并随着需求变化持续演进。如果没有这个执行层,模型往往仍只是文档、存储模式或孤立的规范。

目标不只是构建一个 openEHR 引擎。Kehrnel 提供一种可重复的文档优先方法,让医疗保健数据模型能够在 API、工具和 AI 工作流中执行、检查和复用。随着时间推移,同一运行时模式还可支持其他模型系列和操作型策略,包括 FHIR、合成数据工作流、语义目录、自然语言检索以及其他领域特定工具。

Kehrnel 围绕对外公开的工作流设计,可根据每种持久化策略的需求进行自定义。每种策略都可以定义自己的激活、验证、摄取、转换、查询、合成数据和维护操作,同时仍使用一致的运行时模型。

Kehrnel 从 openEHR 入手,因为 openEHR 是一个要求严苛且语义丰富的模型。它包含原型、模板、路径、术语以及复杂的查询行为。这使它成为验证模型驱动运行时方法的坚实基础。

在此解决方案中,Kehrnel 作为文档优先持久化模式的参考运行时和工具包。

Kehrnel CLI 屏幕截图

图 2. Kehrnel CLI 屏幕截图

图 3 显示了该策略在 Kehrnel 中的端到端流程,从规范 openEHR 输入到路由查询执行。

AQL 编译器和路由运行时的架构表示

图 3. AQL 编译器和路由运行时 (kehrnel)

第 1 层:数据源从规范 openEHR 组合、操作模板模型目录以及用于大规模测试的可选合成数据开始。OPT 是从原型和模板派生的已编译运行时工件。操作型系统使用 OPT 进行验证和路径感知处理。

第 2 层:转换管道将每个传入的组合转换为此策略使用的持久化表示。半扁平化步骤会扫描组合层次结构,应用路径和代码编码,并使用映射规则来具体化可查询节点。结果会为每个组合生成一个半扁平化的 MongoDB 文档,其存储节点保留了本地临床子树、位置元数据和反向路径键。

第 3 层:字典和映射存储此策略所需的辅助工件。_codes_shortcuts 支持紧凑的路径解析和编码。映射存储驱动转换和查询编译的策略特定规则。

第 4 层:MongoDB 集合展示持久化选项。主组合集合存储半扁平化组合文档,并通过 ehr_idcn.p 上的复合索引支持患者范围内执行。对于大型存储库,可选的搜索集合会存储跨患者过滤所需节点数据点的精简投影。该集合使用 MongoDB Atlas Search 建立索引。双集合模式可缩小搜索映射范围并降低搜索成本。

第 5 层:查询引擎,Kehrnel 在此解析并路由 AQL。运行时接受 AQL 语句,验证抽象语法树 (AST),解析别名和安全投影,检测查询是患者范围内查询还是跨患者查询,并发出相应的 MQL 路由。当查询包含 ehr_id 时,运行时会在组合集合上发出患者范围内聚合管道,通常使用 $match$project$sort$limit 等阶段。当查询为跨患者查询时,运行时会在精简投影上发出搜索优先管道,在复合过滤器中使用 embeddedDocumentwildcardrangeequals 等操作符。当 template/time/order 谓词便于匹配时,它也可以让部分跨患者查询在基础集合上执行。

第 6 层:运行时接口,通过 Kehrnel CLI 和 HTTP API 公开这一策略。CLI 支持环境设置、策略激活、编译和查询执行等运维工作流。API 会公开相同的运行时能力,用于集成、自动化和交互式文档。

这种分层设计为应用团队提供一个逻辑统一的操作型查询入口,并可根据存储库大小、查询范围和工作负载选择性启用不同的访问路径。

将每个组合作为一个 MongoDB 文档存储,并以半扁平化形式持久化。每个存储节点包含:

  • 本地临床子树

  • 反向路径键

  • 用于重构的位置元数据

这种结构让模型具备文档优先特性,并可在规模化场景下查询。您可以避免创建“每个原型一张表”的布局,也避免强制每个查询仅使用原始嵌套 JSON 结构。

在此模型中,openEHR 路径仍是一等对象。持久化文档将组合保留为操作单元,节点数组则为编译器提供确定性的查询结构。

以下简化文档展示了一个可读的持久化组合示例。该文档为便于说明而格式化,因此字段名和路径值比紧凑的生产编码更易理解。

{
"_id": "...",
"ehr_id": "patient-001",
"composition_id": "c-001",
"template_id": "openEHR-EHR-COMPOSITION.vaccination_list.v0",
"version": 1,
"cn": [
{
"p": "ACTION.medication.v1.SECTION.immunisation_list.v0.COMPOSITION.vaccination_list.v0",
"kp": "content[0]/items[0]",
"pi": [0,0],
"bk": "b1",
"data": {
"time": {
"value": "2026-01-15T10:30:00Z"
},
"other_participations": {
"performer": {
"identifiers": {
"id": "038321545"
}
}
},
"code": {
"value": "J07BX03"
}
}
}
]
}

一个 MongoDB 文档代表一个 openEHR 组合。cn 数组存储从该组合中提取的可查询节点。每个节点都会在 data 中保留一个本地临床子树,在 p 中保留一个反向路径键,并保留 kppibk 等位置元数据,以便重构原始结构。

公开示例以可读形式显示路径键,便于理解转换过程。在生产环境中,您可以将同一路径存储为紧凑的字典编码令牌,以减小路径大小和索引占用空间

存储的路径字段是关键优化点。参考模型属性和原型节点标识符构成 openEHR 路径。本解决方案使用反向存储路径,可通过前缀匹配来评估包含约束,而无需执行前导通配符扫描。此设置适用于患者范围内路由中的标准正则表达式匹配,也适用于搜索路由中的通配符式匹配。

AQL 独立于存储模型,使得确定性编译有效。SQL 子句转换为 MQL 如下:

  • FROMCONTAINS 会成为结构路径谓词。

  • WHERE 会成为匹配节点负载上的值谓词。

  • SELECT 会成为投影。

  • ORDER BY 变为排序。

以下示例说明了一个 AQL 查询。

SELECT
e/ehr_id/value AS ehrId,
c/uid/value AS compositionId,
med_ac/description[at0017]/items[at0140]/items[at0141]/value/defining_code/code_string AS locationCode
FROM
EHR e
CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.vaccination_list.v0]
CONTAINS (
CLUSTER adminInfo[openEHR-EHR-CLUSTER.admin_salut.v0]
AND SECTION[openEHR-EHR-SECTION.immunisation_list.v0]
AND ACTION med_ac[openEHR-EHR-ACTION.medication.v1]
)
WHERE
med_ac/time/value >= '2000-04-13T07:54:16.345Z'
AND med_ac/time/value <= '2026-02-13T07:54:16.345Z'
AND adminInfo/items[at0007]/items[at0014]/value/defining_code/code_string = 'E08019820'
AND med_ac/other_participations/performer/identifiers/id = '038321545'
ORDER BY
med_ac/time/value DESC

此查询结合了结构约束和基于值的约束。CONTAINS 子句定义所需的 openEHR 结构,在此例中,即一个包含管理集群和用药操作的疫苗接种组合。WHERE 子句随后会添加针对操作时间、执行者标识符和管理代码的谓词。

此类查询可受益于确定性编译。它针对分层临床结构和节点局部值表达条件。

已编译的 MQL 遵循与 AQL 相同的逻辑:

  • 顶层 ehr_id 过滤器会将查询限定为患者范围内查询。

  • $all 子句要求 AQL 描述的所有结构分支都出现在同一组合中。

  • 每个 $elemMatch 都会将一个路径谓词及其值谓词绑定到同一存储节点。

  • p 上的谓词是结构CONTAINS逻辑的编译形式。

  • data 下的谓词是 WHERE 条件的编译形式。

  • 在完整管道中,编译器随后会添加与 SELECTORDER BY 对应的投影和排序阶段。

下一个示例显示了从上述 AQL 查询生成的简化的患者范围 MQL 模式。它说明了编译器逻辑,而不是逐字节的运行时有效负载。

// Simplified compiler output for a single-EHR query.
// Projection and sorting stages are omitted here for clarity.
db.compositions.aggregate([
{
"$match": {
"ehr_id": "b416bc97-de39-43f5-9d47-712af6688947~r1",
"cn": {
"$all": [
{
"$elemMatch": {
"p": {
"$regex": /^ACTION\.medication\.v1(?:\.[^.]+)*\.SECTION\.immunisation_list\.v0(?:\.[^.]+)*\.COMPOSITION\.vaccination_list\.v0$/
},
"data.time.value": {
"$gte": ISODate("2000-04-13T07:54:16.345Z"),
"$lte": ISODate("2026-02-13T07:54:16.345Z")
},
"data.other_participations.performer.identifiers.id": "038321545"
}
},
{
"$elemMatch": {
"p": {
"$regex": /^at0014\.at0007\.CLUSTER\.admin_salut\.v0(?:\.[^.]+)*\.COMPOSITION\.vaccination_list\.v0$/
},
"data.value.defining_code.code_string": "E08019820"
}
}
]
}
}
}
]);

在跨患者路由中,逻辑转换保持不变。差异在于物理执行方式。编译器不是在主组合集合上匹配,而是以精简搜索投影为目标。反向路径上的结构约束会变成通配符过滤器,值谓词则会变成范围过滤器和等值过滤器。

下一个示例展示了由不绑定到单个患者的 AQL 生成的 MQL 模式。与前文一样,它展示的是编译器逻辑,而非逐字节一致的运行时负载。

{
"$search": {
"index": "search_nodes_index",
"compound": {
"filter": [
{
"embeddedDocument": {
"path": "sn",
"operator": {
"compound": {
"filter": [
{
"wildcard": {
"path": "sn.p",
"query": "ACTION.medication.v1*SECTION.immunisation_list.v0*COMPOSITION.vaccination_list.v0"
}
},
{
"range": {
"path": "sn.data.time.value",
"gte": ISODate("2000-04-13T07:54:16.345Z"),
"lte": ISODate("2025-04-13T07:54:16.345Z")
}
},
{
"equals": {
"path": "sn.data.other_participations.performer.identifiers.id",
"value": "038321545"
}
}
]
}
}
}
}
]
}
}
}

一些 openEHR 结构可能包含具有相同有效路径的重复同级节点,例如重复的 EVENTs。在这些情况下,编译器需要将谓词下推到更深层级,以便由同一重复项满足条件。在标准聚合中,这意味着更深层嵌套的 $elemMatch。在搜索路由中,等效项是 embeddedDocument,它会将多个条件绑定到同一个嵌入式数组元素。

使用此存储库中提供的 Kehrnel 作为此模式的参考运行时和工具包。Kehrnel 提供策略生命周期、验证流程、半扁平化管道和 AQL 编译路径,用于摄取规范 openEHR 组合,并通过正确的执行路径路由操作型查询。

激活时,Kehrnel 会通过 manifest.json 公开策略,使用 defaults.json 作为激活基线,通过 schema.json 验证覆盖,并应用策略实现和 spec.json 所描述的存储与索引计划。建议让 Kehrnel 根据活动配置创建集合和 B-tree 索引,而不是先在 MongoDB 中手动创建。

该存储库将 Kehrnel 定位为一个实验性运行时,用于演示、教学、快速原型设计和概念验证。要在您自己的环境中复现此解决方案,请按照以下步骤操作:

1

创建一个 Atlas 集群,并确定哪个数据库用于保存策略数据。

在此阶段,您只需要目标数据库名称和连接字符串。

对于 MacOS 和 Linux:

export MONGODB_URI="<your-atlas-connection-string>"
export MONGODB_DB="openEHR_demo"

对于 Windows Powershell:

set MONGODB_URI=<your-atlas-connection-string>
set MONGODB_DB="openEHR_demo"
exit
2

克隆存储库,并使用 ./startKehrnel 启动运行时。此入口点会自动准备本地环境,并让首次运行保持简单。

git clone https://github.com/mongodb-industry-solutions/kehrnel
cd kehrnel
./startKehrnel
export RUNTIME_URL="${RUNTIME_URL:-http://localhost:8080}"
# Alternative direct API entrypoint:
# uvicorn kehrnel.api.app:app --reload --port 8080

启动后,确认运行时可访问,并使用 Kehrnel 作为其余工作流的控制平面。

启动后,Kehrnel 会在 http://localhost:8080/guide 路由公开一个 Docusaurus 站点。图 4 显示了该站点。

Kehrnel 文档

图 4. Kehrnel 文档

3

将 CLI 指向正在运行的运行时,创建目标环境并检查该环境。环境是 Kehrnel 中的激活单元。它可隔离策略配置、绑定、生成的工件和操作状态,而无需强制更改策略代码。

# Point the CLI at the running kehrnel runtime
kehrnel context set --runtime-url "$RUNTIME_URL"
kehrnel core health
kehrnel core env create --env dev --name "Development"
kehrnel core env list
kehrnel core env show --env dev
4

Kehrnel 支持多种环境、领域和策略。在本演练中,请明确选择 openehr 域和 openehr.rps_dual 策略。

使用 src/kehrnel/engine/strategies/openehr/rps_dual/defaults.json 作为基线配置;仅当您需要更改集合名称、字段标签、搜索启用状态、字典、分隔符、编码策略或映射时,才添加一个小型覆盖文件。

激活是 Kehrnel 根据活动策略配置物化已配置集合和 B-tree 索引的步骤。对于打包的参考示例,激活覆盖文件会将 strategy 指向打包的投影映射。随后会根据策略的激活设置应用字典引导初始化。

注意

如需了解完整的 openehr.rps_dual 配置范围以及支持应用哪些更改,请参阅策略配置指南。本指南解释策略基线中每项设置控制的内容,包括集合名称、字段标签、搜索侧启用状态、字典种子、路径分隔符和编码策略

mkdir -p .kehrnel
# Local plaintext MongoDB bindings for the walkthrough
cat > .kehrnel/bindings.mongo.yaml <<EOF
db:
provider: mongodb
uri: ${MONGODB_URI}
database: ${MONGODB_DB}
EOF
# Packaged activation override for the reference dual-collection example
kehrnel core env activate \
--env dev \
--domain openehr \
--strategy openehr.rps_dual \
--config src/kehrnel/engine/strategies/openehr/rps_dual/samples/reference/activation.config.json \
--allow-plaintext-bindings \
--bindings .kehrnel/bindings.mongo.yaml \
--force
# Ensure bundled dictionaries are present
kehrnel run ensure_dictionaries --env dev --domain openehr
# Generate the Atlas Search definition derived from the active mappings
kehrnel strategy build-search-index \
--env dev \
--domain openehr \
--strategy openehr.rps_dual \
--out .kehrnel/search-index.json
5

使用 src/kehrnel/engine/strategies/openehr/rps_dual/samples 下策略自带的示例资产,或使用您自己的规范 openEHR 输入。

使用 OPT 模板来验证或生成组合。

当您希望搜索侧集合基于同一套配置构建,并由该配置驱动摄取和搜索索引生成时,请使用打包的投影映射。

SAMPLES_ROOT="src/kehrnel/engine/strategies/openehr/rps_dual/samples/reference"
# Inspect the packaged reference assets
ls "$SAMPLES_ROOT/templates"
ls "$SAMPLES_ROOT/queries"
ls "$SAMPLES_ROOT/envelopes"
ls "$SAMPLES_ROOT/projection_mappings.json" \
"$SAMPLES_ROOT/search_index.definition.json" \
"$SAMPLES_ROOT/manifest.json"
# Optional: generate and validate a sample composition from a packaged OPT
kehrnel common generate -- \
-t "$SAMPLES_ROOT/templates/sample_laboratory_v0_4.opt" \
-o .kehrnel/composition.json \
--random
kehrnel common validate -- \
-c .kehrnel/composition.json \
-t "$SAMPLES_ROOT/templates/sample_laboratory_v0_4.opt" \
--stats
# Optional: generate a starter source-to-canonical mapping skeleton
kehrnel common map-skeleton -- \
"$SAMPLES_ROOT/templates/sample_laboratory_v0_4.opt" \
-o .kehrnel/mapping.skeleton.yaml \
--macros
6

通过策略摄取组合。打包的 NDJSON 封套是规范 openEHR 组合包装器,其中包含脱敏组合以及 ehr_idtemplate_idcomposition_versiontime_committed 等元数据。

此处使用 kehrnel run ingest;本演练从规范 openEHR 封套开始,需要该策略生成半扁平化基础文档,并在模板存在映射时生成可选的搜索侧投影文档。

下面的本地文件标志只是保护机制,允许运行时从您的工作树中读取打包的示例 NDJSON。

当模板存在映射时,Kehrnel 还会在 compositions_search 中创建可选的搜索侧文档。如果模板不存在映射,它会跳过该辅助文档,而不是发出空数组。

# The CLI expands the local NDJSON into documents before sending the request.
kehrnel run ingest \
--env dev \
--domain openehr \
--strategy openehr.rps_dual \
--set file_path="$SAMPLES_ROOT/envelopes/all.ndjson"
7

在执行前先编译具有代表性的 AQL。

确认已解决的范围、已发出的 MQL 以及所选的执行路径。

此编译步骤是该模式的关键操作约定。应用程序继续使用 AQL,而 Kehrnel 则负责针对存储模型进行确定性转换和执行规划。

# Compile only: inspect the execution plan without running the query
kehrnel core env compile-query \
--env dev \
--domain openehr \
--aql "$SAMPLES_ROOT/queries/patient_laboratory_by_ehr.aql"
kehrnel core env compile-query \
--env dev \
--domain openehr \
--aql "$SAMPLES_ROOT/queries/cross_patient_laboratory_by_performing_centre.aql"
8

在同一环境中运行患者范围内查询和跨患者查询。这一执行过程展示了该模式的核心价值:提供统一的操作型查询入口,并由运行时为工作负载选择正确的物理执行路径。

对于患者范围内查询,运行时可以面向主半扁平化集合,使用支持索引的 $match 阶段,以及 $project$sort$limit 等阶段。对于范围更广的操作型检索,当查询形态适合时,运行时可以将查询路由到面向搜索的路径。

# Execute both representative queries
kehrnel core env query \
--env dev \
--domain openehr \
--aql "$SAMPLES_ROOT/queries/patient_laboratory_by_ehr.aql"
kehrnel core env query \
--env dev \
--domain openehr \
--aql "$SAMPLES_ROOT/queries/cross_patient_laboratory_by_performing_centre.aql"
9

检查生成的 MongoDB 文档、可选的搜索侧投影以及 Atlas Search 索引定义,以验证文档优先设计。

您可以看到规范组合如何保持为源输入,半扁平化形式如何支持确定性查询,以及映射如何驱动搜索侧投影,而不是盲目复制整个文档。

# Inspect the generated base and search-side documents
mongosh "$MONGODB_URI/$MONGODB_DB" <<'MONGOSH'
db.compositions_rps.findOne({}, { ehr_id: 1, tid: 1, time_c: 1, cn: { $slice: 3 } })
db.compositions_search.findOne({}, { ehr_id: 1, comp_id: 1, tid: 1, sort_time: 1, sn: 1 })
MONGOSH
# Inspect the generated Atlas Search definition
cat .kehrnel/search-index.json
10

基础流程正常运行后,请继续使用 CLI,而不是直接转向自定义 API 对接。CLI 已公开主要的操作型构建块:

  • 环境生命周期

  • 策略激活

  • 字典设置

  • 搜索索引生成

  • 查询编译

  • 查询执行

该工具包让 Kehrnel 成为策略工作的自然控制平面。单独的应用程序或 UI 可以构建在其之上,但策略本身仍具备可移植性和可检查性,并可直接通过运行时和 CLI 操作。

# Continue through the CLI for strategy operations and discovery
kehrnel op capabilities --env dev
kehrnel op schema synthetic_generate_batch --strategy openehr.rps_dual
kehrnel run rebuild_codes --env dev --domain openehr
kehrnel run rebuild_shortcuts --env dev --domain openehr
kehrnel run build_search_index_definition \
--env dev \
--domain openehr \
--strategy openehr.rps_dual

注意

您是否想在引导式沙盒中试用此模式?Healthcare Data Lab 基于 Kehrnel 构建,可帮助团队建模、查询和测试文档优先的医疗保健数据策略,包括这种 openEHR 持久化方法。该功能目前以私有预览版形式提供。请联系您的 MongoDB 客户代表申请访问权限。

  • 将组合作为半扁平化文档持久化:为每个组合保留一个 MongoDB 文档,但将其存储为可重构的半扁平化形式,而不是原始嵌套负载形式。

  • 对路径进行编码和反向处理以实现高效匹配:将 AQL 结构路径转换为紧凑的反向令牌,使 CONTAINS 可映射到前缀匹配谓词。

  • 按范围路由 AQL:使用 ehr_id 将患者范围内查询保留在本地执行,并在适当时将跨患者查询发送到 Atlas Search。

  • 根据扩展选择一个或两个集合:单个半扁平集合效果不错,但非常大的存储库会受益于较小的搜索投影。

  • 保留统一的操作型查询入口:让应用团队继续使用 AQL,而运行时则处理确定性编译和执行规划。

  • Francesc Mateu Amengual, MongoDB

  • Giovanni Rodriguez, MongoDB

  • Greg Cox,MongoDB

  • Juan Crossley,MongoDB