AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。
Docs Menu

ドキュメントファーストのopenEHR永続化レイヤー

ユースケース: アプリ主導型分析相互運用性モダナイゼーション

業種: 医療政府保健サービスライフサイエンス

製品: MongoDB AtlasMongoDB Atlas Search

パートナー: openEHR

openEHRは、アプリケーションやデータベースが進化しても医療的意味が一貫して保たれるように臨床記録を構造化するための方法です。これは、観察、投薬、診断といった現実世界の概念をモデル化するために使用される臨床定義から、記録の安定した技術的構造を分離します。

技術的には、openEHRはモデル駆動型のEHRアーキテクチャです。その参照モデルは臨床記録の安定した構造を定義し、一方でarchetypeとtemplateは臨床的意味および実装制約を追加します。その主要な記録単位はAQLを通じてクエリーされる、階層型の臨床ドキュメントであるCOMPOSITIONです。AQLはストレージモデルから独立しています。SQLのような句と階層的なパスとネストされた医療構造に対するCONTAINS述語を組み合わせます。これらのクエリを効率的にスケールさせることは課題となる場合があります。

実務上、openEHRリポジトリは、通常、次のクエリファミリーをサポートする必要があります。1つ目は単一患者の取得に対応し、例えば既知の患者のカルテを開く場合や、1つのEHR内の特定の臨床ドキュメントを取得する場合です。2つ目は、患者横断の運用取得に関するもので、例えばコホートの作成、安全ルールを満たす患者の特定、作業リストの生成、またはケア提供時に類似ケースを特定することなどが含まれます。これらの運用クエリは、低く予測可能なレイテンシで、アプリケーションのワークフローに近い場所で実行される必要があります。

多くの実装では、これら両方のクエリパターンを効率的にサポートすることに苦労しています。リレーショナルなアプローチは患者単位の取得には適していますが、大規模な患者横断クエリでは、結合、スキーマの変化、テンプレートのばらつきにより負荷が増大することがよくあります。これらのワークロードを別の分析プラットフォームにオフロードすることで、遡及的分析には対応できますが、重複が生じ、レイテンシが増加し、ガバナンスや監査証跡が分断され、統一されたAQLクエリインターフェースという目標が弱まります。また、ドキュメントを過度にフラット化すると、関連する臨床コンテキストが失われる可能性もあります。

このソリューションは、MongoDB上のドキュメントファーストでセミフラット化された永続化モデルにより、この課題に対応します。セミフラット化とは、各要素を配列内のノードとしてフラット化しつつも、それぞれが元の構造における完全なJSONペイロードを保持することを意味します。ドキュメントファーストとは、各openEHRコンポジションを、アーキタイプごとに1テーブルやパスごとに1行に分解するのではなく、1つのMongoDBドキュメントとして保持することを意味します。同時に、コンポジションは再構成可能なノード配列としてマテリアライズされ、運用単位としてのコンポジションを維持しながら、パスベースの効率的なクエリを可能にします。

各格納ノードは、次の主要要素を保持します。

  • ローカルな臨床サブツリーにより、元の意味とコンテキストが保持されます。

  • 位置メタデータにより、構造と順序を再構築できます。

  • 逆順のAQLパスにより、可変深度のパス制約の効率的なマッチングが可能になります。

この逆順パスは、患者単位および患者横断の両方の実行経路において構造的述語を効率的に評価するために使用される汎用的なクエリキーです。正規表現ベースのマッチングやワイルドカード形式のパス解決(検索インデックス内)を含む、さまざまな実行戦略におけるパス制約付きマッチングをサポートします。述語が他のテキストパス要素やテキスト条件を使用する場合でも、同じクエリパターンを適用できます。

このモデルでは、AQL句をMongoDBのクエリステージに決定的にコンパイルできます。FROMCONTAINSWHEREの制約は、ノードパスおよび値に対するターゲット化された述語になります。このアプローチでは、主要な臨床コンテナとしてのコンポジションを維持したまま、大規模環境においても運用上の取得を実用的に実現します。

セミフラット化されたコンポジションの表現

図1。各ノードが自身のコンテキストと値に加えて逆順のAQLパスを保持する、セミフラット化されたコンポジションの表現

注意

アーキテクチャおよび評価の簡潔な公開サマリーについては、「査読付きカンファレンスアブストラクト」を参照してください。セミフラット化された永続化モデル、決定的なAQLからMQLへのコンパイル、ベンチマークの詳細を含む完全な設計については、完全な技術論文を参照してください。

多くのリポジトリでは、単一のセミフラット化コレクションとワイルドカードインデックスで十分です。より大規模なデプロイメントでは、このモデルは、広範な患者横断フィルタリングに必要なデータのみを含むスリムなサーチプロジェクションを使用できます。クエリ実行はその後、スコープに基づいてルーティングされます。スリムな検索プロジェクションは、広範な患者横断フィルタリングに必要なノードフィールドのみを格納する、より小さな派生コレクションです。これはメインのコンポジションドキュメントを置き換えるものではありません。これにより、広範な運用クエリにおけるインデックスの広がりと検索コストが削減されます。

したがって、次のモダリティが提供されます。

  • 患者単位のクエリは、メインのコンポジションコレクション上で実行され、ehr_idreversed_pathといったフィールドに対する複合インデックスなどのターゲット化されたインデックスを使用します。

  • 患者横断クエリは、よりスリムなプロジェクションに対して実行され、パス制約は逆順パスに対するワイルドカードまたはマッチ条件にコンパイルされ、値の述語は等価、範囲、または検索オペレーターにコンパイルされます。

この実行モデルは単一のクエリインターフェースを提供し、ワークロードの規模や選択性に応じて異なる物理的アクセスパスを可能にします。

現代の臨床アプリケーションでは、同一のプラットフォーム上で両方のクエリファミリーを必要とするケースが増えています。臨床医は、1人の患者の記録を即座に開き、次のような問いを発する必要がある場合があります。

  • どの患者が特定の期間内に特定の投薬を受けましたか。

  • どの患者がプロトコルまたは安全ルールに適合しますか。

  • どの過去症例が本症例と臨床的に類似していますか。

これらの運用上の問いには、データを別のシステムに分離して繰り返しETL処理にかけることなく、回答できる必要があります。

ドキュメントファーストでセミフラット化されたモデルは、openEHRの強みを維持しつつ、これらのワークロードを実用的に実現します。これは、コンポジションを権威ある運用単位として維持し、再構成可能な構造によって臨床的忠実性を保ちつつ、アプリケーションチームに対して患者中心ストアと別個の患者横断プラットフォームのいずれかを選択させることを回避します。小規模なリポジトリでは、1つのセミフラット化コレクションでシンプルに運用できます。大規模なリポジトリでは、広範な運用フィルタリングのコストを削減するために、より小さなプロジェクションを追加できます。

当社の評価では、このアプローチは両方のワークロードタイプにおいて低いエンドツーエンドのレイテンシを維持し、患者単位および患者横断クエリのいずれにおいても、大規模環境下でも低い応答時間を実現しました。この効率性は、運用取得、来歴認識処理、セマンティックエンリッチメント、およびAI主導のワークフローを単一のプラットフォームでサポートする必要があるopenEHRリポジトリにとって、実用的な基盤であることを裏付けています。

注意

本番実績:このアーキテクチャは、本番環境において1.2億件を超える永続化ドキュメントを持つリポジトリで検証されています。

このパターンは、ドキュメントファーストの臨床データ戦略向けの実験的なリファレンスランタイムおよびツールキットであるkehrnelを使用して検証できます。

このアプローチにより、次の実用的な利点が得られます。

  • コンポジションの忠実性を維持する再構成可能なセミフラット化モデル。

  • 臨床ドキュメントをリレーショナルに分割することなく実現される、効率的な患者単位クエリ。

  • ウェアハウスファーストのアーキテクチャに依存することなく、患者横断の運用取得をサポート。

  • 重複したストアや分断されたロジックの代わりに、アプリケーションチームに単一の運用クエリサーフェスを提供。

  • ETLのオーバーヘッド、ガバナンスドリフト、および総所有コストの低減につながるアプローチ。

Kehrnelは、ヘルスケアデータモデルを運用機能へと変換する戦略ランタイムです。Kehrnelが存在する理由は、ヘルスケアデータモデルを定義するだけでは不十分だからです。チームには、データを検証し、運用表現へと変換し、取り込み、クエリし、維持し、要件の変化に応じて進化させるための、再現可能な手段も必要です。そのような実行レイヤーがなければ、モデルは単なるドキュメント、ストレージスキーマ、または孤立した仕様のままにとどまることが多くなります。

目標は、openEHRエンジンを構築することにとどまりません。Kehrnelは、ヘルスケアデータモデルを実行可能で検証可能、かつ再利用可能にするための、再現可能なドキュメントファーストのアプローチを提供し、API、ツール群、およびAIワークフロー全体で活用できます。時間の経過とともに、同一のランタイムパターンは、FHIR、合成データワークフロー、セマンティックカタログ、自然言語検索、およびその他のドメイン固有ツールを含む、他のモデルファミリーや運用戦略もサポートできるようになります。

Kehrnelは、公開されたワークフローを中心に設計されており、各永続化戦略のニーズに合わせてカスタマイズできます。各戦略は、一貫したランタイムモデルを使用しながら、独自のアクティベーション、検証、取り込み、変換、クエリ、合成データ、および保守運用を定義できます。

KehrnelはopenEHRから開始されます。これは、openEHRが要求の厳しいセマンティックに豊富なモデルであるためです。これには、アーキタイプ、テンプレート、パス、用語、および複雑なクエリ動作が含まれます。これにより、モデル駆動型ランタイムアプローチを実証するための強固な基盤が形成されます。

このソリューションでは、Kehrnelはドキュメントファーストの永続化パターンのためのリファレンスランタイムおよびツールキットとして機能します。

Kehrnel CLI スクリーンショット

図2。Kehrnel CLIスクリーンショット

図3は、canonicalなopenEHR入力からルーティングされたクエリ実行までの、kehrnelにおけるこの戦略のエンドツーエンドのフローを示しています。

AQLコンパイラーおよびルーティングランタイムのアーキテクチャー表現

図3。AQLコンパイラおよびルーティングランタイム(kehrnel)

レイヤー1:データソースは、標準的なopenEHRコンポジション、運用テンプレートのモデルカタログ、および大規模テスト用のオプションの合成データから開始されます。OPTは、archetypeおよびtemplateから生成されるコンパイル済みランタイムアーティファクトです。運用システムでは、検証およびパス認識処理にOPTを使用します。

レイヤー2:変換パイプラインは、受信した各コンポジションを、この戦略で使用される永続化表現へと変換します。セミフラット化ステップでは、コンポジション階層をスキャンし、パスおよびコードのエンコーディングを適用し、マッピングルールを使用してクエリ可能なノードをマテリアライズします。その結果、各コンポジションごとに1つのセミフラット化されたMongoDBドキュメントが生成され、ローカルな臨床サブツリー、位置メタデータ、および逆順パスキーを保持するノードが格納されます。

レイヤー3:ディクショナリおよびマッピングは、この戦略に必要な補助成果物を格納します。_codesおよび_shortcutsは、コンパクトなパス解決およびエンコーディングをサポートします。マッピングは、変換およびクエリコンパイルを駆動する戦略固有のルールを格納します。

レイヤー4:MongoDBコレクションは永続化オプションを示します。メインのコンポジションコレクションは、セミフラット化されたコンポジションドキュメントを格納し、ehr_idcn.pに対する複合インデックスを通じて患者単位の実行をサポートします。大規模なリポジトリでは、オプションの検索コレクションが、患者横断フィルタリングに必要なノードデータのスリムなプロジェクションを格納します。このコレクションはMongoDB Atlas Searchでインデックス化されます。デュアルコレクションパターンにより、検索マッピングが簡素化され、検索コストが低減されます。

レイヤー5:クエリエンジンは、kehrnelがAQLを解析およびルーティングする場所です。ランタイムはAQLステートメントを受け取り、ASTを検証し、エイリアスおよび安全なプロジェクションを解決し、クエリが患者単位か患者横断かを判定して、適切なMQLルートを生成します。クエリにehr_idが含まれる場合、ランタイムは通常、$match$project$sort、および$limitなどのステージを使用して、コンポジションコレクションに対する患者単位の集約パイプラインを生成します。クエリが患者横断の場合、ランタイムはスリムなプロジェクションに対する検索優先のパイプラインを生成し、複合フィルター内でembeddedDocumentwildcardrange、およびequalsなどの演算子を使用します。template/time/orderの述語がマッチに適している場合、一部の患者横断クエリはベースコレクション上で実行されることもあります

レイヤー6:ランタイムインターフェースは、kehrnel CLIおよびHTTP APIの両方を通じてこの戦略を公開します。CLIは、環境設定、戦略の有効化、コンパイル、クエリ実行などのオペレーターワークフローをサポートします。APIは、統合、自動化、およびインタラクティブなドキュメント化のために、同一のランタイム機能を提供します。

このレイヤード設計により、アプリケーションチームは単一の論理的な運用クエリサーフェスを利用でき、リポジトリの規模、クエリのスコープ、およびワークロードの選択性に応じて異なるアクセスパスが有効になります。

各コンポジションは1つの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"
}
}
}
]
}

1つのMongoDBドキュメントは、1つのopenEHRコンポジションを表します。cn配列には、そのコンポジションから抽出されたクエリ可能なノードが格納されます。各ノードは、data内にローカルな臨床サブツリー、p内に逆順パスキー、およびkppi、およびbkといった位置メタデータを保持し、元の構造を再構築できるようになっています。

公開されているこの例では、翻訳しやすくするためにパスキーを読みやすい形式で示しています。本番環境では、パスサイズとインデックスフットプリントを減らすために、同じパスをコンパクトな辞書エンコードトークンとして保存できます。

格納されたパスフィールドは、主要な最適化を表します。リファレンスモデルの属性およびアーキタイプノード識別子は、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コンパイルパスを提供し、canonicalなopenEHRコンポジションを取り込んで、適切な実行パスを通じて運用クエリをルーティングします。

アクティベーション時には、kehrnelはmanifest.jsonを通じて戦略を公開し、defaults.jsonをアクティベーションのベースラインとして使用し、schema.jsonでオーバーライドを検証し、戦略実装およびspec.jsonで定義されたストレージおよびインデックスプランを適用します。推奨される方法は、まずMongoDBで手動で作成するのではなく、アクティブな構成からkehrnelにコレクションおよびB木インデックスを作成させることです。

このリポジトリでは、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は次のルートでDocusaurusサイトを公開します:http://localhost:8080/guide図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をベースライン設定として使用し、コレクション名、フィールドラベル、検索の有効化、辞書、区切り文字、コーディングポリシー、またはマッピングを変更したい場合にのみ、小さなオーバーライドファイルを追加します。

アクティベーションは、有効な戦略設定から、設定済みのコレクションおよびB木インデックスを実体化するステップです。パッケージ化されたリファレンス例では、アクティベーションのオーバーライドファイルは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エンベロープは、マスクされたコンポジションに加えて、ehr_idtemplate_idcomposition_versiontime_committedなどのメタデータを含む、正規のopenEHRコンポジションラッパーです。

ここでは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検索インデックス定義を確認し、ドキュメントファースト設計を検証します。

正規のコンポジションがソース入力として維持されること、セミフラット化形式が決定的なクエリをサポートすること、またマッピングがドキュメント全体を無差別に複製するのではなく検索側プロジェクションを駆動することを確認できます。

# 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

ベースフローが機能したら、カスタムAPIの配線に直接進むのではなく、CLIを使って進めます。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 のアカウント担当者にお問い合わせください。

  • コンポジションをセミフラット化ドキュメントとして永続化:コンポジションごとに1つのMongoDBドキュメントを保持しつつ、未加工のネストされたペイロードではなく、再構築可能なセミフラット形式で保存します。

  • 効率的なマッチングのためのパスのエンコードと反転:AQLの構造パスをコンパクトな逆順トークンに変換し、CONTAINSがプレフィックス適合の述語にマッピングできるようにします。

  • スコープ別にAQLをルーティング:ehr_idehr_idを使用して患者スコープのクエリーをローカルに保持し、必要に応じてクロス患者クエリーをAtlas検索に送信します。

  • 規模に応じて1つまたは2つのコレクションを選択:単一のセミフラット化されたコレクションでも十分に機能しますが、非常に大規模なリポジトリでは、スリムな検索プロジェクションを使用するメリットがあります。

  • 運用クエリサーフェスを1つに維持:ランタイム側で決定論的なコンパイルと実行計画を処理しつつ、アプリケーションチームはAQLを引き続き使用できるようにします。

  • Francesc Mateu Amengual, MongoDB

  • Giovanni Rodriguez, MongoDB

  • グレッグ・コックス、MongoDB

  • Juan Crossley(MongoDB)