Merge branch 'loinc_loader_update'

This commit is contained in:
jamesagnew 2018-04-15 17:43:32 -04:00
commit ecc23732d3
5 changed files with 48 additions and 36 deletions

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.context.support.IContextValidationSupport;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@ -10,6 +11,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.search.annotations.*;
import org.hl7.fhir.r4.model.Coding;
import org.springframework.validation.ValidationUtils;
import javax.annotation.Nonnull;
import javax.persistence.*;
@ -185,6 +187,7 @@ public class TermConcept implements Serializable {
}
public void setCode(String theCode) {
ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "Code must not be null or empty");
myCode = theCode;
}

View File

@ -432,7 +432,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
fetchParents(concept, retVal);
ourLog.info("Fetched {} codes above code {} in {}ms", new Object[] {retVal.size(), theCode, stopwatch.getMillis()});
ourLog.info("Fetched {} codes above code {} in {}ms", retVal.size(), theCode, stopwatch.getMillis());
return retVal;
}
@ -463,7 +463,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
fetchChildren(concept, retVal);
ourLog.info("Fetched {} codes below code {} in {}ms", new Object[] {retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS)});
ourLog.info("Fetched {} codes below code {} in {}ms", retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS));
return retVal;
}
@ -537,7 +537,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
}
private void processDeferredConceptMaps() {
int count = Math.min(myDeferredConceptMaps.size(), 5);
int count = Math.min(myDeferredConceptMaps.size(), 20);
for (ConceptMap nextConceptMap : new ArrayList<>(myDeferredConceptMaps.subList(0, count))) {
ourLog.info("Creating ConceptMap: {}", nextConceptMap.getId());
createOrUpdateConceptMap(nextConceptMap);
@ -559,7 +559,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
if (codeCount > 0) {
ourLog.info("Saved {} deferred concepts ({} codes remain and {} relationships remain) in {}ms ({}ms / code)",
new Object[] {codeCount, myDeferredConcepts.size(), myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount)});
codeCount, myDeferredConcepts.size(), myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount));
}
if (codeCount == 0) {
@ -580,7 +580,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
if (relCount > 0) {
ourLog.info("Saved {} deferred relationships ({} remain) in {}ms ({}ms / code)",
new Object[] {relCount, myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount)});
relCount, myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount));
}
if ((myDeferredConcepts.size() + myConceptLinksToSaveLater.size()) == 0) {
@ -589,13 +589,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
}
private void processDeferredValueSets() {
int count = Math.min(myDeferredValueSets.size(), 5);
int count = Math.min(myDeferredValueSets.size(), 20);
for (ValueSet nextValueSet : new ArrayList<>(myDeferredValueSets.subList(0, count))) {
ourLog.info("Creating ValueSet: {}", nextValueSet.getId());
createOrUpdateValueSet(nextValueSet);
myDeferredValueSets.remove(nextValueSet);
}
ourLog.info("Saved {} deferred ValueSet resources, have {} remaining", count, myDeferredConceptMaps.size());
ourLog.info("Saved {} deferred ValueSet resources, have {} remaining", count, myDeferredValueSets.size());
}
private void processReindexing() {
@ -668,7 +668,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
count++;
}
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", new Object[] {count, concepts.getContent().size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(count)});
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", count, concepts.getContent().size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(count));
}
});
@ -758,6 +758,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
// Grab the existing versions so we can delete them later
List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystemResourcePid);
// verifyNoDuplicates(theCodeSystemVersion.getConcepts(), new HashSet<String>());
/*
* For now we always delete old versions.. At some point it would be nice to allow configuration to keep old versions
*/
@ -909,6 +911,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
return retVal;
}
private void verifyNoDuplicates(Collection<TermConcept> theConcepts, Set<String> theCodes) {
for (TermConcept next : theConcepts) {
if (!theCodes.add(next.getCode())) {
throw new InvalidRequestException("Duplicate code " + next.getCode() + " found in codesystem after checking " + theCodes.size() + " codes");
}
verifyNoDuplicates(next.getChildren().stream().map(TermConceptParentChildLink::getChild).collect(Collectors.toList()), theCodes);
}
}
/**
* This method is present only for unit tests, do not call from client code
*/

View File

@ -240,7 +240,7 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
iterateOverZipFile(theDescriptors, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer lists (ValueSets of potential answers/values for loinc "questions")
handler = new LoincAnswerListHandler(codeSystemVersion, code2concept, propertyNames, valueSets);
handler = new LoincAnswerListHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer list links (connects loinc observation codes to answerlist codes)

View File

@ -23,9 +23,8 @@ package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.HashMap;
@ -33,10 +32,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim;
import static org.apache.commons.lang3.StringUtils.*;
public class LoincAnswerListHandler implements IRecordHandler {
public class LoincAnswerListHandler extends BaseHandler {
private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion;
@ -44,7 +42,8 @@ public class LoincAnswerListHandler implements IRecordHandler {
private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
public LoincAnswerListHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets) {
public LoincAnswerListHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
@ -70,6 +69,10 @@ public class LoincAnswerListHandler implements IRecordHandler {
String extCodeSystem = trim(theRecord.get("ExtCodeSystem"));
String extCodeSystemVersion = trim(theRecord.get("ExtCodeSystemVersion"));
if (isBlank(answerString)) {
return;
}
// Answer list code
if (!myCode2Concept.containsKey(answerListId)) {
TermConcept concept = new TermConcept(myCodeSystemVersion, answerListId);
@ -88,21 +91,13 @@ public class LoincAnswerListHandler implements IRecordHandler {
}
// Answer list ValueSet
ValueSet vs;
if (!myIdToValueSet.containsKey(answerListId)) {
vs = new ValueSet();
vs.setUrl("urn:oid:" + answerListOid);
ValueSet vs = getValueSet(answerListId, "urn:oid:" + answerListOid, answerListName);
if (vs.getIdentifier().isEmpty()) {
vs.addIdentifier()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setValue(answerListId);
vs.setId(answerListId);
vs.setName(answerListName);
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
myIdToValueSet.put(answerListId, vs);
myValueSets.add(vs);
} else {
vs = myIdToValueSet.get(answerListId);
}
vs
.getCompose()
.getIncludeFirstRep()

View File

@ -58,8 +58,12 @@ public class LoincPartHandler implements IRecordHandler {
// return;
// }
TermConcept concept = new TermConcept(myCodeSystemVersion, partNumber);
TermConcept concept = myCode2Concept.get(partNumber);
if (concept == null) {
concept = new TermConcept(myCodeSystemVersion, partNumber);
concept.setDisplay(partName);
myCode2Concept.put(partNumber, concept);
}
if (isNotBlank(partDisplayName)) {
concept.addDesignation()
@ -68,7 +72,6 @@ public class LoincPartHandler implements IRecordHandler {
.setValue(partDisplayName);
}
myCode2Concept.put(partDisplayName, concept);
}
}