Added pre-fetch for concept designations, improved paging for expanded ValueSets, and columns on TermValueSet for number of concepts and designations.

This commit is contained in:
Diederik Muylwyk 2019-09-03 16:02:28 -04:00
parent 1ef70a0fca
commit b42b598d01
7 changed files with 127 additions and 56 deletions

View File

@ -40,8 +40,8 @@ public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConce
@Modifying
void deleteByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("SELECT vsc from TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid")
Slice<TermValueSetConcept> findByTermValueSetId(Pageable thePage, @Param("pid") Long theValueSetId);
@Query("SELECT vsc from TermValueSetConcept vsc LEFT OUTER JOIN FETCH vsc.myDesignations WHERE vsc.myValueSet.myId = :pid")
Slice<TermValueSetConcept> findByTermValueSetIdAndPreFetchDesignations(Pageable thePage, @Param("pid") Long theValueSetId);
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
Optional<TermValueSetConcept> findByTermValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);

View File

@ -26,6 +26,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.ColumnDefault;
import javax.annotation.Nonnull;
import javax.persistence.*;
@ -43,6 +44,8 @@ import static org.apache.commons.lang3.StringUtils.length;
public class TermValueSet implements Serializable {
private static final long serialVersionUID = 1L;
private static final int MAX_TOTAL_LENGTH = 19;
public static final int MAX_EXPANSION_STATUS_LENGTH = 50;
public static final int MAX_NAME_LENGTH = 200;
public static final int MAX_URL_LENGTH = 200;
@ -69,6 +72,14 @@ public class TermValueSet implements Serializable {
@OneToMany(mappedBy = "myValueSet")
private List<TermValueSetConcept> myConcepts;
@Column(name = "TOTAL_CONCEPTS", nullable = false, length = MAX_TOTAL_LENGTH)
@ColumnDefault("0")
private Long myTotalConcepts;
@Column(name = "TOTAL_CONCEPT_DESIGNATIONS", nullable = false, length = MAX_TOTAL_LENGTH)
@ColumnDefault("0")
private Long myTotalConceptDesignations;
@Enumerated(EnumType.STRING)
@Column(name = "EXPANSION_STATUS", nullable = false, length = MAX_EXPANSION_STATUS_LENGTH)
private TermValueSetPreExpansionStatusEnum myExpansionStatus;
@ -76,6 +87,8 @@ public class TermValueSet implements Serializable {
public TermValueSet() {
super();
myExpansionStatus = TermValueSetPreExpansionStatusEnum.NOT_EXPANDED;
myTotalConcepts = 0L;
myTotalConceptDesignations = 0L;
}
public Long getId() {
@ -120,6 +133,48 @@ public class TermValueSet implements Serializable {
return myConcepts;
}
public Long getTotalConcepts() {
return myTotalConcepts;
}
public TermValueSet setTotalConcepts(Long theTotalConcepts) {
myTotalConcepts = theTotalConcepts;
return this;
}
public TermValueSet decrementTotalConcepts() {
if (myTotalConcepts > 0) {
myTotalConcepts--;
}
return this;
}
public TermValueSet incrementTotalConcepts() {
myTotalConcepts++;
return this;
}
public Long getTotalConceptDesignations() {
return myTotalConceptDesignations;
}
public TermValueSet setTotalConceptDesignations(Long theTotalConceptDesignations) {
myTotalConceptDesignations = theTotalConceptDesignations;
return this;
}
public TermValueSet decrementTotalConceptDesignations() {
if (myTotalConceptDesignations > 0) {
myTotalConceptDesignations--;
}
return this;
}
public TermValueSet incrementTotalConceptDesignations() {
myTotalConceptDesignations++;
return this;
}
public TermValueSetPreExpansionStatusEnum getExpansionStatus() {
return myExpansionStatus;
}
@ -157,6 +212,8 @@ public class TermValueSet implements Serializable {
.append("myResourcePid", myResourcePid)
.append("myName", myName)
.append(myConcepts != null ? ("myConcepts - size=" + myConcepts.size()) : ("myConcepts=(null)"))
.append("myTotalConcepts", myTotalConcepts)
.append("myTotalConceptDesignations", myTotalConceptDesignations)
.append("myExpansionStatus", myExpansionStatus)
.toString();
}

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -524,7 +525,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
}
private void populateExpansionComponent(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) {
int total = myValueSetConceptDao.countByTermValueSetId(theTermValueSet.getId());
int total = theTermValueSet.getTotalConcepts().intValue();
theExpansionComponent.setTotal(total);
theExpansionComponent.setOffset(theOffset);
theExpansionComponent.addParameter().setName("offset").setValue(new IntegerType(theOffset));
@ -539,72 +540,59 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private void expandConcepts(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) {
int conceptsExpanded = 0;
for (int i = theOffset; i < (theOffset + theCount); i++) {
final int page = i;
Supplier<Slice<TermValueSetConcept>> loader = () -> myValueSetConceptDao.findByTermValueSetId(PageRequest.of(page, 1), theTermValueSet.getId());
int toIndex = theOffset + theCount;
Supplier<Slice<TermValueSetConcept>> loader = () -> myValueSetConceptDao.findByTermValueSetIdAndPreFetchDesignations(SearchCoordinatorSvcImpl.toPage(theOffset, toIndex), theTermValueSet.getId());
Slice<TermValueSetConcept> slice = loader.get();
if (!slice.hasContent()) {
logConceptsExpanded(theTermValueSet, conceptsExpanded);
return;
}
Slice<TermValueSetConcept> slice = loader.get();
if (!slice.hasContent()) {
break;
}
for (TermValueSetConcept concept : slice.getContent()) {
ValueSet.ValueSetExpansionContainsComponent containsComponent = theExpansionComponent.addContains();
containsComponent.setSystem(concept.getSystem());
containsComponent.setCode(concept.getCode());
containsComponent.setDisplay(concept.getDisplay());
for (TermValueSetConcept concept : slice.getContent()) {
ValueSet.ValueSetExpansionContainsComponent containsComponent = theExpansionComponent.addContains();
containsComponent.setSystem(concept.getSystem());
containsComponent.setCode(concept.getCode());
containsComponent.setDisplay(concept.getDisplay());
// TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to make this optional.
expandDesignations(theTermValueSet, concept, containsComponent);
// TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to make this optional.
expandDesignations(theTermValueSet, concept, containsComponent);
if (++conceptsExpanded % 250 == 0) {
ourLog.info("Have expanded {} concepts in ValueSet[{}]", conceptsExpanded, theTermValueSet.getUrl());
}
}
if (!slice.hasNext()) {
break;
if (++conceptsExpanded % 250 == 0) {
logConceptsExpanded(theTermValueSet, conceptsExpanded);
}
}
if (conceptsExpanded > 0) {
ourLog.info("Have expanded {} concepts in ValueSet[{}]", conceptsExpanded, theTermValueSet.getUrl());
logConceptsExpanded(theTermValueSet, conceptsExpanded);
}
private void logConceptsExpanded(TermValueSet theTermValueSet, int theConceptsExpanded) {
if (theConceptsExpanded > 0) {
ourLog.info("Have expanded {} concepts in ValueSet[{}]", theConceptsExpanded, theTermValueSet.getUrl());
}
}
private void expandDesignations(TermValueSet theValueSet, TermValueSetConcept theConcept, ValueSet.ValueSetExpansionContainsComponent theContainsComponent) {
int designationsExpanded = 0;
int index = 0;
while (true) {
final int page = index++;
Supplier<Slice<TermValueSetConceptDesignation>> loader = () -> myValueSetConceptDesignationDao.findByTermValueSetConceptId(PageRequest.of(page, 1000), theConcept.getId());
for (TermValueSetConceptDesignation designation : theConcept.getDesignations()) {
ValueSet.ConceptReferenceDesignationComponent designationComponent = theContainsComponent.addDesignation();
designationComponent.setLanguage(designation.getLanguage());
designationComponent.setUse(new Coding(
designation.getUseSystem(),
designation.getUseCode(),
designation.getUseDisplay()));
designationComponent.setValue(designation.getValue());
Slice<TermValueSetConceptDesignation> slice = loader.get();
if (!slice.hasContent()) {
break;
}
for (TermValueSetConceptDesignation designation : slice.getContent()) {
ValueSet.ConceptReferenceDesignationComponent designationComponent = theContainsComponent.addDesignation();
designationComponent.setLanguage(designation.getLanguage());
designationComponent.setUse(new Coding(
designation.getUseSystem(),
designation.getUseCode(),
designation.getUseDisplay()));
designationComponent.setValue(designation.getValue());
if (++designationsExpanded % 250 == 0) {
ourLog.info("Have expanded {} designations for Concept[{}|{}] in ValueSet[{}]", designationsExpanded, theConcept.getSystem(), theConcept.getCode(), theValueSet.getUrl());
}
}
if (!slice.hasNext()) {
break;
if (++designationsExpanded % 250 == 0) {
logDesignationsExpanded(theValueSet, theConcept, designationsExpanded);
}
}
if (designationsExpanded > 0) {
ourLog.info("Have expanded {} designations for Concept[{}|{}] in ValueSet[{}]", designationsExpanded, theConcept.getSystem(), theConcept.getCode(), theValueSet.getUrl());
logDesignationsExpanded(theValueSet, theConcept, designationsExpanded);
}
private void logDesignationsExpanded(TermValueSet theValueSet, TermValueSetConcept theConcept, int theDesignationsExpanded) {
if (theDesignationsExpanded > 0) {
ourLog.info("Have expanded {} designations for Concept[{}|{}] in ValueSet[{}]", theDesignationsExpanded, theConcept.getSystem(), theConcept.getCode(), theValueSet.getUrl());
}
}

View File

@ -79,8 +79,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
ourLog.info("Excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl());
for (TermValueSetConceptDesignation designation : concept.getDesignations()) {
myValueSetConceptDesignationDao.deleteById(designation.getId());
myTermValueSet.decrementTotalConceptDesignations();
}
myValueSetConceptDao.deleteById(concept.getId());
myTermValueSet.decrementTotalConcepts();
ourLog.info("Done excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl());
ourLog.info("Flushing...");
@ -102,6 +104,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
concept.setDisplay(theDisplay);
}
myValueSetConceptDao.save(concept);
myTermValueSet.incrementTotalConcepts();
if (myConceptsSaved++ % 250 == 0) { // TODO: DM 2019-08-23 - This message never appears in the log. Fix it!
ourLog.info("Have pre-expanded {} concepts in ValueSet[{}]", myConceptsSaved, myTermValueSet.getUrl());
@ -126,6 +129,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
}
designation.setValue(theDesignation.getValue());
myValueSetConceptDesignationDao.save(designation);
myTermValueSet.incrementTotalConceptDesignations();
if (myDesignationsSaved++ % 250 == 0) { // TODO: DM 2019-08-23 - This message never appears in the log. Fix it!
ourLog.info("Have pre-expanded {} designations for Concept[{}|{}] in ValueSet[{}]", myDesignationsSaved, theConcept.getSystem(), theConcept.getCode(), myTermValueSet.getUrl());

View File

@ -312,6 +312,7 @@ public class SearchCoordinatorSvcImplTest {
public void testGetPage() {
Pageable page = SearchCoordinatorSvcImpl.toPage(50, 73);
assertEquals(50, page.getOffset());
assertEquals(23, page.getPageSize());
}
@Test

View File

@ -36,6 +36,7 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
@ -643,9 +644,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
Long termValueSetId = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get().getId();
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
Long termValueSetId = termValueSet.getId();
assertEquals(3, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue());
assertEquals(3, termValueSet.getTotalConceptDesignations().intValue());
assertEquals(24, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue());
assertEquals(24, termValueSet.getTotalConcepts().intValue());
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
@ -677,9 +681,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
Long termValueSetId = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get().getId();
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
Long termValueSetId = termValueSet.getId();
assertEquals(3, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue());
assertEquals(3, termValueSet.getTotalConceptDesignations().intValue());
assertEquals(24, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue());
assertEquals(24, termValueSet.getTotalConcepts().intValue());
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
@ -741,9 +748,17 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
myCaptureQueriesListener.clear();
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(3, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
assertThat(myCaptureQueriesListener.getUpdateQueriesForCurrentThread(), empty());
assertThat(myCaptureQueriesListener.getInsertQueriesForCurrentThread(), empty());
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());

View File

@ -87,6 +87,12 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.addForeignKey("FK_TRM_VSCD_VS_PID")
.toColumn("VALUESET_PID")
.references("TRM_VALUESET", "PID");
// TermValueSet
version.startSectionWithMessage("Processing table: TRM_VALUESET");
Builder.BuilderWithTableName termValueSetTable = version.onTable("TRM_VALUESET");
termValueSetTable.addColumn("TOTAL_CONCEPTS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
termValueSetTable.addColumn("TOTAL_CONCEPT_DESIGNATIONS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
}
protected void init400() {