ในช่วงสัปดาห์ที่ผ่านมา ผมพยายามทำความเข้าใจและหาข้อสรุปให้ตนเองว่าเวลาเราทำ FHIR Profile เมื่อไหร่ควรใช้ fixed value และเมื่อไหร่ควรใช้ fixed pattern ก็เลยลองดูตัวอย่างจากใน US-Core และ International Patient Summary (IPS) มาครับ สรุปว่าทั้งสอง implementation guide (IG) ทำแบบนี้ครับ
(Cover Photo by Praewthida K on Unsplash)
1. ใช้ fixed value น้อย
ส่วนใหญ่จะใช้ fixedCode หรือ fixedUri สำหรับ data type ต่าง ๆ ที่มีการใช้ code, system
US-Core มีใช้แค่ 2 ที่
- Vital Signs Profile โดยใช้ใน slicing ของ Observation.category และ profile ย่อยอื่น ๆ ในกลุ่มนี้ก็ derive ไปจาก profile นี้ (จริง ๆ อันนี้ก็เป็นวิธี slice เดียวกันกับ vital signs profile ของ FHIR core)
- ใช้ในการระบุ code และ system ของ Quantity ใน Observation ส่วนใหญ่ก็คือ vital signs profile และลูก ๆ นี่แหละครับ เช่นด้านล่างนี้คือ blood pressure profile ส่วน diastolic
IPS มีใช้แค่ 2 ที่เช่นกัน
- ใช้ในการระบุ status ของในหลาย ๆ profile เช่น DiagnosticReport, Media, Observation
- ใช้ในการระบุ system ของ profile ของ datatype Quantity และ SimpleQuantity
2. ใช้ pattern เป็นหลักในการ discriminate แล้ว fixed pattern ใน slice
ถ้าลองดูในทั้งสอง IG จะเห็นว่าเขาไปท่านี้เยอะมาก แต่โดยหลัก ๆ ก็มี data type อยู่ 3 ประเภทที่เขาจะ fixed pattern ได้แก่
- CodeableConcept อันนี้พบบ่อยที่สุดแล้ว เช่น ใน Provenance profile นี้ จะเห็นว่า type เป็น CodeableConcept ที่แต่ละ slice จะมีการบังคับ coding อย่างน้อย 1 element (ข้างในก็จะมี system และ code)
ถ้าไปดูที่ element หลัก จะพบว่า slice ด้วย pattern โดยมี path เป็น type (จะกล่าวถึงในหัวข้อถัดไป)
- Identifier เป็นอันที่พบบ่อยรองลงมา เช่น Practitioner, Organization เช่น ด้านล่างนี้จะเห็นว่า slice ของ NPI บังคับ pattern โดยกำหนดค่าของ system
คำถามที่ผมยังต้องหาคำตอบเพิ่ม -> การทำ fixed pattern ใน slice ของ identifier แบบนี้ ต่างอย่างไรกับการทำ fixed value ใส่ element ลูกของ slice ? เช่น แทนที่เราจะไป fixed pattern ที่ Practitioner.identifier:NPI เราก็ไป fixed value ที่ Practitioner.identifier:NPI.system เลยได้หรือไม่ โดยไม่ต้อง fixed pattern
- Coding อันนี้ผมเห็นแค่ที่เดียวคือที่ US Core Pulse Oximetry Profile เป็นการ fix Coding สองค่า ภายใน element ที่เป็น CodeableConcept
เสริม: discriminator ที่ใช้ในทั้งสอง IG
น่าสนใจว่าทั้งสอง IG เลือกใช้ discriminator หลัก ๆ แค่ 3 แบบนี้เท่านั้น (ไม่รวม value ใน vital signs)
pattern
เนื่องจากข้อมูลที่แลกเปลี่ยนใน FHIR ส่วนใหญ่มักจะเป็น CodeableConcept ซึ่งพอเป็น data type นี้ เขาจึงมักจะเลือกใช้ discriminator เป็น pattern ดังที่ได้กล่าวไปก่อนหน้านี้ และโดยส่วนใหญ่มักจะใช้ path เป็น $this ด้วยครับ เพราะ slice ที่ตัว element เอง เช่น Observation.category อันนี้ สังเกตว่า slice by pattern ที่ path คือ $this

หรือลองดู IPS Immunization นี้ก็ได้ครับ จะเห็นว่า vaccineCode และ protocolApplied.targetDisease ก็ slice ด้วย pattern ที่ path คือ $this

type
มักใช้กับพวกที่เลือก data type ได้หลายแบบ เช่น Observation.value[x] หรือ Medication.ingredient.item[x]


คำถามที่ผมยังตอบไม่ได้: data พวกนี้มี maximum cardinality เป็น 1 (มีได้ค่าเดียว) ทำไมถึงเลือกทำ slice แล้วค่อยมาจำกัด type เอาใน slice แทนที่จะจำกัด type ตั้งแต่ element หลักเลย
profile
อันนี้มีใช้ใน IPS 2 ที่ ได้แก่ DiagnosticReport และ Composition.section.entry น่าสนใจเหมือนกันว่าทำไมถึงเลือกใช้วิธีนี้ อีกอย่างคือ US-Core ก็ไม่ได้มี profile ไหนที่ใช้วิธีนี้
หมายเหตุ: ใน FHIR spec แบบว่าการ discriminate ด้วยวิธีนี้ต้องใช้ process สูงสุด (reference)


ก็หมดแล้วครับ ผมว่าก็พอได้ไอเดียว่าถ้าทำ profile เองควรจะทำแบบไหน กล่าวโดยสรุปคือ
- ถ้าจะทำ slicing เน้นใช้ pattern เป็น discriminator แล้วก็ไป fixed pattern ใน slice (หลัก ๆ คือ CodeableConcept กับ Identifier)
- พวก primitive value ใช้ fixed value ได้ รวมถึงพวก system, code ของ Quantity
- เรื่อง discriminate ด้วย type กับ profile นี่ผมยังไม่ค่อยแม่น
ส่วนพวกคำถามที่ผมติดค้างไว้เดี๋ยวไว้ได้คำตอบแล้วมาแชร์ครับ