Document ontology done

This commit is contained in:
James Agnew 2018-03-11 10:02:13 -05:00
parent a5a7d75e58
commit b9802d0101
4 changed files with 48 additions and 21 deletions

View File

@ -47,6 +47,10 @@ RSNA Playbook
equivalent (or would they be wider/narrower). They look equivalent to me. equivalent (or would they be wider/narrower). They look equivalent to me.
Document Ontology Document Ontology
- Per the SOW, "A value set containing terms in the LOINC Document Ontology
will be created". Just to confirm, entries in this ValueSet are therefore
LOINC terms (such as "11488-4 / Consultation Note") as opposed to part
codes?
- Need to define a URI for the document ontology ValueSet. Currently I am - Need to define a URI for the document ontology ValueSet. Currently I am
using "http://loinc.org/document-ontology-codes" using "http://loinc.org/document-ontology-codes"

View File

@ -6,14 +6,11 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler; import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import java.util.*; import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincDocumentOntologyHandler implements IRecordHandler { public class LoincDocumentOntologyHandler implements IRecordHandler {
@ -26,7 +23,7 @@ public class LoincDocumentOntologyHandler implements IRecordHandler {
private final Set<String> myPropertyNames; private final Set<String> myPropertyNames;
private final List<ValueSet> myValueSets; private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>(); private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Set<String> myCodesInRsnaPlaybookValueSet = new HashSet<>(); private final Set<String> myCodesInDocumentOntologyValueSet = new HashSet<>();
public LoincDocumentOntologyHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets) { public LoincDocumentOntologyHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets) {
myCodeSystemVersion = theCodeSystemVersion; myCodeSystemVersion = theCodeSystemVersion;
@ -46,39 +43,50 @@ public class LoincDocumentOntologyHandler implements IRecordHandler {
// RSNA Codes VS // RSNA Codes VS
ValueSet vs; ValueSet vs;
if (!myIdToValueSet.containsKey(RSNA_CODES_VS_ID)) { if (!myIdToValueSet.containsKey(DOCUMENT_ONTOLOGY_CODES_VS_ID)) {
vs = new ValueSet(); vs = new ValueSet();
vs.setUrl(RSNA_CODES_VS_URI); vs.setUrl(DOCUMENT_ONTOLOGY_CODES_VS_URI);
vs.setId(RSNA_CODES_VS_ID); vs.setId(DOCUMENT_ONTOLOGY_CODES_VS_ID);
vs.setName(RSNA_CODES_VS_NAME); vs.setName(DOCUMENT_ONTOLOGY_CODES_VS_NAME);
vs.setStatus(Enumerations.PublicationStatus.ACTIVE); vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
myIdToValueSet.put(RSNA_CODES_VS_ID, vs); myIdToValueSet.put(DOCUMENT_ONTOLOGY_CODES_VS_ID, vs);
myValueSets.add(vs); myValueSets.add(vs);
} else { } else {
vs = myIdToValueSet.get(RSNA_CODES_VS_ID); vs = myIdToValueSet.get(DOCUMENT_ONTOLOGY_CODES_VS_ID);
} }
if (!myCodesInRsnaPlaybookValueSet.contains(loincNumber)) { if (!myCodesInDocumentOntologyValueSet.contains(loincNumber)) {
String loincDisplayName= null;
if (myCode2Concept.containsKey(loincNumber)) {
loincDisplayName = myCode2Concept.get(loincNumber).getDisplay();
}
vs vs
.getCompose() .getCompose()
.getIncludeFirstRep() .getIncludeFirstRep()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL) .setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.addConcept() .addConcept()
.setCode(loincNumber) .setCode(loincNumber)
.setDisplay(longCommonName); .setDisplay(loincDisplayName);
myCodesInRsnaPlaybookValueSet.add(loincNumber); myCodesInDocumentOntologyValueSet.add(loincNumber);
} }
String loincCodePropName; String loincCodePropName;
switch (partTypeName) { switch (partTypeName) {
case "Rad.Anatomic Location.Region Imaged": case "Document.Kind":
loincCodePropName = "rad-anatomic-location-region-imaged"; loincCodePropName = "document-kind";
break; break;
case "Rad.Anatomic Location.Imaging Focus": case "Document.Role":
loincCodePropName = "rad-anatomic-location-imaging-focus"; loincCodePropName = "document-role";
break; break;
case "Rad.Modality.Modality type": case "Document.Setting":
loincCodePropName = "rad-modality-modality-type"; loincCodePropName = "document-setting";
break;
case "Document.SubjectMatterDomain":
loincCodePropName = "document-subject-matter-domain";
break;
case "Document.TypeOfService":
loincCodePropName = "document-type-of-service";
break; break;
default: default:
throw new InternalErrorException("Unknown PartTypeName: " + partTypeName); throw new InternalErrorException("Unknown PartTypeName: " + partTypeName);
@ -89,7 +97,6 @@ public class LoincDocumentOntologyHandler implements IRecordHandler {
code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URL, partNumber, partName); code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URL, partNumber, partName);
} }
} }
} }

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.loinc.LoincDocumentOntologyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartHandler; import ca.uhn.fhir.jpa.term.loinc.LoincPartHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler; import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler; import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler;
@ -158,8 +159,22 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals("420710006", group.getElement().get(0).getTarget().get(0).getCode()); assertEquals("420710006", group.getElement().get(0).getTarget().get(0).getCode());
assertEquals("Interferon beta (substance)", group.getElement().get(0).getTarget().get(0).getDisplay()); assertEquals("Interferon beta (substance)", group.getElement().get(0).getTarget().get(0).getDisplay());
// Document Ontology Parts // Document Ontology ValueSet
vs = valueSets.get(LoincDocumentOntologyHandler.DOCUMENT_ONTOLOGY_CODES_VS_ID);
assertEquals(LoincDocumentOntologyHandler.DOCUMENT_ONTOLOGY_CODES_VS_NAME, vs.getName());
assertEquals(LoincDocumentOntologyHandler.DOCUMENT_ONTOLOGY_CODES_VS_URI, vs.getUrl());
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(3, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("11488-4", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("Consult note", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
// Document ontology parts
code = concepts.get("11488-4");
assertEquals(1, code.getCodingProperties("document-kind").size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, code.getCodingProperties("document-kind").get(0).getSystem());
assertEquals("LP173418-7", code.getCodingProperties("document-kind").get(0).getCode());
assertEquals("Note", code.getCodingProperties("document-kind").get(0).getDisplay());
// RSNA Playbook ValueSet // RSNA Playbook ValueSet
vs = valueSets.get(LoincRsnaPlaybookHandler.RSNA_CODES_VS_ID); vs = valueSets.get(LoincRsnaPlaybookHandler.RSNA_CODES_VS_ID);

View File

@ -13,3 +13,4 @@
"17787-3" ,"Study report" ,"Find" ,"Pt" ,"Neck>Thyroid gland","Doc" ,"NM" ,"RAD" ,"2.61" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Document; Finding; Findings; Imaging; Point in time; Radiology; Random; Study report; Thy" ,"NM Thyroid Study report" ,"Both" , , , , ,"NM Thyroid gland Study report" , , , , , , ,"Changed System from ""Thyroid"" for conformance with the LOINC/RadLex unified model.; Method of ""Radnuc"" was changed to ""NM"". The LOINC/RadLex Committee agreed to use a subset of the two-letter DICOM modality codes as the primary modality identifier." ,0 ,0 ,0 ,"IG exists" , , , ,"81220-6;72230-6" ,"1.0l" , "17787-3" ,"Study report" ,"Find" ,"Pt" ,"Neck>Thyroid gland","Doc" ,"NM" ,"RAD" ,"2.61" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Document; Finding; Findings; Imaging; Point in time; Radiology; Random; Study report; Thy" ,"NM Thyroid Study report" ,"Both" , , , , ,"NM Thyroid gland Study report" , , , , , , ,"Changed System from ""Thyroid"" for conformance with the LOINC/RadLex unified model.; Method of ""Radnuc"" was changed to ""NM"". The LOINC/RadLex Committee agreed to use a subset of the two-letter DICOM modality codes as the primary modality identifier." ,0 ,0 ,0 ,"IG exists" , , , ,"81220-6;72230-6" ,"1.0l" ,
"17788-1" ,"Large unstained cells/100 leukocytes" ,"NFr" ,"Pt" ,"Bld" ,"Qn" ,"Automated count","HEM/BC" ,"2.50" ,"MIN" ,"Part of auto diff output of Bayer H*3S; peroxidase negative cells too large to be classified as lymph or basophil","ACTIVE", ,1 , , , , , ,"Y" ,"%" ,"100WBC; Auto; Automated detection; Blood; Cell; Cellularity; Elec; Elect; Electr; HEMATOLOGY/CELL COUNTS; Leuc; Leuk; Leukocyte; Lkcs; LUC; Number Fraction; Percent; Point in time; QNT; Quan; Quant; Quantitative; Random; WB; WBC; WBCs; White blood cell; White blood cells; Whole blood","LUC/leuk NFr Bld Auto" ,"Observation", , , ,"%" ,"Large unstained cells/100 leukocytes in Blood by Automated count" , , ,"%" , , , , ,1894 ,0 ,1894 , , , , , ,"1.0l" , "17788-1" ,"Large unstained cells/100 leukocytes" ,"NFr" ,"Pt" ,"Bld" ,"Qn" ,"Automated count","HEM/BC" ,"2.50" ,"MIN" ,"Part of auto diff output of Bayer H*3S; peroxidase negative cells too large to be classified as lymph or basophil","ACTIVE", ,1 , , , , , ,"Y" ,"%" ,"100WBC; Auto; Automated detection; Blood; Cell; Cellularity; Elec; Elect; Electr; HEMATOLOGY/CELL COUNTS; Leuc; Leuk; Leukocyte; Lkcs; LUC; Number Fraction; Percent; Point in time; QNT; Quan; Quant; Quantitative; Random; WB; WBC; WBCs; White blood cell; White blood cells; Whole blood","LUC/leuk NFr Bld Auto" ,"Observation", , , ,"%" ,"Large unstained cells/100 leukocytes in Blood by Automated count" , , ,"%" , , , , ,1894 ,0 ,1894 , , , , , ,"1.0l" ,
"11488-4" ,"Consultation note" ,"Find" ,"Pt" ,"{Setting}" ,"Doc" ,"{Role}" ,"DOC.ONTOLOGY","2.63" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Consult note; DOC.ONT; Document; Encounter; Evaluation and management; Evaluation and management note; Finding; Findings; notes; Point in time; Random; Visit note" ,"Consult note" ,"Both" , , , , ,"Consult note" , , , , , , ,"Edit made because this term is conformant to the Document Ontology axis values and therefore are being placed in this class.; Based on Clinical LOINC Committee decision during the September 2014 meeting, {Provider} was changed to {Author Type} to emphasize a greater breadth of potential document authors. At the September 2015 Clinical LOINC Committee meeting, the Committee decided to change {Author Type} to {Role} to align with the 'Role' axis name in the LOINC Document Ontology.; Because it is too difficult to maintain and because the distinction between documents and sections is not clear-cut nor necessary in most cases, the DOCUMENT_SECTION field has been deemed to have little value. The field has been set to null in the December 2017 release in preparation for removal in the December 2018 release. These changes were approved by the Clinical LOINC Committee.",0 ,0 ,0 ,"IG exists" , , , ,"81222-2;72231-4;81243-8","1.0j-a" ,"Y" "11488-4" ,"Consultation note" ,"Find" ,"Pt" ,"{Setting}" ,"Doc" ,"{Role}" ,"DOC.ONTOLOGY","2.63" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Consult note; DOC.ONT; Document; Encounter; Evaluation and management; Evaluation and management note; Finding; Findings; notes; Point in time; Random; Visit note" ,"Consult note" ,"Both" , , , , ,"Consult note" , , , , , , ,"Edit made because this term is conformant to the Document Ontology axis values and therefore are being placed in this class.; Based on Clinical LOINC Committee decision during the September 2014 meeting, {Provider} was changed to {Author Type} to emphasize a greater breadth of potential document authors. At the September 2015 Clinical LOINC Committee meeting, the Committee decided to change {Author Type} to {Role} to align with the 'Role' axis name in the LOINC Document Ontology.; Because it is too difficult to maintain and because the distinction between documents and sections is not clear-cut nor necessary in most cases, the DOCUMENT_SECTION field has been deemed to have little value. The field has been set to null in the December 2017 release in preparation for removal in the December 2018 release. These changes were approved by the Clinical LOINC Committee.",0 ,0 ,0 ,"IG exists" , , , ,"81222-2;72231-4;81243-8","1.0j-a" ,"Y"

Can't render this file because it contains an unexpected character in line 1 and column 23.