제품: MongoDB Atlas, MongoDB Atlas 검색
파트너: openEHR
솔루션 개요
openEHR은 애플리케이션과 데이터베이스가 진화하더라도 임상 기록의 의학적 의미가 일관되게 유지되도록 구조화하는 방법입니다. 이 방식은 기록의 안정적인 기술적 구조를 관찰, 약물 처방 또는 진단과 같은 실세계 개념을 모델링하는 데 사용하는 임상 정의와 분리합니다.
기술적으로 openEHR은 모델 기반 EHR 아키텍처입니다. 참조 모델은 임상 기록의 안정적인 구조를 정의하는 반면, 아키타입과 템플릿은 임상적 의미와 구현 제약 조건을 추가합니다. 주요 기록 단위는 COMPOSITION이며 이는 AQL을 통해 콘텐츠를 쿼리할 수 있는 계층 구조의 임상 문서입니다. AQL은 저장 모델과 무관합니다. 이는 SQL과 유사한 절을 계층적 경로 및 중첩된 임상 구조에 대한 CONTAINS 조건자와 결합합니다. 이러한 쿼리를 효율적으로 확장하는 작업은 까다로운 과제가 될 수 있습니다.
실제로 OpenEHR 리포지토리는 다음과 같은 쿼리 제품군을 지원해야 하는 경우가 많습니다. 첫 번째는 단일 환자 조회로 특정 환자의 차트를 열거나 단일 EHR 내에서 특정 임상 문서를 검색하는 사례 등이 해당합니다. 두 번째는 다수 환자 대상 운영 조회이며 코호트 구축이나 안전 규칙을 충족하는 환자 검색, 작업 목록 생성 또는 진료 중 유사 사례 식별 등을 포함합니다. 이러한 운영 쿼리는 애플리케이션 워크플로우와 밀접하게 실행되어야 하며 지연 시간이 짧고 예측 가능해야 합니다.
많은 구현 사례에서 이 두 가지 쿼리 패턴을 모두 효율적으로 지원하는 데 어려움을 겪고 있습니다. 관계형 접근 방식은 개별 환자 단위의 조회에는 효과적일 수 있지만 대규모의 다수 환자 대상 쿼리는 조인이나 스키마의 빈번한 변경 및 템플릿 변형으로 인해 시스템 부하를 유발하는 경우가 많습니다. 이러한 워크로드를 별도의 분석 플랫폼으로 오프로드하면 사후 분석에는 도움이 될 수 있지만 데이터 중복과 지연 시간이 발생하고 거버넌스 및 감사 추적이 파편화되며 통합 AQL 쿼리 인터페이스라는 목표를 약화시킵니다. 또한 문서를 지나치게 공격적으로 평탄화하면 관련 임상 컨텍스트가 유실될 수 있습니다.
임상 쿼리 제품군 통합
이 솔루션은 MongoDB에서 문서 우선 및 반평탄화 지속성 모델을 사용하여 해당 문제를 해결합니다. 반평탄화란 각 요소를 배열의 노드로 평면화하되 각 노드가 원래 구조의 전체 JSON 페이로드를 그대로 유지하는 방식을 의미합니다. 문서 우선이란 각 openEHR 컴포지션을 아키타입별 테이블이나 경로별 행으로 분해하지 않고 단일 MongoDB 문서로 보존하는 것을 뜻합니다. 동시에 컴포지션은 재구성 가능한 노드 배열로 구체화되므로 컴포지션이라는 운영 단위를 유지하면서도 효율적인 경로 기반 쿼리를 수행할 수 있습니다.
각 저장된 노드는 다음과 같은 주요 요소를 보유합니다.
로컬 임상 서브트리: 원래의 의미와 컨텍스트를 그대로 활용할 수 있습니다.
위치 메타데이터를 통해 구조와 순서를 재구성할 수 있습니다.
역방향 AQL 경로: 가변 깊이의 경로 제약 조건에 대해 효율적인 매칭을 가능하게 합니다.
역방향 경로는 개별 환자 단위 및 다수 환자 대상 실행 경로 모두에서 구조적 조건자를 효율적으로 평가하는 데 사용되는 일반 쿼리 키입니다. 이 키는 정규식 기반 매칭 및 검색 인덱스의 와일드카드 방식 경로 확인을 포함하여 다양한 실행 전략에서 경로 제약 매칭을 지원합니다. 조건자가 다른 텍스트 경로 구성 요소나 텍스트 조건을 사용하는 경우에도 동일한 쿼리 패턴을 적용할 수 있습니다.
이 모델을 사용하면 AQL 절을 MongoDB 쿼리 단계로 결정론적으로 컴파일할 수 있습니다. FROM, CONTAINS 및 WHERE 제약 조건은 노드 경로 및 값에 대한 타겟팅된 조건자가 됩니다. 이 접근 방식은 컴포지션을 기본 임상 컨테이너로 온전하게 유지하면서도 대규모 환경에서 운영 조회를 실용적으로 만들어 줍니다.
그림 1. 각 노드가 자체 컨텍스트 및 값과 역방향 AQL 경로를 포함하는 반평탄화된 컴포지션의 구조
참고
아키텍처 및 평가에 대한 간결한 요약은 동료 검토를 거친 컨퍼런스 초록에서 확인할 수 있습니다. 반평탄화 지속성 모델, 결정론적 AQL-MQL 컴파일 및 벤치마크 세부 정보를 포함한 전체 설계는 기술 문서 전문을 참조하세요.
워크로드 기반 라우팅
많은 리포지토리의 경우 단일 반평탄화 컬렉션과 와일드카드 인덱스만으로도 충분합니다. 더 큰 규모의 배포 환경에서는 광범위한 다수 환자 대상 필터링에 필요한 데이터만 포함하는 간소화된 검색 프로젝션을 사용할 수 있습니다. 이후 쿼리 실행은 범위에 따라 라우팅됩니다. 간소화된 검색 프로젝션은 광범위한 다수 환자 대상 필터링에 필수적인 노드 필드만 저장하는 소규모 파생 컬렉션입니다. 이는 메인 컴포지션 문서를 대체하지 않으며 광범위한 운영 쿼리의 인덱스 폭과 검색 비용을 절감합니다.
이에 따라 다음과 같은 실행 방식을 제공합니다.
개별 환자 단위 쿼리는
ehr_id및reversed_path필드에 대한 복합 인덱스와 같은 타겟 인덱스를 사용하여 메인 컴포지션 컬렉션에서 실행됩니다.다수 환자 대상 쿼리는 더 간소화된 프로젝션을 대상으로 실행되며 경로 제약 조건은 와일드카드나 역방향 경로 매칭으로, 값 조건자는 등호, 범위 또는 검색 연산자로 컴파일됩니다.
이 실행 모델은 단일 쿼리 인터페이스를 제공하며 워크로드 규모와 선택도에 따라 다양한 물리적 액세스 경로를 지원합니다.
운영 코호트 쿼리 지원이 중요한 이유
현대의 임상 애플리케이션은 동일한 플랫폼 내에서 두 가지 쿼리 패밀리를 모두 처리해야 하는 필요성이 증가하고 있습니다. 임상의는 특정 환자의 기록을 즉시 열람하는 동시에 다음과 같은 질문을 던질 수 있어야 합니다.
특정 기간 내에 특정 약물을 투여받은 환자는 누구인가?
어떤 환자가 프로토콜 또는 안전 규칙과 일치하나요?
현재 사례와 임상적으로 유사한 이전 사례는 무엇인가?
이러한 운영상의 질문은 반복적인 ETL 주기를 통해 데이터를 별도의 시스템으로 전송하지 않고도 답변을 얻을 수 있어야 합니다.
문서 우선의 반평탄화 모델은 openEHR의 강점을 유지하면서 이러한 워크로드를 실용적으로 구현할 수 있게 합니다. 이 모델은 컴포지션을 신뢰할 수 있는 운영 단위로 유지하고 재구성 가능한 구조를 통해 임상적 충실도를 보존하며, 애플리케이션 팀이 환자 중심 저장소와 별도의 다수 환자 대상 플랫폼 중 하나를 선택해야 하는 제약을 없애줍니다. 규모가 작은 리포지토리는 단일 반평탄 컬렉션을 사용하여 단순하게 구성할 수 있습니다. 규모가 큰 리포지토리의 경우 소규모 프로젝션을 추가하여 광범위한 운영 필터링에 드는 비용을 절감할 수 있습니다.
본 평가 결과 이 접근 방식은 대규모 환경에서도 개별 환자 단위 및 다수 환자 대상 쿼리 모두에서 빠른 응답 시간을 기록하며 두 워크로드 유형 전반에 걸쳐 낮은 엔드 투 엔드 지연 시간을 유지했습니다. 이러한 효율성은 단일 플랫폼에서 운영 검색, 출처 인식 처리, 시맨틱 강화 및 AI 기반 워크로드를 지원해야 하는 openEHR 리포지토리에 있어 실용적인 기반임을 입증합니다.
참고
운영 환경 검증 사례: 이 아키텍처는 12억 개 이상의 문서가 저장된 실제 운영 리포지토리에서 검증되었습니다.
문서 우선 임상 데이터 전략을 위한 실험적 참조 런타임 및 툴킷인 KEhrnel을 사용하여 이 패턴을 탐색할 수 있습니다.
이 방식을 따르면 다음과 같은 실질적인 이점을 얻을 수 있습니다:
컴포지션 충실도를 보존하는 재구성 가능한 반평탄 모델
임상 문서를 관계형으로 파편화하지 않고도 효율적인 개별 환자 단위 쿼리 수행
웨어하우스 우선 아키텍처로 전환하지 않고도 환자 통합 운영 검색 지원
중복된 저장소와 분산된 로직 대신 애플리케이션 팀을 위한 단일 운영 쿼리 인터페이스 제공
ETL 오버헤드 감소, 거버넌스 편차 완화 및 총 소유 비용 절감 경로 확보
Kehrnel의 정의와 사용 목적
Kehrnel은 헬스케어 데이터 모델을 운영 역량으로 전환하는 전략형 런타임입니다. 헬스케어 데이터 모델을 정의하는 것만으로는 충분하지 않기에 Kehrnel이 존재합니다. 개발 팀에는 요구 사항의 변화에 따라 데이터를 검증하고 이를 운영 표현으로 변환하며 수집, 쿼리, 유지 관리 및 발전시킬 수 있는 반복 가능한 방법이 필요합니다. 이러한 실행 계층이 없다면 모델은 단순한 문서나 스토리지 스키마 또는 고립된 사양으로 남게 되는 경우가 많습니다.
목표는 단순한 openEHR 엔진 구축보다 광범위합니다. Kehrnel은 헬스케어 데이터 모델을 API, 툴링 및 AI 워크플로 전반에서 실행, 검사 및 재사용이 가능하도록 만드는 반복 가능한 문서 우선 접근 방식을 제공합니다. 시간이 지남에 따라 동일한 런타임 패턴을 통해 FHIR, 합성 데이터 워크플로, 시맨틱 카탈로그, 자연어 검색 및 기타 도메인 전용 도구를 포함한 다양한 모델 계열 및 운영 전략을 지원할 수 있습니다.
Kehrnel은 각 지속성 전략의 요구 사항에 따라 맞춤 설정이 가능한 노출형 워크플로를 기반으로 설계되었습니다. 각 전략은 일관적인 런타임 모델을 유지하면서 자체 활성화, 유효성 검사, 수집, 변환, 쿼리, 합성 데이터 및 유지 관리 작업을 독자적으로 정의할 수 있습니다.
Kehrnel이 openEHR을 시작점으로 채택한 이유는 openEHR이 요구 사항이 까다롭고 시맨틱이 풍부한 모델이기 때문입니다. 여기에는 아키타입, 템플릿, 경로, 용어 및 복잡한 쿼리 동작이 포함됩니다. 따라서 이는 모델 기반 런타임 접근 방식을 입증하기 위한 강력한 토대가 됩니다.
본 솔루션에서 Kehrnel은 문서 우선 지속성 패턴을 위한 참조 런타임 및 툴킷 역할을 합니다.
그림 2. Kehrnel CLI 스크린샷
참조 아키텍처
그림 3은 정준 openEHR 입력부터 라우팅된 쿼리 실행까지, kehrnel에서의 이 전략의 엔드 투 엔드 흐름을 보여줍니다.
그림 3. AQL 컴파일러 및 라우팅 런타임(KEhrnel)
계층 1: 데이터 소스는 표준 openEHR 컴포지션, 운영 템플릿의 모델 카탈로그 및 대규모 테스트에 사용되는 선택적 합성 데이터로 시작합니다. OPT 는 아키타입과 템플릿에서 파생되어 컴파일된 런타임 아티팩트입니다. 운영 시스템은 유효성 검사 및 경로 인식 처리를 위해 OPT를 사용합니다.
계층 2: 변환 파이프라인은 유입되는 각 컴포지션을 이 전략에서 사용하는 지속성 표현으로 변환합니다. 반평탄화 단계에서는 컴포지션 계층 구조를 스캔하고 경로 및 코드 인코딩을 적용하며, 매핑 규칙을 사용하여 쿼리 가능한 노드를 구체화합니다. 그 결과 컴포지션당 하나의 반평탄화된 MongoDB 문서가 생성되며 여기에는 로컬 임상 서브트리, 위치 메타데이터 및 역방향 경로 키를 유지하는 저장 노드가 포함됩니다.
계층 3: 사전 및 매핑에는 이 전략에 필요한 헬퍼 아티팩트를 저장합니다. _codes 및 _shortcuts는 컴팩트한 경로 확인 및 인코딩을 지원합니다. 매핑은 변환 및 쿼리 컴파일을 구동하는 전략별 규칙이 저장됩니다.
계층 4: MongoDB 컬렉션은 지속성 옵션을 보여줍니다. 기본 컴포지션 컬렉션은 반평탄화된 컴포지션 문서를 저장하며 ehr_id 및 cn.p에 대한 복합 인덱스를 통해 개별 환자 단위의 실행을 지원합니다. 대규모 리포지토리의 경우 선택 사항인 검색 컬렉션에 다수 환자 대상 필터링에 필요한 노드 데이터 포인트의 간소화된 검색 프로젝션을 저장할 수 있습니다. 이 컬렉션은 MongoDB Atlas Search로 인덱싱됩니다. 이러한 이중 컬렉션 패턴은 검색 매핑의 범위를 좁히고 검색 비용을 낮게 유지해 줍니다.
계층 5: 쿼리 엔진은 kehrnel이 AQL을 파싱하고 라우팅하는 영역입니다. 런타임은 AQL 문을 수락하고 AST의 유효성을 검증하며, 별칭과 안전한 프로젝션을 확인하고 쿼리가 개별 환자 단위인지 또는 다수 환자 대상인지를 감지하여 적절한 MQL 경로를 생성합니다. 쿼리에 ehr_id가 포함된 경우 런타임은 컴포지션 컬렉션에 대해 개별 환자 단위의 집계 파이프라인을 생성하며 일반적으로 $match, $project, $sort, $limit와 같은 단계를 사용합니다. 쿼리가 다수 환자 대상인 경우 런타임은 간소화된 프로젝션에 대해 검색 우선 파이프라인을 생성하며 복합 필터 내에서 embeddedDocument, wildcard, range, equals와 같은 연산자를 사용합니다. 다만 template/time/order 조건자가 일치 조건에 적합한 경우에는 일부 다수 환자 대상 쿼리를 기본 컬렉션에서 그대로 처리할 수 있습니다.
계층 6: 런타임 인터페이스는 kernel 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에는 역방향 경로 키를 그리고 kp, pi, bk와 같은 위치 메타데이터를 유지합니다.
공개 예시에서는 변환 과정을 더 쉽게 이해할 수 있도록 읽기 쉬운 형식으로 경로 키를 보여줍니다. 실제 운영 환경에서는 경로 크기와 인덱스 설치 공간을 줄이기 위해 동일한 경로를 간결한 사전 인코딩된 토큰으로 저장할 수 있습니다.
역방향 경로 인코딩
저장된 경로 필드는 키 최적화를 나타냅니다. 참조 모델 속성과 아키타입 노드 식별자는 openEHR 경로를 구축합니다. 이 솔루션은 역방향으로 저장된 경로를 사용하여 리딩 와일드카드 스캔 대신 접두사 친화적 매칭으로 포함 제약 조건을 평가할 수 있게 합니다 이 설정은 개별 환자 단위 경로에서의 표준 정규식 기반 매칭 및 검색 경로에서의 와일드카드 방식 매칭과 함께 작동합니다.
결정론적 AQL-MQL 변환
AQL은 저장 모델과 독립적이므로 결정론적 컴파일이 효과적으로 작동합니다. SQL 절은 다음과 같이 MQL로 변환됩니다.
FROM및CONTAINS는 구조적 경로 조건자가 됩니다.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
AQL 쿼리의 의도
이 쿼리는 구조적 제약 조건과 값 기반 제약 조건을 결합합니다. CONTAINS 절은 필요한 openEHR 구조를 정의하며 이 경우 관리 클러스터와 투약 작업을 포함하는 예방 접종 컴포지션을 정의합니다. 그런 다음 WHERE 절에서 행위 시간, 수행자 식별자 및 관리 코드에 대한 조건자를 추가합니다.
이러한 쿼리 유형은 결정론적 컴파일에 유리합니다. 이는 계층적 임상 구조와 노드 로컬 값에 대한 조건을 표현합니다.
컴파일러가 AQL을 MQL에 매핑하는 방법
컴파일된 MQL은 AQL과 동일한 로직을 따릅니다.
최상위
ehr_id필터는 쿼리를 환자 범위로 만듭니다.$all절은 AQL에 기술된 모든 구조적 브랜치가 동일한 컴포지션에 포함되도록 요구합니다.각각의
$elemMatch는 경로 조건자와 해당 값 조건자들을 동일한 저장 노드에 바인딩합니다.p의 조건자는 구조적CONTAINS로직이 컴파일된 형태입니다.데이터 하위의 조건자들은
WHERE조건이 컴파일된 형태를 나타냅니다.전체 파이프라인에서 컴파일러는
SELECT및ORDER 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은 표준 openEHR 컴포지션을 수집하고 운영 쿼리를 올바른 실행 경로로 라우팅하는 데 사용되는 전략 생명주기, 검증 흐름, 반평탄화 파이프라인 및 AQL 컴파일 경로를 제공합니다.
활성화 시점에 kehrnel은 manifest.json을 통해 전략을 노출하고 defaults.json을 활성화 기준으로 사용하며, schema.json으로 재정의 항목을 검증하고 전략 구현 및 spec.json에 기술된 스토리지 및 인덱스 계획을 적용합니다. MongoDB에서 수동으로 먼저 생성하기보다는 활성 구성에 따라 kehrnel이 컬렉션과 B-트리 인덱스를 생성하도록 하는 것이 권장되는 경로입니다.
리포지토리는 kehrnel을 데모, 교육, 신속한 프로토타이핑 및 PoC를 위한 실험적 런타임으로 규정합니다 사용자 환경에서 이 솔루션을 재현하려면 다음 단계를 따르세요.
Atlas에서 MongoDB 설정하기
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
GitHub 리포지토리 복제 및 kehrnel 시작
리포지토리를 복제하고 ./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는 해당 사이트를 보여줍니다.
그림 4. Kehrnel 문서화
CLI 컨텍스트 구성 및 환경 생성
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
전략 검색 및 활성화
Kehrnel은 여러 환경, 도메인 및 전략을 지원합니다. 본 튜토리얼에서는 openehr 도메인과 openehr.rps_dual 전략을 명시적으로 선택합니다.
src/kehrnel/engine/strategies/openehr/rps_dual/defaults.json을 기준 구성으로 사용하고 컬렉션 이름, 필드 레이블, 검색 활성화 여부, 사전, 구분자, 코딩 정책 또는 매핑을 변경하려는 경우에만 소량의 재정의 파일을 추가합니다.
활성화는 kehrnel이 활성 전략 구성으로부터 설정된 컬렉션과 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
템플릿, 매핑 및 표준형 컴포지션 준비
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
컴포지션 수집
전략을 통해 컴포지션을 수집하세요. 패키지된 NDJSON 엔벨로프는 마스킹 처리된 컴포지션과 ehr_id, template_id, composition_version 및 time_committed와 같은 메타데이터를 포함하는 표준 openEHR 컴포넌스 래퍼입니다.
여기서는 kehrnel run ingest 명령을 사용합니다. 이 튜토리얼은 표준 openEHR 엔벨로프에서 시작하며 반평탄화된 기본 문서와 (템플릿 매핑이 존재하는 경우) 선택적인 검색 측 프로젝션 문서를 생성하기 위해 전략을 활용합니다.
아래의 local-file 플래그는 런타임이 작업 트리에 있는 패키지 샘플 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"
AQL 컴파일 및 검사
실행하기 전에 대표 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"
운영 쿼리 실행
동일한 환경에서 개별 환자 단위 쿼리와 다수 환자 대상 쿼리를 모두 실행해 보세요. 이 실행은 본 패턴의 핵심 가치를 보여줍니다. 즉, 단일한 운영 쿼리 인터페이스를 제공하며 런타임이 워크로드에 가장 적합한 물리적 실행 경로를 자동으로 선택합니다.
개별 환자 단위 쿼리의 경우 런타임은 인덱싱된 $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"
생성된 아티팩트 탐색
생성된 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
CLI를 통해 패턴 확장
기본 흐름이 작동하면 사용자 정의 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
참고
안내식 샌드박스에서 이 패턴을 실험하고 싶으신가요? 헬스케어 데이터 랩은 kehrnel을 기반으로 팀이 openEHR 지속성 접근 방식을 포함한 문서 우선 의료 데이터 전략을 모델링, 쿼리 및 테스트할 수 있도록 지원합니다. 현재는 비공개 미리 보기로 제공됩니다. MongoDB 계정 담당자에게 문의하여 액세스를 요청하세요.
주요 학습 사항
컴포지션을 반평탄화된 문서로 유지: 컴포지션당 하나의 MongoDB 문서를 유지하되, 원시 중첩 페이로드가 아닌 재구성 가능한 반평탄화된 형태로 저장합니다.
효율적인 매칭을 위해 경로를 인코딩 및 역순 변환: AQL 구조 경로를 압축된 역순 토큰으로 변환하여
CONTAINS가 접두사 기반 조건에 매핑될 수 있도록 합니다.범위별 AQL 라우팅:
ehr_id를 사용하여 개별 환자 단위 쿼리는 로컬에서 처리하고 필요에 따라 다수 환자 대상 쿼리는 Atlas Search로 전송합니다.규모에 따른 컬렉션 수량(1개 또는 2개) 선택: 단일 반평탄화 컬렉션으로도 충분할 수 있지만 대규모 리포지토리는 간소화된 검색 프로젝션을 사용하는 것이 유리합니다.
단일 운영 쿼리 접점 유지: 런타임이 결정론적 컴파일 및 실행 계획을 처리하므로 애플리케이션 팀은 AQL 인터페이스를 그대로 사용할 수 있습니다.
작성자
Francesc Mateu Amengual, MongoDB
Giovanni Rodriguez, MongoDB
Greg Cox, MongoDB
Juan Crossley, MongoDB
자세히 알아보기
openEHR 표준 확인