Terminology Binding: CodeSystem, ValueSet, ConceptMap trong FHIR
Mọi field code trong FHIR (Condition.code, Observation.code, Patient.gender) đều ràng buộc tới một ValueSet — đó là cách FHIR đảm bảo mỗi mã chỉ có một ý nghĩa duy nhất giữa bệnh viện này và bệnh viện kia. ValueSet lấy mã từ CodeSystem (ICD-10 VN, SNOMED CT, LOINC), còn ConceptMap dùng để dịch giữa hai hệ thống mã. VN Core đang xây trên 12 CodeSystem riêng cho thực tế y tế Việt Nam.
Đối tượng: DEV, Vendor, Regulator — đã quen FHIR base, đang gặp lỗi "code not in valueset" hoặc cần hiểu vì sao chuẩn hóa terminology là điều kiện sống còn của interoperability.
Tóm tắt nhanh
- CodeSystem là bộ mã gốc có URL canonical, ví dụ ICD-10 VN, SNOMED CT, LOINC, dân tộc 54.
- ValueSet là tập con (compose) của một hoặc nhiều CodeSystem, dùng để bind vào một field cụ thể.
- ConceptMap là ánh xạ giữa hai hệ thống mã, ví dụ ICD-10 VN sang ICD-10 WHO, hoặc XML 4210 sang FHIR.
- NamingSystem đăng ký URI cho identifier (CCCD, BHYT, BHXH, MRN bệnh viện), không phải cho clinical code.
- Binding strength có 4 mức:
required,extensible,preferred,example— quyết định mức độ ràng buộc của ValueSet với field.
Nội dung trang
- Bốn khái niệm cốt lõi: CodeSystem, ValueSet, ConceptMap, NamingSystem
- Coding và CodeableConcept: vì sao luôn cần text
- Binding strength: required, extensible, preferred, example
- ValueSet — composition và expansion
- Operations: $expand, $validate-code, $lookup, $translate
- Terminology server: tự host hay dùng dịch vụ ngoài
- VN Core terminology landscape — 12+ CodeSystem
- Khi nào tự tạo CodeSystem, khi nào tái sử dụng chuẩn quốc tế
- Câu hỏi thường gặp
- Đọc tiếp
1. Bốn khái niệm cốt lõi
FHIR Terminology Module (R4 §3.6) chia tài nguyên quản lý mã làm bốn nhóm: CodeSystem định nghĩa bộ mã gốc, ValueSet chọn ra tập con dùng được, ConceptMap dịch giữa các hệ thống mã, và NamingSystem đăng ký URI định danh. Hiểu rõ phân vai này là điều kiện cần để đọc bất kỳ Implementation Guide nào, từ US Core, JP Core đến VN Core.
CodeSystem — bộ mã gốc
CodeSystem là tài nguyên định nghĩa chính xác mã nào tồn tại và mỗi mã nghĩa là gì. Mỗi CodeSystem có một URL canonical duy nhất toàn cầu, đóng vai trò định danh bộ mã. VN Core dùng quy ước http://fhir.hl7.org.vn/core/CodeSystem/ kèm hậu tố -cs, ví dụ vn-ethnicity-cs cho danh mục 54 dân tộc Việt Nam hoặc vn-icd10-cs cho ICD-10 phiên bản Việt Nam.
{
"resourceType": "CodeSystem",
"url": "http://fhir.hl7.org.vn/core/CodeSystem/vn-ethnicity-cs",
"version": "1.0.0",
"name": "VNEthnicity",
"title": "Dân tộc Việt Nam",
"status": "active",
"content": "complete",
"concept": [
{ "code": "01", "display": "Kinh" },
{ "code": "02", "display": "Tày" },
{ "code": "03", "display": "Thái" }
]
}
Trường content chỉ ra mức độ đầy đủ của resource: complete (toàn bộ mã đều có trong resource), fragment (chỉ một phần), example (minh họa), hoặc not-present (chỉ định nghĩa metadata, mã ở nơi khác — phù hợp cho những bộ mã rất lớn như SNOMED CT).
ValueSet — tập con dùng được
ValueSet không chứa mã mới; nó chọn ra tập con từ một hoặc nhiều CodeSystem để bind vào một field. Một CodeSystem có thể sinh nhiều ValueSet khác nhau tuỳ ngữ cảnh. Ví dụ ICD-10 VN có hơn 14.000 mã, nhưng ValueSet cho chẩn đoán nhi khoa hay ValueSet bệnh truyền nhiễm chỉ chọn vài trăm mã liên quan.
{
"resourceType": "ValueSet",
"url": "http://fhir.hl7.org.vn/core/ValueSet/vn-ethnicity-vs",
"version": "1.0.0",
"name": "VNEthnicityVS",
"status": "active",
"compose": {
"include": [
{
"system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-ethnicity-cs"
}
]
}
}
Lưu ý FHIR R4 yêu cầu trường status là bắt buộc (cardinality 1..1) cho cả CodeSystem, ValueSet, ConceptMap và NamingSystem. Bỏ quên status sẽ khiến validator báo lỗi ngay.
ConceptMap — ánh xạ giữa hai hệ
ConceptMap mô tả mối quan hệ giữa các mã của hai hệ thống. Ứng dụng phổ biến tại Việt Nam là chuyển đổi giữa ICD-10 VN và ICD-10 WHO, hoặc dịch các trường XML 4210 (chuẩn dữ liệu BHYT) sang Claim/Coverage/EOB của FHIR. Trong R4, sourceUri và targetUri là phạm vi của mapping (thường là URL ValueSet), còn cụm group.source và group.target mới chứa URL CodeSystem cụ thể.
{
"resourceType": "ConceptMap",
"url": "http://fhir.hl7.org.vn/core/ConceptMap/vn-icd10-to-who",
"version": "1.0.0",
"name": "VNICD10ToWHO",
"status": "active",
"sourceUri": "http://fhir.hl7.org.vn/core/ValueSet/vn-icd10-vs",
"targetUri": "http://hl7.org/fhir/ValueSet/icd-10",
"group": [
{
"source": "http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs",
"target": "http://hl7.org/fhir/sid/icd-10",
"element": [
{
"code": "I10.0",
"target": [
{ "code": "I10", "equivalence": "wider" }
]
}
]
}
]
}
Trường equivalence nhận các giá trị như equal, equivalent, wider, narrower, inexact, unmatched — phản ánh mức độ tương đương ngữ nghĩa, không chỉ map "1-1".
NamingSystem — đăng ký URI cho identifier
NamingSystem khác với ba tài nguyên trên: nó không quản lý mã lâm sàng mà đăng ký URI cho hệ thống định danh. CCCD, số thẻ BHYT, mã BHXH, MRN bệnh viện đều là identifier system, mỗi cái cần một URI duy nhất để Patient.identifier có thể trỏ tới.
{
"resourceType": "NamingSystem",
"name": "VNCCCD",
"status": "active",
"kind": "identifier",
"date": "2026-04-30",
"uniqueId": [
{
"type": "uri",
"value": "http://fhir.hl7.org.vn/core/sid/cccd",
"preferred": true
}
]
}
Quy ước VN Core dùng http://fhir.hl7.org.vn/core/sid/{cccd|bhyt|bhxh|gks|passport}. Lưu ý NamingSystem cũng yêu cầu cả status và date.
2. Coding và CodeableConcept
Hai datatype thường gây nhầm lẫn nhất khi mới tiếp cận FHIR. Coding là một mã đơn lẻ gồm system, version, code, display. CodeableConcept bao gồm một mảng nhiều Coding cùng nghĩa, kèm trường text chứa diễn giải tự do.
"code": {
"coding": [
{
"system": "http://hl7.org/fhir/sid/icd-10",
"version": "2019",
"code": "I10",
"display": "Essential hypertension"
},
{
"system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs",
"code": "I10.0",
"display": "Tăng huyết áp vô căn"
}
],
"text": "Tăng huyết áp"
}
Cùng một chẩn đoán có thể được code hoá song song bằng ICD-10 WHO và ICD-10 VN. Best practice mạnh mẽ nhất từ HL7: luôn điền trường text, kể cả khi đã có nhiều coding. Lý do: bác sĩ ghi diễn giải bằng tiếng Việt trên giao diện EMR thường không khớp tuyệt đối với display chuẩn của bộ mã, và khi mã trở nên lỗi thời (deprecated), trường text vẫn giữ lại ý định ban đầu của người ghi chép.
Quy tắc thực dụng: nếu chỉ dùng được một trong hai, hãy chọn CodeableConcept. Trường text luôn đứng vững khi bộ mã thay đổi, còn coding giúp máy hiểu được.
3. Binding strength: bốn mức ràng buộc
Khi một field FHIR được bind tới một ValueSet, Implementer phải biết mức ràng buộc đến đâu. HL7 R4 định nghĩa bốn mức theo trang Terminology — Binding (hl7.org/fhir/R4/terminologies.html#strength):
| Strength | Ý nghĩa | Ví dụ FHIR R4 base |
|---|---|---|
required | Mã phải nằm trong ValueSet. Validator báo lỗi nếu nằm ngoài. Không cho phép text-only. | Patient.gender bind tới AdministrativeGender (male/female/other/unknown). |
extensible | Nếu khái niệm đã có trong ValueSet thì phải dùng mã đó. Chỉ được mở rộng bằng mã ngoài khi ValueSet không cover khái niệm cần ghi. | Patient.maritalStatus bind extensible tới MaritalStatus. Profile downstream có thể siết chặt. |
preferred | Khuyến nghị dùng ValueSet, nhưng không bắt buộc. Validator chỉ cảnh báo. | Encounter.serviceType bind preferred tới ServiceType. |
example | ValueSet chỉ minh hoạ một bộ mã có thể dùng. Không có tính ràng buộc. | Condition.code trong R4 base bind example tới Condition/Problem/Diagnosis Codes. |
Một profile (như VN Core) hoàn toàn có thể siết chặt binding strength so với base. Ví dụ R4 base bind Condition.code ở mức example, nhưng VN Core có thể profile lại thành extensible với ValueSet ICD-10 VN, buộc các hệ thống ưu tiên dùng mã ICD-10 VN trừ khi không có mã phù hợp.
Lưu ý quan trọng: extensible nghiêm khắc hơn preferred. Nếu khái niệm cần ghi đã có trong ValueSet mà người dùng cố tình điền mã khác hoặc chỉ điền text, validator sẽ báo lỗi. preferred chỉ đưa ra khuyến nghị mà không có cơ chế cưỡng chế.
4. ValueSet — composition và expansion
ValueSet có hai mặt: composition (định nghĩa cách chọn) và expansion (kết quả expand ra danh sách mã thực tế).
Composition — định nghĩa
Phần compose của ValueSet liệt kê các nguyên tắc chọn mã: include chọn tập hợp, exclude loại trừ. Có thể chọn theo filter trên thuộc tính của CodeSystem (ví dụ: tất cả mã con của một parent, tất cả mã có status = active).
ValueSet: VNEncounterTypeVS
Id: vn-encounter-type-vs
Title: "Loại lượt khám"
Description: "Phân loại lượt khám theo TT 13/2025/TT-BYT"
* ^status = #active
* include codes from system VNEncounterTypeCS where status = #active Expansion — kết quả
Khi terminology server expand ValueSet (qua operation $expand), kết quả là danh sách phẳng các mã thực tế:
{
"resourceType": "ValueSet",
"url": "http://fhir.hl7.org.vn/core/ValueSet/vn-encounter-type-vs",
"status": "active",
"expansion": {
"timestamp": "2026-04-30T10:00:00+07:00",
"contains": [
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "OUTPATIENT", "display": "Ngoại trú" },
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "INPATIENT", "display": "Nội trú" },
{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-encounter-type-cs", "code": "EMERGENCY", "display": "Cấp cứu" }
]
}
} Tách rời composition và expansion là một thiết kế quan trọng: composition ổn định trong IG, expansion có thể được terminology server tính lại bất cứ lúc nào khi CodeSystem cập nhật. Ví dụ ValueSet chẩn đoán theo ICD-10 VN sẽ tự động bao gồm các mã mới khi Bộ Y tế ban hành quyết định bổ sung.
5. Operations: $expand, $validate-code, $lookup, $translate
FHIR định nghĩa năm operation chính cho terminology, mọi terminology server tuân thủ đều phải hỗ trợ:
$expandtrên ValueSet — trả về danh sách mã thực tế. Hỗ trợ filter, paging, ngôn ngữ.$validate-codetrên ValueSet hoặc CodeSystem — kiểm tra một mã có hợp lệ trong ngữ cảnh không.$lookuptrên CodeSystem — tra display, designation đa ngôn ngữ, properties của một mã.$translatetrên ConceptMap — áp dụng mapping để dịch mã từ hệ này sang hệ khác.$subsumestrên CodeSystem — kiểm tra quan hệ cha-con giữa hai mã (subsumption).
GET /ValueSet/vn-ethnicity-vs/$expand
GET /CodeSystem/vn-icd10-cs/$lookup?code=I10.0
GET /CodeSystem/vn-icd10-cs/$validate-code?code=I10.0
POST /ConceptMap/vn-icd10-to-who/$translate?code=I10.0&system=http://fhir.hl7.org.vn/core/CodeSystem/vn-icd10-cs
Trong thực tế triển khai EMR: validator thường gọi $validate-code mỗi khi bác sĩ chọn mã từ dropdown; UI gọi $expand để render dropdown; cổng tích hợp BHYT có thể gọi $translate để chuyển ICD-10 VN nội bộ sang format mà BHXH chấp nhận.
6. Terminology server
Terminology server là dịch vụ chuyên biệt phục vụ các operation trên. Một số lựa chọn phổ biến:
- Ontoserver (CSIRO, Úc) — sản phẩm thương mại trưởng thành, mạnh về SNOMED CT, được dùng trong AU Core và NHS.
- HAPI FHIR JPA Server — open source, có module terminology đầy đủ, phù hợp triển khai trong nước.
- Snowstorm (SNOMED International) — open source, thiết kế chuyên biệt cho SNOMED CT.
- tx.fhir.org — terminology server công cộng do HL7 vận hành, dùng cho test và validate IG.
Định hướng VN Core: trong giai đoạn đầu sẽ dùng tx.fhir.org cho test, đồng thời lên kế hoạch tự host tại terminology.hl7.org.vn để đảm bảo data residency theo Luật An ninh mạng (Luật 24/2018/QH14) và Luật Bảo vệ dữ liệu cá nhân (Luật 91/2025/QH15). Đây là mô hình tham chiếu — chờ thiết kế hạ tầng cụ thể được công bố.
7. VN Core terminology landscape
Bộ terminology của VN Core được tổ chức theo hai trục: tái sử dụng chuẩn quốc tế (ICD-10, LOINC, SNOMED CT) và xây mới các CodeSystem đặc thù Việt Nam (dân tộc, BHYT, đơn vị hành chính, hạng bệnh viện). Mỗi mã trong CodeSystem được kèm căn cứ pháp lý cụ thể (Thông tư, Quyết định, Nghị định) — đây là yêu cầu bắt buộc đã được ghi nhận trong CONTRIBUTING.
| Bộ mã | CodeSystem ID | Số mã | Văn bản pháp lý |
|---|---|---|---|
| ICD-10 VN | vn-icd10-cs | ~14.000 | QĐ 4469/QĐ-BYT (28/10/2020) |
| ICD-10 COVID-19 | vn-icd10-covid-cs | 2 (U07.1, U07.2) | QĐ 98/QĐ-BYT (14/01/2022) |
| ICD-9-CM 2026 | vn-icd9cm-cs | ~3.000 | QĐ 387/QĐ-BYT (05/02/2026) |
| Dân tộc Việt Nam | vn-ethnicity-cs | 54 | Tổng cục Thống kê |
| Đơn vị hành chính | vn-admin-division-cs | ~3.355 (34 tỉnh + 3.321 xã) | QĐ 19/2025/QĐ-TTg (NQ 202/2025/QH15) |
| BHYT đối tượng | vn-bhyt-subject-cs | ~30 | QĐ 3276/QĐ-BYT (17/10/2025) |
| KCB tuyến (mô hình 2 cấp) | vn-kcb-line-cs | 3 (TW / Tỉnh / Xã) | NQ 202/2025/QH15 |
| Hạng cơ sở KCB | vn-hospital-rank-cs | 4 hạng | TT 06/2024/TT-BYT (16/05/2024) |
| LOINC partial (CLS đợt 1) | vn-loinc-cs | 2.964 | QĐ 1227/QĐ-BYT (11/04/2025) |
| SNOMED CT VN đợt 1-3 | vn-snomed-ct-cs | Hàng nghìn concept | QĐ 2427/QĐ-BYT (25/07/2025), QĐ 2493/QĐ-BYT (08/2025), QĐ 2805/QĐ-BYT (04/09/2025) |
| YHCT thuật ngữ | vn-yhct-cs | Hàng nghìn thuật ngữ | QĐ 2552/QĐ-BYT (12/08/2025), QĐ 3080/QĐ-BYT (26/09/2025) |
| Văn bản pháp lý tham chiếu | vn-legal-doc-ref-cs | 101 entries | Do dự án VN Core tổng hợp và duy trì |
ICD-10 VN khác bản WHO chủ yếu ở chỗ Việt Nam đã mở rộng nhánh phân loại 4-5 ký tự cho một số bệnh phổ biến trong nước, ví dụ I10.0 (Tăng huyết áp vô căn) và I10.1 mà bản WHO chỉ giữ I10. Vì vậy, ConceptMap từ ICD-10 VN sang ICD-10 WHO thường là quan hệ wider (mã VN hẹp hơn, cha của nó ở WHO rộng hơn).
Riêng SNOMED CT đặt ra bài toán giấy phép: Việt Nam chưa là thành viên SNOMED International, nên ba đợt QĐ 2427/2493/2805 chỉ ban hành mã ánh xạ (mapping) chứ không trực tiếp cấp quyền sử dụng SNOMED CT toàn bộ. Các tổ chức cần triển khai SNOMED CT đầy đủ vẫn phải đàm phán quốc gia membership hoặc affiliate license riêng.
8. Khi nào tự tạo CodeSystem
Một sai lầm phổ biến của các dự án mới là tự tạo CodeSystem riêng cho mọi thứ, dẫn tới phân mảnh terminology và mất khả năng interoperate. Quy tắc chung từ HL7 Vocabulary Working Group:
Không tự tạo nếu
- Đã có chuẩn quốc tế phù hợp (ICD-10, LOINC, SNOMED CT, ATC, ISO 3166).
- Có CodeSystem trong FHIR core hoặc terminology.hl7.org đã cover (AdministrativeGender, MaritalStatus, ContactPointSystem).
- Đã có IG khu vực mạnh (US Core, JP Core) định nghĩa CodeSystem reusable.
Nên tự tạo khi
- Khái niệm là VN-specific: 54 dân tộc, đối tượng BHYT, tuyến KCB sau NQ 202/2025, hạng bệnh viện theo TT 06/2024.
- Văn bản pháp lý Việt Nam ban hành code list cụ thể (Quyết định Bộ Y tế, Thông tư BYT, Quyết định Tổng cục Thống kê).
- Bộ mã quốc tế thiếu một số nhánh chi tiết mà thực tế Việt Nam cần (ví dụ ICD-10 VN mở rộng so với ICD-10 WHO).
- Cần một CodeSystem internal cho IG (ví dụ
VNLegalDocumentRefCSđể tham chiếu văn bản pháp lý từ profile và extension).
Khi đã quyết định tự tạo, ba nguyên tắc cứng:
- Mỗi mã phải kèm căn cứ pháp lý cụ thể trong concept property hoặc designation, để truy vết về Thông tư/Quyết định gốc.
- Versioning rõ ràng: khi văn bản pháp lý sửa đổi, phải tăng version CodeSystem và đánh dấu mã cũ
status = deprecatedhoặcretirement-date. - URL canonical theo pattern
http://fhir.hl7.org.vn/core/CodeSystem/vn-{domain}-cskhông thay đổi.
9. Câu hỏi thường gặp
Có thể bind cùng lúc nhiều ValueSet vào một field không?
FHIR R4 chỉ cho phép một binding chính trên mỗi element. Tuy nhiên, vì CodeableConcept.coding là mảng, một field có thể chứa nhiều Coding từ nhiều CodeSystem khác nhau, miễn là tất cả cùng diễn đạt một khái niệm. Đây là cơ chế chuẩn để vừa code ICD-10 VN vừa code SNOMED CT trên cùng một Condition.code.
ICD-10 VN khác ICD-10 WHO ở đâu?
ICD-10 VN ban hành theo QĐ 4469/QĐ-BYT (28/10/2020) mở rộng nhánh phân loại 4-5 ký tự cho một số bệnh đặc trưng tại Việt Nam, đồng thời bổ sung mã COVID-19 (U07.1, U07.2) qua QĐ 98/QĐ-BYT. Mã cấp 3 (3 ký tự) gần như tương đương WHO; sai biệt chỉ xảy ra ở cấp chi tiết hơn.
Có bắt buộc mua giấy phép SNOMED CT không?
Việt Nam chưa là thành viên SNOMED International nên hiện chưa có quyền sử dụng SNOMED CT toàn diện theo dạng quốc gia membership. Ba đợt QĐ 2427/2493/2805 năm 2025 chỉ ban hành các mã mapping VN-SNOMED CT cho một số nhánh (Body Structure, Morphologic Abnormality, Allergy + Finding). Các tổ chức cần dùng SNOMED CT toàn bộ phải đàm phán affiliate license riêng với SNOMED International.
NamingSystem có thay thế CodeSystem được không?
Không. NamingSystem chỉ đăng ký URI cho identifier system (CCCD, BHYT, BHXH, MRN), không quản lý mã lâm sàng. Nhầm lẫn này là nguyên nhân thường gặp khiến validator báo lỗi: Patient.identifier.system phải là URI đã đăng ký qua NamingSystem; còn Condition.code.coding.system phải trỏ tới URL canonical của một CodeSystem.
Tài liệu tham chiếu
- HL7 FHIR R4 — Terminology Module: hl7.org/fhir/R4/terminology-module.html
- HL7 FHIR R4 — Binding strength: hl7.org/fhir/R4/terminologies.html#strength
- HL7 FHIR R4 — CodeSystem definitions: hl7.org/fhir/R4/codesystem-definitions.html
- HL7 FHIR R4 — ValueSet definitions: hl7.org/fhir/R4/valueset-definitions.html
- HL7 FHIR R4 — ConceptMap definitions: hl7.org/fhir/R4/conceptmap-definitions.html
- HL7 FHIR R4 — NamingSystem definitions: hl7.org/fhir/R4/namingsystem-definitions.html
- QĐ 4469/QĐ-BYT (28/10/2020) — ICD-10 phiên bản Việt Nam.
- QĐ 98/QĐ-BYT (14/01/2022) — Bổ sung mã COVID-19 vào ICD-10 VN.
- QĐ 1227/QĐ-BYT (11/04/2025) — Danh mục mã chỉ số cận lâm sàng đợt 1 (LOINC mapping).
- QĐ 2427/QĐ-BYT (25/07/2025) — SNOMED CT VN đợt 1, Body Structure.
- QĐ 2493/QĐ-BYT (08/2025) — SNOMED CT VN đợt 2, Morphologic Abnormality.
- QĐ 2805/QĐ-BYT (04/09/2025) — SNOMED CT VN đợt 3, Allergy và Finding.
- QĐ 387/QĐ-BYT (05/02/2026) — Bảng phân loại ICD-9-CM bản 2026.
- NQ 202/2025/QH15 (12/06/2025) — Sắp xếp đơn vị hành chính cấp tỉnh.
- TT 06/2024/TT-BYT (16/05/2024) — Phân hạng cơ sở KCB (4 hạng).
- Snowstorm SNOMED CT terminology server: github.com/IHTSDO/snowstorm
- Ontoserver (CSIRO): ontoserver.csiro.au