Work on terminology services

This commit is contained in:
jamesagnew 2016-03-15 10:03:22 -04:00
parent 00ced6a652
commit 96d6fa1b8a
10 changed files with 188 additions and 59 deletions

View File

@ -9,6 +9,8 @@ public interface ITerminologySvc {
void storeNewCodeSystemVersion(String theSystemUri, TermCodeSystemVersion theCodeSytem);
Set<TermConcept> findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersion, String theCode);
Set<TermConcept> findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);
Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);
}

View File

@ -3,11 +3,13 @@ package ca.uhn.fhir.jpa.term;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.ValidationUtils;
import com.google.common.base.Stopwatch;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
@ -28,28 +30,99 @@ public class TerminologySvcImpl implements ITerminologySvc {
@Autowired
private ITermCodeSystemVersionDao myCodeSystemVersionDao;
@Autowired
private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
@Autowired
private ITermConceptDao myConceptDao;
@Autowired
private ITermCodeSystemDao myCodeSystemDao;
@Autowired
private FhirContext myContext;
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) {
TermConcept nextChild = nextChildLink.getChild();
if (theSetToPopulate.add(nextChild)) {
fetchChildren(nextChild, theSetToPopulate);
}
}
}
private TermConcept fetchLoadedCode(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
TermCodeSystemVersion codeSystem = myCodeSystemVersionDao.findByCodeSystemResourceAndVersion(theCodeSystemResourcePid, theCodeSystemVersionPid);
TermConcept concept = myConceptDao.findByCodeSystemAndCode(codeSystem, theCode);
return concept;
}
private void fetchParents(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
for (TermConceptParentChildLink nextChildLink : theConcept.getParents()) {
TermConcept nextChild = nextChildLink.getParent();
if (theSetToPopulate.add(nextChild)) {
fetchParents(nextChild, theSetToPopulate);
}
}
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
@Transactional(propagation=Propagation.REQUIRED)
public Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
Stopwatch stopwatch = Stopwatch.createStarted();
TermConcept concept = fetchLoadedCode(theCodeSystemResourcePid, theCodeSystemVersionPid, theCode);
Set<TermConcept> retVal = new HashSet<TermConcept>();
retVal.add(concept);
fetchParents(concept, retVal);
ourLog.info("Fetched {} codes above code {} in {}ms", retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS));
return retVal;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Set<TermConcept> findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
Stopwatch stopwatch = Stopwatch.createStarted();
TermConcept concept = fetchLoadedCode(theCodeSystemResourcePid, theCodeSystemVersionPid, theCode);
Set<TermConcept> retVal = new HashSet<TermConcept>();
retVal.add(concept);
fetchChildren(concept, retVal);
ourLog.info("Fetched {} codes below code {} in {}ms", retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS));
return retVal;
}
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack) {
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
return;
}
for (TermConceptParentChildLink next : theConcept.getChildren()) {
persistChildren(next.getChild(), theCodeSystem, theConceptsStack);
}
myConceptDao.save(theConcept);
for (TermConceptParentChildLink next : theConcept.getChildren()) {
myConceptParentChildLinkDao.save(next);
}
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void storeNewCodeSystemVersion(String theSystemUri, TermCodeSystemVersion theCodeSystem) {
ourLog.info("Storing code system");
ValidateUtil.isNotNullOrThrowInvalidRequest(theCodeSystem.getResource() != null, "No resource supplied");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied");
TermCodeSystem codeSystem = myCodeSystemDao.findByCodeSystemUri(theSystemUri);
if (codeSystem == null) {
TermCodeSystem newCodeSystem = new TermCodeSystem();
@ -61,41 +134,25 @@ public class TerminologySvcImpl implements ITerminologySvc {
throw new InvalidRequestException(myContext.getLocalizer().getMessage(TerminologySvcImpl.class, "cannotCreateDuplicateCodeSystemUri", theSystemUri, codeSystem.getResource().getIdDt().getValue()));
}
}
// Validate the code system
IdentityHashMap<TermConcept, Object> conceptsStack = new IdentityHashMap<TermConcept, Object>();
for (TermConcept next : theCodeSystem.getConcepts()) {
validateConceptForStorage(next, theCodeSystem, conceptsStack);
}
myCodeSystemVersionDao.save(theCodeSystem);
conceptsStack = new IdentityHashMap<TermConcept, Object>();
for (TermConcept next : theCodeSystem.getConcepts()) {
persistChildren(next, theCodeSystem, conceptsStack);
}
}
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack) {
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
return;
}
for (TermConceptParentChildLink next : theConcept.getChildren()) {
persistChildren(next.getChild(), theCodeSystem, theConceptsStack);
}
myConceptDao.save(theConcept);
for (TermConceptParentChildLink next : theConcept.getChildren()) {
myConceptParentChildLinkDao.save(next);
}
}
private void validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack) {
ValidateUtil.isNotNullOrThrowInvalidRequest(theConcept.getCodeSystem() == theCodeSystem, "Codesystem contains a code which does not reference the codesystem");
ValidateUtil.isNotNullOrThrowInvalidRequest(theConcept.getCodeSystem() == theCodeSystem, "Codesystem contains a code which does not reference the codesystem");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "Codesystem contains a code which does not reference the codesystem");
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
}
@ -103,34 +160,8 @@ public class TerminologySvcImpl implements ITerminologySvc {
for (TermConceptParentChildLink next : theConcept.getChildren()) {
validateConceptForStorage(next.getChild(), theCodeSystem, theConceptsStack);
}
theConceptsStack.remove(theConcept);
}
@Transactional(propagation=Propagation.REQUIRED)
@Override
public Set<TermConcept> findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
TermCodeSystemVersion codeSystem = myCodeSystemVersionDao.findByCodeSystemResourceAndVersion(theCodeSystemResourcePid, theCodeSystemVersionPid);
TermConcept concept = myConceptDao.findByCodeSystemAndCode(codeSystem, theCode);
Set<TermConcept> retVal = new HashSet<TermConcept>();
retVal.add(concept);
fetchChildren(concept, retVal);
return retVal;
}
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) {
TermConcept nextChild = nextChildLink.getChild();
if (theSetToPopulate.add(nextChild)) {
fetchChildren(nextChild, theSetToPopulate);
}
}
}
}

View File

@ -56,7 +56,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
}
@Test
public void testFetchIsA() {
public void testFindCodesBelowA() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl("http://example.com/my_code_system");
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
@ -100,6 +100,51 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB"));
}
@Test
public void testFindCodesAbove() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl("http://example.com/my_code_system");
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());
TermConcept parentA = new TermConcept(cs, "ParentA");
cs.getConcepts().add(parentA);
TermConcept childAA = new TermConcept(cs, "childAA");
parentA.addChild(childAA);
TermConcept childAAA = new TermConcept(cs, "childAAA");
childAA.addChild(childAAA);
TermConcept childAAB = new TermConcept(cs, "childAAB");
childAA.addChild(childAAB);
TermConcept childAB = new TermConcept(cs, "childAB");
parentA.addChild(childAB);
TermConcept parentB = new TermConcept(cs, "ParentB");
cs.getConcepts().add(parentB);
myTermSvc.storeNewCodeSystemVersion("http://foo", cs);
Set<TermConcept> concepts;
Set<String> codes;
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ChildAA");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("ParentA", "childAA"));
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB"));
}
@Test
public void testCreateDuplicateCodeSystemUri() {
CodeSystem codeSystem = new CodeSystem();

View File

@ -0,0 +1,10 @@
id effectiveTime active moduleId definitionStatusId
100005 20020131 0 900000000000207008 900000000000074008
101009 20020131 1 900000000000207008 900000000000074008
102002 20020131 1 900000000000207008 900000000000074008
103007 20020131 1 900000000000207008 900000000000074008
104001 20020131 1 900000000000207008 900000000000073002
105000 20020131 1 900000000000207008 900000000000074008
105000 20040731 0 900000000000207008 900000000000074008
106004 20020131 1 900000000000207008 900000000000074008
107008 20020131 1 900000000000207008 900000000000074008

View File

@ -0,0 +1,10 @@
id effectiveTime active moduleId conceptId languageCode typeId term caseSignificanceId
101013 20020131 1 900000000000207008 126813005 en 900000000000013009 Neoplasm of anterior aspect of epiglottis 900000000000020002
102018 20020131 1 900000000000207008 126814004 en 900000000000013009 Neoplasm of junctional region of epiglottis 900000000000020002
103011 20020131 1 900000000000207008 126815003 en 900000000000013009 Neoplasm of lateral wall of oropharynx 900000000000020002
104017 20020131 1 900000000000207008 126816002 en 900000000000013009 Neoplasm of posterior wall of oropharynx 900000000000020002
105016 20020131 1 900000000000207008 126817006 en 900000000000013009 Neoplasm of esophagus 900000000000020002
106015 20020131 1 900000000000207008 126818001 en 900000000000013009 Neoplasm of cervical esophagus 900000000000020002
107012 20020131 1 900000000000207008 126819009 en 900000000000013009 Neoplasm of thoracic esophagus 900000000000020002
108019 20020131 1 900000000000207008 126820003 en 900000000000013009 Neoplasm of abdominal esophagus 900000000000020002
110017 20020131 1 900000000000207008 126822006 en 900000000000013009 Neoplasm of middle third of esophagus 900000000000020002

View File

@ -0,0 +1 @@
identifierSchemeId alternateIdentifier effectiveTime active moduleId referencedComponentId

View File

@ -0,0 +1,10 @@
id effectiveTime active moduleId sourceId destinationId relationshipGroup typeId characteristicTypeId modifierId
100022 20020131 1 900000000000207008 100000000 102272007 0 116680003 900000000000011006 900000000000451002
100022 20090731 0 900000000000207008 100000000 102272007 0 116680003 900000000000011006 900000000000451002
101021 20020131 1 900000000000207008 10000006 29857009 0 116680003 900000000000011006 900000000000451002
102025 20020131 1 900000000000207008 10000006 9972008 0 116680003 900000000000011006 900000000000451002
103024 20020131 1 900000000000207008 1000004 19130008 0 116680003 900000000000011006 900000000000451002
103024 20030131 0 900000000000207008 1000004 19130008 0 116680003 900000000000011006 900000000000451002
104029 20020131 1 900000000000207008 100001001 102272007 0 116680003 900000000000011006 900000000000451002
104029 20090731 0 900000000000207008 100001001 102272007 0 116680003 900000000000011006 900000000000451002
105028 20020131 1 900000000000207008 100002008 102272007 0 116680003 900000000000011006 900000000000451002

View File

@ -0,0 +1,10 @@
id effectiveTime active moduleId sourceId destinationId relationshipGroup typeId characteristicTypeId modifierId
3187444026 20140131 1 900000000000207008 425630003 400195000 0 42752001 900000000000010007 900000000000451002
3187444026 20160131 0 900000000000207008 425630003 400195000 0 42752001 900000000000010007 900000000000451002
3192499027 20140131 0 900000000000207008 425630003 105590001 0 246075003 900000000000010007 900000000000451002
3574321020 20140131 1 900000000000207008 425630003 111189002 0 116680003 900000000000010007 900000000000451002
3574321020 20160131 0 900000000000207008 425630003 111189002 0 116680003 900000000000010007 900000000000451002
3829433029 20080731 1 900000000000207008 102977005 102976001 0 116680003 900000000000010007 900000000000451002
3829434024 20080731 1 900000000000207008 413337008 306751006 0 116680003 900000000000010007 900000000000451002
3829435020 20080731 1 900000000000207008 103085008 72909000 0 116680003 900000000000010007 900000000000451002
3829436021 20080731 1 900000000000207008 103085008 259648002 0 116680003 900000000000010007 900000000000451002

View File

@ -0,0 +1,10 @@
id effectiveTime active moduleId conceptId languageCode typeId term caseSignificanceId
2884452019 20040731 1 900000000000207008 410016009 en 900000000000550004 A decrease in lower leg circumference due to recurrent ulceration and fat necrosis causing loss of subcutaneous tissue in a patient with venous stasis disease 900000000000017005
2884453012 20050731 1 900000000000207008 416118004 en 900000000000550004 Introduction of a substance to the body 900000000000017005
2884454018 20030731 1 900000000000207008 125097000 en 900000000000550004 Domestic goat 900000000000017005
2884455017 20030731 1 900000000000207008 125099002 en 900000000000550004 Domestic sheep species 900000000000017005
2884455017 20110131 0 900000000000207008 125099002 en 900000000000550004 Domestic sheep species 900000000000017005
2884456016 20030731 1 900000000000207008 122868007 en 900000000000550004 An implantation of a staple 900000000000017005
2884457013 20030731 1 900000000000207008 125085001 en 900000000000550004 Equus subspecies 900000000000017005
2884457013 20100731 0 900000000000207008 125085001 en 900000000000550004 Equus subspecies 900000000000017005
2884458015 20030731 1 900000000000207008 125671007 en 900000000000550004 Disruption of continuity of tissue, not necessarily due to external forces; may be due to weakness in the tissue or excessive internal pressures 900000000000017005