Có CDM rồi mới chỉ là điểm khởi đầu. Để khai thác giá trị cần bộ tooling: ATLAS (cohort + characterization UI), DQD (chất lượng dữ liệu), ACHILLES (profiling). Bài viết hướng dẫn cài và vận hành.
1. Stack analytics OHDSI

Tất cả chạy được trong Docker compose qua Broadsea.
2. Broadsea — deploy 1 lệnh
git clone https://github.com/OHDSI/Broadsea
cd Broadsea
cp .env.example .env
# Sửa .env: Postgres connection, ATLAS port, security
docker compose --profile default up -d
# Truy cập:
# - ATLAS: http://localhost/atlas
# - WebAPI: http://localhost/WebAPI
# - HADES R Studio: http://localhost:8787
Service trong Broadsea:
broadsea-webtools— ATLAS + WebAPIbroadsea-hades— RStudio Server với HADES preinstalledbroadsea-content— Atlas content portalohdsi-postgresql— DB cho WebAPI
3. ATLAS
3.1 Tính năng chính

3.2 Workflow tạo cohort
Ví dụ: "Bệnh nhân Diabetes Type 2 mới được chẩn đoán năm 2026 và bắt đầu Metformin"

UI trong ATLAS giúp click drag không cần SQL → output ra cohort table chuẩn OMOP.
3.3 Export Cohort SQL
ATLAS tự generate SQL chuẩn OHDSI Circe:
-- Generated by Atlas
INSERT INTO cohort (cohort_definition_id, subject_id, cohort_start_date, cohort_end_date)
SELECT 1, person_id, condition_start_date, ...
FROM condition_occurrence co
JOIN concept_ancestor ca ON co.condition_concept_id = ca.descendant_concept_id
WHERE ca.ancestor_concept_id = 201826
AND condition_start_date >= '2026-01-01'
...
→ Có thể version control, chạy CLI ngoài ATLAS.
3.4 Characterization
Sau khi có cohort → chạy Characterization để mô tả:
- % gender, age stratify
- Top comorbid (top 100 condition trong 365 ngày trước index)
- Top drug
- Top procedure
- Lab values
→ output bảng + Forest plot. Đặc biệt mạnh khi compare 2 cohort (vd Metformin vs SGLT2 first-line).
4. ACHILLES
ACHILLES = R package profile mọi cột trong CDM, ra ~170 analysis ID:
- Number of person, gender, race, year of birth distribution
- Visit count by type
- Top conditions, drugs, procedures, measurements
- Time series: monthly count
- Heel: outlier flag (vd "year_of_birth = 1850 detected")
library(Achilles)
achilles(
connectionDetails = connectionDetails,
cdmDatabaseSchema = "cdm",
resultsDatabaseSchema = "results",
vocabDatabaseSchema = "cdm",
numThreads = 4
)
Sau khi chạy → bảng achilles_results, achilles_results_dist, achilles_heel_results.
ATLAS có tab "Data Sources" hiển thị ACHILLES result trực quan — đây là bảng giới thiệu data partner cho researcher.
5. Data Quality Dashboard (DQD)
3000+ rule chia 3 nhóm Kahn:
| Loại | Mô tả | Ví dụ |
|---|---|---|
| Conformance | Data đúng kiểu, format, value set | gender_concept_id ∈ {0, 8507, 8532} |
| Completeness | Tỷ lệ NULL chấp nhận được | < 5% person.year_of_birth NULL |
| Plausibility | Giá trị hợp lý lâm sàng | HbA1c không > 20% |
5.1 Chạy DQD
library(DataQualityDashboard)
executeDqChecks(
connectionDetails = connectionDetails,
cdmDatabaseSchema = "cdm",
resultsDatabaseSchema = "results",
cdmSourceName = "BV ABC OMOP CDM",
outputFolder = "dqd_results",
cdmVersion = "5.4"
)
# Generate viewer
viewDqDashboard("dqd_results/results.json")
Output:
- HTML dashboard tương tác
- JSON với mỗi check + pass/fail/threshold
5.2 Đọc DQD
Mỗi check có:
category: conformance / completeness / plausibilitysubcategory: vd "valueLow", "valueHigh"level: TABLE / FIELD / CONCEPTseverity: error / warning / notificationpct_records_violating: % vi phạmthreshold: ngưỡng chấp nhậnpass/fail

5.3 Pattern xử lý
Khi DQD fail:
- Đọc check description
- Identify root cause (source data lỗi vs ETL lỗi vs threshold quá strict)
- Fix ETL hoặc tăng threshold (nếu lý do hợp lý)
- Re-run DQD
- Document quyết định trong ETL spec
5.4 Custom check
DQD cho phép thêm rule riêng:
# custom_checks.csv
checkName: VN_BHYT_coverage
checkDescription: > 90% person có ít nhất 1 PAYER_PLAN_PERIOD = BHYT
queryText: |
SELECT (1.0 - SUM(CASE WHEN p.person_id IS NOT NULL THEN 1 ELSE 0 END) / COUNT(*)) AS pct_violation
FROM person ps
LEFT JOIN payer_plan_period p ON ps.person_id = p.person_id
AND p.payer_concept_id = 2000010001 -- VN custom BHYT
threshold: 0.10
severity: warning
6. CI/CD tích hợp DQD
# .github/workflows/dqd.yml
name: OMOP DQ Weekly
on:
schedule:
- cron: '0 3 * * 1' # Monday 3AM
jobs:
dqd:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- run: Rscript scripts/run_dqd.R
- name: Upload result
uses: actions/upload-artifact@v4
with:
name: dqd-${{ github.run_id }}
path: dqd_results/
- name: Fail on critical errors
run: |
jq '.Overview | select(.numFailed > 0)' dqd_results/results.json && exit 1 || exit 0
7. Stack production thực tế
| Component | Spec gợi ý |
|---|---|
| Postgres CDM | 16 vCPU, 64 GB RAM, 2 TB SSD, partition by year |
| WebAPI | 4 vCPU, 8 GB RAM, JVM heap 4GB |
| ATLAS Web | 2 vCPU, 4 GB RAM (chỉ static) |
| ACHILLES | 8 vCPU, 16 GB RAM, lifetime 4-12h cho dataset 10M person |
| DQD | 8 vCPU, 16 GB RAM, 2-6h tuỳ rule scope |
| HADES R Studio | 16 vCPU, 32 GB RAM cho PLP training |
Backup: snapshot CDM hàng đêm, ACHILLES result hàng tuần.
8. Security ATLAS
ATLAS mặc định không có auth → KHÔNG deploy public không che. Setup:
- LDAP / AD integration qua WebAPI
- HTTPS với reverse proxy (NGINX)
- Audit log mọi cohort generate
- Row-level security cho data partner sensitive
9. Multi-tenant pattern

WebAPI hỗ trợ multi-source — researcher chọn source qua dropdown. Permission per user/source.
10. Network deployment cho VN

Pattern federated: dữ liệu ở lại BV, chỉ aggregate result đi lên.
11. Pitfall
- ❌ Cohort không dùng
concept_ancestor→ thiếu biến thể bệnh - ❌ Generate cohort không kiểm tra inclusion rule overlap → nhân đôi
- ❌ Bỏ qua DQD warning → analytic publish bị reviewer reject
- ❌ Không re-run ACHILLES sau ETL refresh → ATLAS show số cũ
- ❌ Public ATLAS không auth → leak metadata bệnh nhân
- ❌ Quên backup
webapi.cohort_definition→ mất công định nghĩa cohort
Kết luận
ATLAS + DQD + ACHILLES là 3 trụ vận hành OMOP. Broadsea giúp deploy 1 lệnh. Đầu tư DQ gate vào CI/CD ngay từ đầu — đỡ tốn rất nhiều khi muốn publish nghiên cứu.
Bài tiếp: HADES Analytics — PLE, PLP, Characterization với R.



