Merge pull request #2872 from hapifhir/issue-2871-enhance-mdm-expansion

Add MDM expansion by golden pid
This commit is contained in:
Tadgh 2021-08-10 17:40:22 -04:00 committed by GitHub
commit a89798ad87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 6 deletions

View File

@ -75,6 +75,7 @@ public enum VersionEnum {
V5_4_1, V5_4_1,
V5_4_2, V5_4_2,
V5_5_0, V5_5_0,
; ;
public static VersionEnum latestVersion() { public static VersionEnum latestVersion() {

View File

@ -0,0 +1,5 @@
---
type: add
issue: 2871
title: "Modified the behaviour of the `:mdm` param qualifier. Previously, it used to only resolve IDs if the resource ID was a source resource.
Now, MDM expansion will work if you pass it the ID of a golden resource instead."

View File

@ -67,4 +67,7 @@ public interface IMdmLinkDao extends JpaRepository<MdmLink, Long> {
"AND ml.myMatchResult=:matchResult") "AND ml.myMatchResult=:matchResult")
List<MdmPidTuple> expandPidsBySourcePidAndMatchResult(@Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum); List<MdmPidTuple> expandPidsBySourcePidAndMatchResult(@Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
@Query("SELECT ml.myGoldenResourcePid as goldenPid, ml.mySourcePid as sourcePid FROM MdmLink ml WHERE ml.myGoldenResourcePid = :goldenPid and ml.myMatchResult = :matchResult")
List<MdmPidTuple> expandPidsByGoldenResourcePidAndMatchResult(@Param("goldenPid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
} }

View File

@ -25,15 +25,13 @@ import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.log.Logs; import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import javax.annotation.Nonnull;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -82,14 +80,50 @@ public class MdmLinkExpandSvc {
public Set<String> expandMdmBySourceResourcePid(Long theSourceResourcePid) { public Set<String> expandMdmBySourceResourcePid(Long theSourceResourcePid) {
ourLog.debug("About to expand source resource with PID {}", theSourceResourcePid); ourLog.debug("About to expand source resource with PID {}", theSourceResourcePid);
List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuples = myMdmLinkDao.expandPidsBySourcePidAndMatchResult(theSourceResourcePid, MdmMatchResultEnum.MATCH); List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuples = myMdmLinkDao.expandPidsBySourcePidAndMatchResult(theSourceResourcePid, MdmMatchResultEnum.MATCH);
return flattenPidTuplesToSet(theSourceResourcePid, goldenPidSourcePidTuples);
}
/**
* Given a PID of a golden resource, perform MDM expansion and return all the resource IDs of all resources that are
* MDM-Matched to this golden resource.
*
* @param theGoldenResourcePid The PID of the golden resource to MDM-Expand.
* @return A set of strings representing the FHIR ids of the expanded resources.
*/
public Set<String> expandMdmByGoldenResourceId(Long theGoldenResourcePid) {
ourLog.debug("About to expand golden resource with PID {}", theGoldenResourcePid);
List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuples = myMdmLinkDao.expandPidsByGoldenResourcePidAndMatchResult(theGoldenResourcePid, MdmMatchResultEnum.MATCH);
return flattenPidTuplesToSet(theGoldenResourcePid, goldenPidSourcePidTuples);
}
/**
* Given a resource ID of a golden resource, perform MDM expansion and return all the resource IDs of all resources that are
* MDM-Matched to this golden resource.
*
* @param theGoldenResourcePid The resource ID of the golden resource to MDM-Expand.
* @return A set of strings representing the FHIR ids of the expanded resources.
*/
public Set<String> expandMdmByGoldenResourcePid(Long theGoldenResourcePid) {
ourLog.debug("About to expand golden resource with PID {}", theGoldenResourcePid);
List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuples = myMdmLinkDao.expandPidsByGoldenResourcePidAndMatchResult(theGoldenResourcePid, MdmMatchResultEnum.MATCH);
return flattenPidTuplesToSet(theGoldenResourcePid, goldenPidSourcePidTuples);
}
public Set<String> expandMdmByGoldenResourceId(IdDt theId) {
ourLog.debug("About to expand golden resource with golden resource id {}", theId);
Long pidOrThrowException = myIdHelperService.getPidOrThrowException(theId);
return expandMdmByGoldenResourcePid(pidOrThrowException);
}
@Nonnull
private Set<String> flattenPidTuplesToSet(Long initialPid, List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuples) {
Set<Long> flattenedPids = new HashSet<>(); Set<Long> flattenedPids = new HashSet<>();
goldenPidSourcePidTuples.forEach(tuple -> { goldenPidSourcePidTuples.forEach(tuple -> {
flattenedPids.add(tuple.getSourcePid()); flattenedPids.add(tuple.getSourcePid());
flattenedPids.add(tuple.getGoldenPid()); flattenedPids.add(tuple.getGoldenPid());
}); });
Set<String> resourceIds = myIdHelperService.translatePidsToFhirResourceIds(flattenedPids); Set<String> resourceIds = myIdHelperService.translatePidsToFhirResourceIds(flattenedPids);
ourLog.debug("Pid {} has been expanded to [{}]", theSourceResourcePid, String.join(",", resourceIds)); ourLog.debug("Pid {} has been expanded to [{}]", initialPid, String.join(",", resourceIds));
return resourceIds; return resourceIds;
} }
} }

View File

@ -76,8 +76,16 @@ public class MdmSearchExpandingInterceptor {
if (iQueryParameterType instanceof ReferenceParam) { if (iQueryParameterType instanceof ReferenceParam) {
ReferenceParam refParam = (ReferenceParam) iQueryParameterType; ReferenceParam refParam = (ReferenceParam) iQueryParameterType;
if (refParam.isMdmExpand()) { if (refParam.isMdmExpand()) {
ourLog.debug("Found a reference parameter to expand: {}", refParam.toString()); ourLog.debug("Found a reference parameter to expand: {}", refParam);
//First, attempt to expand as a source resource.
Set<String> expandedResourceIds = myMdmLinkExpandSvc.expandMdmBySourceResourceId(new IdDt(refParam.getValue())); Set<String> expandedResourceIds = myMdmLinkExpandSvc.expandMdmBySourceResourceId(new IdDt(refParam.getValue()));
// If we failed, attempt to expand as a golden resource
if (expandedResourceIds.isEmpty()) {
expandedResourceIds = myMdmLinkExpandSvc.expandMdmByGoldenResourceId(new IdDt(refParam.getValue()));
}
//Rebuild the search param list.
if (!expandedResourceIds.isEmpty()) { if (!expandedResourceIds.isEmpty()) {
ourLog.debug("Parameter has been expanded to: {}", String.join(", ", expandedResourceIds)); ourLog.debug("Parameter has been expanded to: {}", String.join(", ", expandedResourceIds));
toRemove.add(refParam); toRemove.add(refParam);

View File

@ -2,14 +2,18 @@ package ca.uhn.fhir.jpa.mdm.interceptor;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test; import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig; import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4; import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.MdmConstants; import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.ReferenceOrListParam; import ca.uhn.fhir.rest.param.ReferenceOrListParam;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import org.elasticsearch.common.collect.Set;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
@ -21,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -73,6 +79,19 @@ public class MdmSearchExpandingInterceptorIT extends BaseMdmR4Test {
myDaoConfig.setAllowMdmExpansion(true); myDaoConfig.setAllowMdmExpansion(true);
search = myObservationDao.search(searchParameterMap); search = myObservationDao.search(searchParameterMap);
assertThat(search.size(), is(equalTo(4))); assertThat(search.size(), is(equalTo(4)));
List<MdmLink> all = myMdmLinkDao.findAll();
Long goldenPid = all.get(0).getGoldenResourcePid();
IIdType goldenId = myIdHelperService.translatePidIdToForcedId(myFhirContext, "Patient", new ResourcePersistentId(goldenPid));
//Verify that expansion by the golden resource id resolves down to everything its links have.
SearchParameterMap goldenSpMap = new SearchParameterMap();
goldenSpMap.setLoadSynchronous(true);
ReferenceOrListParam goldenReferenceOrListParam = new ReferenceOrListParam();
goldenReferenceOrListParam.addOr(new ReferenceParam(goldenId).setMdmExpand(true));
goldenSpMap.add(Observation.SP_SUBJECT, goldenReferenceOrListParam);
search = myObservationDao.search(goldenSpMap);
assertThat(search.size(), is(equalTo(4)));
} }
@Test @Test