Additional changes to enable processing of lastn operations with large numbers of parameters.
This commit is contained in:
parent
3e49e5615f
commit
4db5beeabf
|
@ -38,7 +38,7 @@ public abstract class BaseHapiFhirResourceDaoObservation<T extends IBaseResource
|
||||||
if (theSearchParameterMap.getSort() == null) {
|
if (theSearchParameterMap.getSort() == null) {
|
||||||
SortSpec effectiveDtm = new SortSpec("date").setOrder(SortOrderEnum.DESC);
|
SortSpec effectiveDtm = new SortSpec("date").setOrder(SortOrderEnum.DESC);
|
||||||
SortSpec observationCode = new SortSpec(IndexConstants.CODE_SEARCH_PARAM).setOrder(SortOrderEnum.ASC).setChain(effectiveDtm);
|
SortSpec observationCode = new SortSpec(IndexConstants.CODE_SEARCH_PARAM).setOrder(SortOrderEnum.ASC).setChain(effectiveDtm);
|
||||||
theSearchParameterMap.setSort(new SortSpec(IndexConstants.SUBJECT_SEARCH_PARAM).setChain(observationCode));
|
theSearchParameterMap.setSort(new SortSpec(IndexConstants.SUBJECT_SEARCH_PARAM).setOrder(SortOrderEnum.ASC).setChain(observationCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,16 +351,19 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Integer myMaxObservationsPerCode = null;
|
Integer myMaxObservationsPerCode = null;
|
||||||
String[] maxCountParams = theRequest.getParameters().get("max");
|
// String[] maxCountParams = theRequest.getParameters().get("max");
|
||||||
if (maxCountParams != null && maxCountParams.length > 0) {
|
// if (maxCountParams != null && maxCountParams.length > 0) {
|
||||||
myMaxObservationsPerCode = Integer.valueOf(maxCountParams[0]);
|
// myMaxObservationsPerCode = Integer.valueOf(maxCountParams[0]);
|
||||||
|
if(myParams.getLastNMax() != null) {
|
||||||
|
myMaxObservationsPerCode = myParams.getLastNMax();
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidRequestException("Max parameter is required for $lastn operation");
|
throw new InvalidRequestException("Max parameter is required for $lastn operation");
|
||||||
}
|
}
|
||||||
List<String> lastnResourceIds = myIElasticsearchSvc.executeLastN(myParams, myMaxObservationsPerCode);
|
List<String> lastnResourceIds = myIElasticsearchSvc.executeLastN(myParams, myMaxObservationsPerCode);
|
||||||
for (String lastnResourceId : lastnResourceIds) {
|
// for (String lastnResourceId : lastnResourceIds) {
|
||||||
pids.add(myIdHelperService.resolveResourcePersistentIds(myRequestPartitionId, myResourceName, lastnResourceId));
|
// pids.add(myIdHelperService.resolveResourcePersistentIds(myRequestPartitionId, myResourceName, lastnResourceId));
|
||||||
}
|
// }
|
||||||
|
pids = normalizeIdListForLastNInClause(lastnResourceIds);
|
||||||
}
|
}
|
||||||
if (pids.isEmpty()) {
|
if (pids.isEmpty()) {
|
||||||
// Will never match
|
// Will never match
|
||||||
|
@ -411,6 +414,50 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ResourcePersistentId> normalizeIdListForLastNInClause(List<String> lastnResourceIds) {
|
||||||
|
List<ResourcePersistentId> retVal = new ArrayList<>();
|
||||||
|
for (String lastnResourceId : lastnResourceIds) {
|
||||||
|
retVal.add(new ResourcePersistentId(Long.parseLong(lastnResourceId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following is a workaround to a known issue involving Hibernate. If queries are used with "in" clauses with large and varying
|
||||||
|
numbers of parameters, this can overwhelm Hibernate's QueryPlanCache and deplete heap space. See the following link for more info:
|
||||||
|
https://stackoverflow.com/questions/31557076/spring-hibernate-query-plan-cache-memory-usage.
|
||||||
|
|
||||||
|
Normalizing the number of parameters in the "in" clause stabilizes the size of the QueryPlanCache, so long as the number of
|
||||||
|
arguments never exceeds the maximum specified below.
|
||||||
|
*/
|
||||||
|
int listSize = retVal.size();
|
||||||
|
if(listSize > 1 && listSize < 10) {
|
||||||
|
padIdListWithPlaceholders(retVal, 10);
|
||||||
|
} else if (listSize > 10 && listSize < 100) {
|
||||||
|
padIdListWithPlaceholders(retVal, 100);
|
||||||
|
} else if (listSize > 100 && listSize < 200) {
|
||||||
|
padIdListWithPlaceholders(retVal, 200);
|
||||||
|
} else if (listSize > 200 && listSize < 500) {
|
||||||
|
padIdListWithPlaceholders(retVal, 500);
|
||||||
|
} else if (listSize > 500 && listSize < 1000) {
|
||||||
|
padIdListWithPlaceholders(retVal, 1000);
|
||||||
|
} else if (listSize > 1000 && listSize < 500) {
|
||||||
|
padIdListWithPlaceholders(retVal, 5000);
|
||||||
|
} else if (listSize > 5000 && listSize < 10000) {
|
||||||
|
padIdListWithPlaceholders(retVal, 10000);
|
||||||
|
} else if (listSize > 10000 && listSize < 20000) {
|
||||||
|
padIdListWithPlaceholders(retVal, 20000);
|
||||||
|
} else if (listSize > 20000 && listSize < 30000) {
|
||||||
|
padIdListWithPlaceholders(retVal, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void padIdListWithPlaceholders(List<ResourcePersistentId> theIdList, int preferredListSize) {
|
||||||
|
while(theIdList.size() < preferredListSize) {
|
||||||
|
theIdList.add(new ResourcePersistentId(-1L));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns {@literal true} if any search parameter sorts were found, or false if
|
* @return Returns {@literal true} if any search parameter sorts were found, or false if
|
||||||
* no sorts were found, or only non-search parameters ones (e.g. _id, _lastUpdated)
|
* no sorts were found, or only non-search parameters ones (e.g. _id, _lastUpdated)
|
||||||
|
@ -1190,7 +1237,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
mySearchRuntimeDetails.setQueryStopwatch(new StopWatch());
|
mySearchRuntimeDetails.setQueryStopwatch(new StopWatch());
|
||||||
|
|
||||||
Query<Long> hibernateQuery = (Query<Long>) query;
|
Query<Long> hibernateQuery = (Query<Long>) query;
|
||||||
hibernateQuery.setFetchSize(myFetchSize);
|
hibernateQuery.setFetchSize(myFetchSize);
|
||||||
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
myResultsIterator = new ScrollableResultsIterator<>(scroll);
|
myResultsIterator = new ScrollableResultsIterator<>(scroll);
|
||||||
|
|
|
@ -29,6 +29,8 @@ import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.dstu3.model.Observation;
|
import org.hl7.fhir.dstu3.model.Observation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
|
@ -29,6 +29,8 @@ import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r5.model.Observation;
|
import org.hl7.fhir.r5.model.Observation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
|
@ -3,19 +3,17 @@ package ca.uhn.fhir.jpa.provider.dstu3;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.annotation.*;
|
import ca.uhn.fhir.rest.annotation.*;
|
||||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
import org.hl7.fhir.dstu3.model.Observation;
|
import org.hl7.fhir.dstu3.model.Observation;
|
||||||
|
import org.hl7.fhir.dstu3.model.UnsignedIntType;
|
||||||
import java.util.Set;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -50,17 +48,9 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider
|
||||||
|
|
||||||
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a filter")
|
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_FILTER)
|
@OperationParam(name = Constants.PARAM_COUNT)
|
||||||
StringAndListParam theFtFilter,
|
UnsignedIntType theCount,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
|
|
||||||
StringAndListParam theFtContent,
|
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
|
|
||||||
StringAndListParam theFtText,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The classification of the type of observation")
|
@Description(shortDefinition="The classification of the type of observation")
|
||||||
@OperationParam(name="category")
|
@OperationParam(name="category")
|
||||||
|
@ -70,10 +60,6 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider
|
||||||
@OperationParam(name="code")
|
@OperationParam(name="code")
|
||||||
TokenAndListParam theCode,
|
TokenAndListParam theCode,
|
||||||
|
|
||||||
@Description(shortDefinition="Obtained date/time. If the obtained element is a period, a date that falls in the period")
|
|
||||||
@OperationParam(name="date")
|
|
||||||
DateRangeParam theDate,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
||||||
@OperationParam(name="patient")
|
@OperationParam(name="patient")
|
||||||
ReferenceAndListParam thePatient,
|
ReferenceAndListParam thePatient,
|
||||||
|
@ -82,69 +68,31 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider
|
||||||
@OperationParam(name="subject" )
|
@OperationParam(name="subject" )
|
||||||
ReferenceAndListParam theSubject,
|
ReferenceAndListParam theSubject,
|
||||||
|
|
||||||
@IncludeParam(reverse=true)
|
@Description(shortDefinition="The maximum number of observations to return for each observation code")
|
||||||
Set<Include> theRevIncludes,
|
@OperationParam(name = "max", typeName = "integer", min = 0, max = 1)
|
||||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
IPrimitiveType<Integer> theMax,
|
||||||
@OperationParam(name="_lastUpdated")
|
|
||||||
DateRangeParam theLastUpdated,
|
|
||||||
|
|
||||||
@IncludeParam(allow= {
|
|
||||||
"Observation:based-on",
|
|
||||||
"Observation:derived-from",
|
|
||||||
"Observation:device",
|
|
||||||
"Observation:encounter",
|
|
||||||
"Observation:focus",
|
|
||||||
"Observation:has-member",
|
|
||||||
"Observation:part-of",
|
|
||||||
"Observation:patient",
|
|
||||||
"Observation:performer",
|
|
||||||
"Observation:specimen",
|
|
||||||
"Observation:subject",
|
|
||||||
"*"
|
|
||||||
})
|
|
||||||
Set<Include> theIncludes,
|
|
||||||
|
|
||||||
@Sort
|
@Sort
|
||||||
SortSpec theSort,
|
SortSpec theSort
|
||||||
|
|
||||||
@ca.uhn.fhir.rest.annotation.Count
|
|
||||||
Integer theCount,
|
|
||||||
|
|
||||||
SummaryEnum theSummaryMode,
|
|
||||||
|
|
||||||
SearchTotalModeEnum theSearchTotalMode
|
|
||||||
|
|
||||||
) {
|
) {
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_FILTER, theFtFilter);
|
paramMap.add(Observation.SP_CATEGORY, theCategory);
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
|
paramMap.add(Observation.SP_CODE, theCode);
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
|
paramMap.add(Observation.SP_PATIENT, thePatient);
|
||||||
paramMap.add("category", theCategory);
|
paramMap.add(Observation.SP_SUBJECT, theSubject);
|
||||||
paramMap.add("code", theCode);
|
paramMap.setLastNMax(theMax.getValue());
|
||||||
paramMap.add("date", theDate);
|
if (theCount != null) {
|
||||||
paramMap.add("patient", thePatient);
|
paramMap.setCount(theCount.getValue());
|
||||||
paramMap.add("subject", theSubject);
|
|
||||||
paramMap.setRevIncludes(theRevIncludes);
|
|
||||||
paramMap.setLastUpdated(theLastUpdated);
|
|
||||||
paramMap.setIncludes(theIncludes);
|
|
||||||
paramMap.setLastN(true);
|
|
||||||
if (theSort == null) {
|
|
||||||
SortSpec effectiveDtm = new SortSpec("date").setOrder(SortOrderEnum.DESC);
|
|
||||||
SortSpec observationCode = new SortSpec("code").setOrder(SortOrderEnum.ASC).setChain(effectiveDtm);
|
|
||||||
if (thePatient != null && theSubject == null) {
|
|
||||||
theSort = new SortSpec("patient").setChain(observationCode);
|
|
||||||
} else {
|
|
||||||
theSort = new SortSpec("subject").setChain(observationCode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
paramMap.setSort(theSort);
|
|
||||||
paramMap.setCount(theCount);
|
|
||||||
paramMap.setSummaryMode(theSummaryMode);
|
|
||||||
paramMap.setSearchTotalMode(theSearchTotalMode);
|
|
||||||
|
|
||||||
return ((IFhirResourceDaoObservation<org.hl7.fhir.dstu3.model.Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
if (theSort != null) {
|
||||||
|
paramMap.setSort(theSort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((IFhirResourceDaoObservation<Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
||||||
} finally {
|
} finally {
|
||||||
endRequest(theServletRequest);
|
endRequest(theServletRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,20 +3,17 @@ package ca.uhn.fhir.jpa.provider.r4;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.annotation.*;
|
import ca.uhn.fhir.rest.annotation.*;
|
||||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server
|
* HAPI FHIR JPA Server
|
||||||
|
@ -50,17 +47,9 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4<
|
||||||
|
|
||||||
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a filter")
|
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_FILTER)
|
@OperationParam(name = Constants.PARAM_COUNT)
|
||||||
StringAndListParam theFtFilter,
|
UnsignedIntType theCount,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
|
|
||||||
StringAndListParam theFtContent,
|
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
|
|
||||||
StringAndListParam theFtText,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The classification of the type of observation")
|
@Description(shortDefinition="The classification of the type of observation")
|
||||||
@OperationParam(name="category")
|
@OperationParam(name="category")
|
||||||
|
@ -70,10 +59,6 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4<
|
||||||
@OperationParam(name="code")
|
@OperationParam(name="code")
|
||||||
TokenAndListParam theCode,
|
TokenAndListParam theCode,
|
||||||
|
|
||||||
@Description(shortDefinition="Obtained date/time. If the obtained element is a period, a date that falls in the period")
|
|
||||||
@OperationParam(name="date")
|
|
||||||
DateRangeParam theDate,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
||||||
@OperationParam(name="patient")
|
@OperationParam(name="patient")
|
||||||
ReferenceAndListParam thePatient,
|
ReferenceAndListParam thePatient,
|
||||||
|
@ -82,67 +67,29 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4<
|
||||||
@OperationParam(name="subject" )
|
@OperationParam(name="subject" )
|
||||||
ReferenceAndListParam theSubject,
|
ReferenceAndListParam theSubject,
|
||||||
|
|
||||||
@IncludeParam(reverse=true)
|
@Description(shortDefinition="The maximum number of observations to return for each observation code")
|
||||||
Set<Include> theRevIncludes,
|
@OperationParam(name = "max", typeName = "integer", min = 0, max = 1)
|
||||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
IPrimitiveType<Integer> theMax,
|
||||||
@OperationParam(name="_lastUpdated")
|
|
||||||
DateRangeParam theLastUpdated,
|
|
||||||
|
|
||||||
@IncludeParam(allow= {
|
|
||||||
"Observation:based-on",
|
|
||||||
"Observation:derived-from",
|
|
||||||
"Observation:device",
|
|
||||||
"Observation:encounter",
|
|
||||||
"Observation:focus",
|
|
||||||
"Observation:has-member",
|
|
||||||
"Observation:part-of",
|
|
||||||
"Observation:patient",
|
|
||||||
"Observation:performer",
|
|
||||||
"Observation:specimen",
|
|
||||||
"Observation:subject",
|
|
||||||
"*"
|
|
||||||
})
|
|
||||||
Set<Include> theIncludes,
|
|
||||||
|
|
||||||
@Sort
|
@Sort
|
||||||
SortSpec theSort,
|
SortSpec theSort
|
||||||
|
|
||||||
@ca.uhn.fhir.rest.annotation.Count
|
|
||||||
Integer theCount,
|
|
||||||
|
|
||||||
SummaryEnum theSummaryMode,
|
|
||||||
|
|
||||||
SearchTotalModeEnum theSearchTotalMode
|
|
||||||
|
|
||||||
) {
|
) {
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_FILTER, theFtFilter);
|
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
|
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
|
|
||||||
paramMap.add("category", theCategory);
|
paramMap.add("category", theCategory);
|
||||||
paramMap.add("code", theCode);
|
paramMap.add("code", theCode);
|
||||||
paramMap.add("date", theDate);
|
|
||||||
paramMap.add("patient", thePatient);
|
paramMap.add("patient", thePatient);
|
||||||
paramMap.add("subject", theSubject);
|
paramMap.add("subject", theSubject);
|
||||||
paramMap.setRevIncludes(theRevIncludes);
|
paramMap.setLastNMax(theMax.getValue());
|
||||||
paramMap.setLastUpdated(theLastUpdated);
|
if (theCount != null) {
|
||||||
paramMap.setIncludes(theIncludes);
|
paramMap.setCount(theCount.getValue());
|
||||||
/* paramMap.setLastN(true);
|
}
|
||||||
if (theSort == null) {
|
|
||||||
SortSpec effectiveDtm = new SortSpec("date").setOrder(SortOrderEnum.DESC);
|
if (theSort != null) {
|
||||||
SortSpec observationCode = new SortSpec("code").setOrder(SortOrderEnum.ASC).setChain(effectiveDtm);
|
paramMap.setSort(theSort);
|
||||||
if (thePatient != null && theSubject == null) {
|
}
|
||||||
theSort = new SortSpec("patient").setChain(observationCode);
|
|
||||||
} else {
|
|
||||||
theSort = new SortSpec("subject").setChain(observationCode);
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
paramMap.setSort(theSort);
|
|
||||||
paramMap.setCount(theCount);
|
|
||||||
paramMap.setSummaryMode(theSummaryMode);
|
|
||||||
paramMap.setSearchTotalMode(theSearchTotalMode);
|
|
||||||
|
|
||||||
return ((IFhirResourceDaoObservation<Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
return ((IFhirResourceDaoObservation<Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -3,20 +3,18 @@ package ca.uhn.fhir.jpa.provider.r5;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.annotation.*;
|
import ca.uhn.fhir.rest.annotation.*;
|
||||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r5.model.UnsignedIntType;
|
||||||
import org.hl7.fhir.r5.model.Observation;
|
import org.hl7.fhir.r5.model.Observation;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server
|
* HAPI FHIR JPA Server
|
||||||
|
@ -50,17 +48,9 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5<
|
||||||
|
|
||||||
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a filter")
|
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_FILTER)
|
@OperationParam(name = Constants.PARAM_COUNT)
|
||||||
StringAndListParam theFtFilter,
|
UnsignedIntType theCount,
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
|
|
||||||
StringAndListParam theFtContent,
|
|
||||||
|
|
||||||
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
|
|
||||||
@OperationParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
|
|
||||||
StringAndListParam theFtText,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The classification of the type of observation")
|
@Description(shortDefinition="The classification of the type of observation")
|
||||||
@OperationParam(name="category")
|
@OperationParam(name="category")
|
||||||
|
@ -70,10 +60,6 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5<
|
||||||
@OperationParam(name="code")
|
@OperationParam(name="code")
|
||||||
TokenAndListParam theCode,
|
TokenAndListParam theCode,
|
||||||
|
|
||||||
@Description(shortDefinition="Obtained date/time. If the obtained element is a period, a date that falls in the period")
|
|
||||||
@OperationParam(name="date")
|
|
||||||
DateRangeParam theDate,
|
|
||||||
|
|
||||||
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
@Description(shortDefinition="The subject that the observation is about (if patient)")
|
||||||
@OperationParam(name="patient")
|
@OperationParam(name="patient")
|
||||||
ReferenceAndListParam thePatient,
|
ReferenceAndListParam thePatient,
|
||||||
|
@ -82,69 +68,31 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5<
|
||||||
@OperationParam(name="subject" )
|
@OperationParam(name="subject" )
|
||||||
ReferenceAndListParam theSubject,
|
ReferenceAndListParam theSubject,
|
||||||
|
|
||||||
@IncludeParam(reverse=true)
|
@Description(shortDefinition="The maximum number of observations to return for each observation code")
|
||||||
Set<Include> theRevIncludes,
|
@OperationParam(name = "max", typeName = "integer", min = 0, max = 1)
|
||||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
IPrimitiveType<Integer> theMax,
|
||||||
@OperationParam(name="_lastUpdated")
|
|
||||||
DateRangeParam theLastUpdated,
|
|
||||||
|
|
||||||
@IncludeParam(allow= {
|
|
||||||
"Observation:based-on",
|
|
||||||
"Observation:derived-from",
|
|
||||||
"Observation:device",
|
|
||||||
"Observation:encounter",
|
|
||||||
"Observation:focus",
|
|
||||||
"Observation:has-member",
|
|
||||||
"Observation:part-of",
|
|
||||||
"Observation:patient",
|
|
||||||
"Observation:performer",
|
|
||||||
"Observation:specimen",
|
|
||||||
"Observation:subject",
|
|
||||||
"*"
|
|
||||||
})
|
|
||||||
Set<Include> theIncludes,
|
|
||||||
|
|
||||||
@Sort
|
@Sort
|
||||||
SortSpec theSort,
|
SortSpec theSort
|
||||||
|
|
||||||
@ca.uhn.fhir.rest.annotation.Count
|
|
||||||
Integer theCount,
|
|
||||||
|
|
||||||
SummaryEnum theSummaryMode,
|
|
||||||
|
|
||||||
SearchTotalModeEnum theSearchTotalMode
|
|
||||||
|
|
||||||
) {
|
) {
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_FILTER, theFtFilter);
|
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
|
|
||||||
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
|
|
||||||
paramMap.add("category", theCategory);
|
paramMap.add("category", theCategory);
|
||||||
paramMap.add("code", theCode);
|
paramMap.add("code", theCode);
|
||||||
paramMap.add("date", theDate);
|
|
||||||
paramMap.add("patient", thePatient);
|
paramMap.add("patient", thePatient);
|
||||||
paramMap.add("subject", theSubject);
|
paramMap.add("subject", theSubject);
|
||||||
paramMap.setRevIncludes(theRevIncludes);
|
paramMap.setLastNMax(theMax.getValue());
|
||||||
paramMap.setLastUpdated(theLastUpdated);
|
if (theCount != null) {
|
||||||
paramMap.setIncludes(theIncludes);
|
paramMap.setCount(theCount.getValue());
|
||||||
paramMap.setLastN(true);
|
|
||||||
if (theSort == null) {
|
|
||||||
SortSpec effectiveDtm = new SortSpec("date").setOrder(SortOrderEnum.DESC);
|
|
||||||
SortSpec observationCode = new SortSpec("code").setOrder(SortOrderEnum.ASC).setChain(effectiveDtm);
|
|
||||||
if (thePatient != null && theSubject == null) {
|
|
||||||
theSort = new SortSpec("patient").setChain(observationCode);
|
|
||||||
} else {
|
|
||||||
theSort = new SortSpec("subject").setChain(observationCode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
paramMap.setSort(theSort);
|
|
||||||
paramMap.setCount(theCount);
|
|
||||||
paramMap.setSummaryMode(theSummaryMode);
|
|
||||||
paramMap.setSearchTotalMode(theSearchTotalMode);
|
|
||||||
|
|
||||||
return ((IFhirResourceDaoObservation<org.hl7.fhir.r5.model.Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
if (theSort != null) {
|
||||||
|
paramMap.setSort(theSort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((IFhirResourceDaoObservation<Observation>) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse);
|
||||||
} finally {
|
} finally {
|
||||||
endRequest(theServletRequest);
|
endRequest(theServletRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.search.lastn;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
||||||
|
@ -42,6 +43,7 @@ import org.shadehapi.elasticsearch.search.sort.SortOrder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
|
@ -200,21 +202,64 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
@Override
|
@Override
|
||||||
public List<String> executeLastN(SearchParameterMap theSearchParameterMap, Integer theMaxObservationsPerCode) {
|
public List<String> executeLastN(SearchParameterMap theSearchParameterMap, Integer theMaxObservationsPerCode) {
|
||||||
String[] topHitsInclude = {OBSERVATION_IDENTIFIER_FIELD_NAME};
|
String[] topHitsInclude = {OBSERVATION_IDENTIFIER_FIELD_NAME};
|
||||||
SearchRequest myLastNRequest = buildObservationsSearchRequest(theSearchParameterMap, createCompositeAggregationBuilder(theMaxObservationsPerCode, topHitsInclude));
|
|
||||||
try {
|
try {
|
||||||
SearchResponse lastnResponse = executeSearchRequest(myLastNRequest);
|
List<SearchResponse> responses = buildAndExecuteSearch(theSearchParameterMap, theMaxObservationsPerCode, topHitsInclude);
|
||||||
return buildObservationIdList(lastnResponse);
|
List<String> observationIds = new ArrayList<>();
|
||||||
|
for (SearchResponse response : responses) {
|
||||||
|
// observationIds.addAll(buildObservationIdList(response));
|
||||||
|
observationIds.addAll(buildObservationList(response, t -> t.getIdentifier(), theSearchParameterMap));
|
||||||
|
}
|
||||||
|
return observationIds;
|
||||||
} catch (IOException theE) {
|
} catch (IOException theE) {
|
||||||
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<SearchResponse> buildAndExecuteSearch(SearchParameterMap theSearchParameterMap, Integer theMaxObservationsPerCode, String[] topHitsInclude) {
|
||||||
|
List<SearchResponse> responses = new ArrayList<>();
|
||||||
|
if (theSearchParameterMap.containsKey(IndexConstants.PATIENT_SEARCH_PARAM) || theSearchParameterMap.containsKey(IndexConstants.SUBJECT_SEARCH_PARAM)) {
|
||||||
|
ArrayList<String> subjectReferenceCriteria = new ArrayList<>();
|
||||||
|
List<List<IQueryParameterType>> patientParams = new ArrayList<>();
|
||||||
|
if (theSearchParameterMap.get(IndexConstants.PATIENT_SEARCH_PARAM) != null) {
|
||||||
|
patientParams.addAll(theSearchParameterMap.get(IndexConstants.PATIENT_SEARCH_PARAM));
|
||||||
|
}
|
||||||
|
if (theSearchParameterMap.get(IndexConstants.SUBJECT_SEARCH_PARAM) != null) {
|
||||||
|
patientParams.addAll(theSearchParameterMap.get(IndexConstants.SUBJECT_SEARCH_PARAM));
|
||||||
|
}
|
||||||
|
for (List<? extends IQueryParameterType> nextSubjectList : patientParams) {
|
||||||
|
subjectReferenceCriteria.addAll(getReferenceValues(nextSubjectList));
|
||||||
|
}
|
||||||
|
for (String subject : subjectReferenceCriteria) {
|
||||||
|
SearchRequest myLastNRequest = buildObservationsSearchRequest(subject, theSearchParameterMap, createCompositeAggregationBuilder(theMaxObservationsPerCode, topHitsInclude));
|
||||||
|
try {
|
||||||
|
SearchResponse lastnResponse = executeSearchRequest(myLastNRequest);
|
||||||
|
responses.add(lastnResponse);
|
||||||
|
} catch (IOException theE) {
|
||||||
|
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SearchRequest myLastNRequest = buildObservationsSearchRequest(theSearchParameterMap, createObservationCodeAggregationBuilder(theMaxObservationsPerCode, topHitsInclude));
|
||||||
|
try {
|
||||||
|
SearchResponse lastnResponse = executeSearchRequest(myLastNRequest);
|
||||||
|
responses.add(lastnResponse);
|
||||||
|
} catch (IOException theE) {
|
||||||
|
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<ObservationJson> executeLastNWithAllFields(SearchParameterMap theSearchParameterMap, Integer theMaxObservationsPerCode) {
|
List<ObservationJson> executeLastNWithAllFields(SearchParameterMap theSearchParameterMap, Integer theMaxObservationsPerCode) {
|
||||||
SearchRequest myLastNRequest = buildObservationsSearchRequest(theSearchParameterMap, createCompositeAggregationBuilder(theMaxObservationsPerCode, null));
|
|
||||||
try {
|
try {
|
||||||
SearchResponse lastnResponse = executeSearchRequest(myLastNRequest);
|
List<SearchResponse> responses = buildAndExecuteSearch(theSearchParameterMap, theMaxObservationsPerCode, null);
|
||||||
return buildObservationDocumentList(lastnResponse);
|
List<ObservationJson> observationDocuments = new ArrayList<>();
|
||||||
|
for (SearchResponse response : responses) {
|
||||||
|
observationDocuments.addAll(buildObservationList(response, t -> t, theSearchParameterMap));
|
||||||
|
}
|
||||||
|
return observationDocuments;
|
||||||
} catch (IOException theE) {
|
} catch (IOException theE) {
|
||||||
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
throw new InvalidRequestException("Unable to execute LastN request", theE);
|
||||||
}
|
}
|
||||||
|
@ -227,8 +272,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
return buildCodeResult(codeSearchResponse);
|
return buildCodeResult(codeSearchResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
private SearchRequest buildObservationCodesSearchRequest(int theMaxResultSetSize) {
|
||||||
SearchRequest buildObservationCodesSearchRequest(int theMaxResultSetSize) {
|
|
||||||
SearchRequest searchRequest = new SearchRequest(IndexConstants.CODE_INDEX);
|
SearchRequest searchRequest = new SearchRequest(IndexConstants.CODE_INDEX);
|
||||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||||
// Query
|
// Query
|
||||||
|
@ -239,27 +283,30 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompositeAggregationBuilder createCompositeAggregationBuilder(int theMaxNumberObservationsPerCode, String[] theTopHitsInclude) {
|
private CompositeAggregationBuilder createCompositeAggregationBuilder(int theMaxNumberObservationsPerCode, String[] theTopHitsInclude) {
|
||||||
|
CompositeValuesSourceBuilder<?> subjectValuesBuilder = new TermsValuesSourceBuilder("subject").field("subject");
|
||||||
|
List<CompositeValuesSourceBuilder<?>> compositeAggSubjectSources = new ArrayList();
|
||||||
|
compositeAggSubjectSources.add(subjectValuesBuilder);
|
||||||
|
CompositeAggregationBuilder compositeAggregationSubjectBuilder = new CompositeAggregationBuilder(GROUP_BY_SUBJECT, compositeAggSubjectSources);
|
||||||
|
compositeAggregationSubjectBuilder.subAggregation(createObservationCodeAggregationBuilder(theMaxNumberObservationsPerCode, theTopHitsInclude));
|
||||||
|
compositeAggregationSubjectBuilder.size(10000);
|
||||||
|
|
||||||
|
return compositeAggregationSubjectBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TermsAggregationBuilder createObservationCodeAggregationBuilder(int theMaxNumberObservationsPerCode, String[] theTopHitsInclude) {
|
||||||
TermsAggregationBuilder observationCodeAggregationBuilder = new TermsAggregationBuilder(GROUP_BY_CODE, ValueType.STRING).field("codeconceptid");
|
TermsAggregationBuilder observationCodeAggregationBuilder = new TermsAggregationBuilder(GROUP_BY_CODE, ValueType.STRING).field("codeconceptid");
|
||||||
// Top Hits Aggregation
|
// Top Hits Aggregation
|
||||||
observationCodeAggregationBuilder.subAggregation(AggregationBuilders.topHits("most_recent_effective")
|
observationCodeAggregationBuilder.subAggregation(AggregationBuilders.topHits("most_recent_effective")
|
||||||
.sort("effectivedtm", SortOrder.DESC)
|
.sort("effectivedtm", SortOrder.DESC)
|
||||||
.fetchSource(theTopHitsInclude, null).size(theMaxNumberObservationsPerCode));
|
.fetchSource(theTopHitsInclude, null).size(theMaxNumberObservationsPerCode));
|
||||||
observationCodeAggregationBuilder.size(10000);
|
observationCodeAggregationBuilder.size(10000);
|
||||||
CompositeValuesSourceBuilder<?> subjectValuesBuilder = new TermsValuesSourceBuilder("subject").field("subject");
|
return observationCodeAggregationBuilder;
|
||||||
List<CompositeValuesSourceBuilder<?>> compositeAggSubjectSources = new ArrayList();
|
|
||||||
compositeAggSubjectSources.add(subjectValuesBuilder);
|
|
||||||
CompositeAggregationBuilder compositeAggregationSubjectBuilder = new CompositeAggregationBuilder(GROUP_BY_SUBJECT, compositeAggSubjectSources);
|
|
||||||
compositeAggregationSubjectBuilder.subAggregation(observationCodeAggregationBuilder);
|
|
||||||
compositeAggregationSubjectBuilder.size(10000);
|
|
||||||
|
|
||||||
return compositeAggregationSubjectBuilder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchResponse executeSearchRequest(SearchRequest searchRequest) throws IOException {
|
public SearchResponse executeSearchRequest(SearchRequest searchRequest) throws IOException {
|
||||||
return myRestHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
|
return myRestHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<String> buildObservationIdList(SearchResponse theSearchResponse) throws IOException {
|
private List<String> buildObservationIdList(SearchResponse theSearchResponse) throws IOException {
|
||||||
List<String> theObservationList = new ArrayList<>();
|
List<String> theObservationList = new ArrayList<>();
|
||||||
for (ParsedComposite.ParsedBucket subjectBucket : getSubjectBuckets(theSearchResponse)) {
|
for (ParsedComposite.ParsedBucket subjectBucket : getSubjectBuckets(theSearchResponse)) {
|
||||||
|
@ -288,12 +335,43 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
return theObservationList;
|
return theObservationList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> List<T> buildObservationList(SearchResponse theSearchResponse, Function<ObservationJson,T> setValue, SearchParameterMap theSearchParameterMap) throws IOException {
|
||||||
|
List<T> theObservationList = new ArrayList<>();
|
||||||
|
if (theSearchParameterMap.containsKey(IndexConstants.PATIENT_SEARCH_PARAM) || theSearchParameterMap.containsKey(IndexConstants.SUBJECT_SEARCH_PARAM)) {
|
||||||
|
for (ParsedComposite.ParsedBucket subjectBucket : getSubjectBuckets(theSearchResponse)) {
|
||||||
|
for (Terms.Bucket observationCodeBucket : getObservationCodeBuckets(subjectBucket)) {
|
||||||
|
for (SearchHit lastNMatch : getLastNMatches(observationCodeBucket)) {
|
||||||
|
String indexedObservation = lastNMatch.getSourceAsString();
|
||||||
|
ObservationJson observationJson = objectMapper.readValue(indexedObservation, ObservationJson.class);
|
||||||
|
theObservationList.add(setValue.apply(observationJson));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Terms.Bucket observationCodeBucket : getObservationCodeBuckets(theSearchResponse)) {
|
||||||
|
for (SearchHit lastNMatch : getLastNMatches(observationCodeBucket)) {
|
||||||
|
String indexedObservation = lastNMatch.getSourceAsString();
|
||||||
|
ObservationJson observationJson = objectMapper.readValue(indexedObservation, ObservationJson.class);
|
||||||
|
theObservationList.add(setValue.apply(observationJson));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theObservationList;
|
||||||
|
}
|
||||||
|
|
||||||
private List<ParsedComposite.ParsedBucket> getSubjectBuckets(SearchResponse theSearchResponse) {
|
private List<ParsedComposite.ParsedBucket> getSubjectBuckets(SearchResponse theSearchResponse) {
|
||||||
Aggregations responseAggregations = theSearchResponse.getAggregations();
|
Aggregations responseAggregations = theSearchResponse.getAggregations();
|
||||||
ParsedComposite aggregatedSubjects = responseAggregations.get(GROUP_BY_SUBJECT);
|
ParsedComposite aggregatedSubjects = responseAggregations.get(GROUP_BY_SUBJECT);
|
||||||
return aggregatedSubjects.getBuckets();
|
return aggregatedSubjects.getBuckets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<? extends Terms.Bucket> getObservationCodeBuckets(SearchResponse theSearchResponse) {
|
||||||
|
Aggregations responseAggregations = theSearchResponse.getAggregations();
|
||||||
|
ParsedTerms aggregatedObservationCodes = responseAggregations.get(GROUP_BY_CODE);
|
||||||
|
return aggregatedObservationCodes.getBuckets();
|
||||||
|
}
|
||||||
|
|
||||||
private List<? extends Terms.Bucket> getObservationCodeBuckets(ParsedComposite.ParsedBucket theSubjectBucket) {
|
private List<? extends Terms.Bucket> getObservationCodeBuckets(ParsedComposite.ParsedBucket theSubjectBucket) {
|
||||||
Aggregations observationCodeAggregations = theSubjectBucket.getAggregations();
|
Aggregations observationCodeAggregations = theSubjectBucket.getAggregations();
|
||||||
ParsedTerms aggregatedObservationCodes = observationCodeAggregations.get(GROUP_BY_CODE);
|
ParsedTerms aggregatedObservationCodes = observationCodeAggregations.get(GROUP_BY_CODE);
|
||||||
|
@ -338,6 +416,24 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
return searchRequest;
|
return searchRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SearchRequest buildObservationsSearchRequest(String theSubjectParam, SearchParameterMap theSearchParameterMap, AggregationBuilder theAggregationBuilder) {
|
||||||
|
SearchRequest searchRequest = new SearchRequest(IndexConstants.OBSERVATION_INDEX);
|
||||||
|
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||||
|
// Query
|
||||||
|
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
||||||
|
boolQueryBuilder.must(QueryBuilders.termQuery("subject", theSubjectParam));
|
||||||
|
addCategoriesCriteria(boolQueryBuilder, theSearchParameterMap);
|
||||||
|
addObservationCodeCriteria(boolQueryBuilder, theSearchParameterMap);
|
||||||
|
searchSourceBuilder.query(boolQueryBuilder);
|
||||||
|
searchSourceBuilder.size(0);
|
||||||
|
|
||||||
|
// Aggregation by order codes
|
||||||
|
searchSourceBuilder.aggregation(theAggregationBuilder);
|
||||||
|
searchRequest.source(searchSourceBuilder);
|
||||||
|
|
||||||
|
return searchRequest;
|
||||||
|
}
|
||||||
|
|
||||||
private Boolean searchParamsHaveLastNCriteria(SearchParameterMap theSearchParameterMap) {
|
private Boolean searchParamsHaveLastNCriteria(SearchParameterMap theSearchParameterMap) {
|
||||||
return theSearchParameterMap != null &&
|
return theSearchParameterMap != null &&
|
||||||
(theSearchParameterMap.containsKey(IndexConstants.PATIENT_SEARCH_PARAM) || theSearchParameterMap.containsKey(IndexConstants.SUBJECT_SEARCH_PARAM) ||
|
(theSearchParameterMap.containsKey(IndexConstants.PATIENT_SEARCH_PARAM) || theSearchParameterMap.containsKey(IndexConstants.SUBJECT_SEARCH_PARAM) ||
|
||||||
|
@ -519,11 +615,12 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteObservationIndex(String theObservationIdentifier) throws IOException {
|
/* public void deleteObservationIndex(String theObservationIdentifier) throws IOException {
|
||||||
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(IndexConstants.OBSERVATION_DOCUMENT_TYPE);
|
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(IndexConstants.OBSERVATION_DOCUMENT_TYPE);
|
||||||
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
||||||
boolQueryBuilder.must(QueryBuilders.termsQuery(OBSERVATION_IDENTIFIER_FIELD_NAME, theObservationIdentifier));
|
boolQueryBuilder.must(QueryBuilders.termsQuery(OBSERVATION_IDENTIFIER_FIELD_NAME, theObservationIdentifier));
|
||||||
deleteByQueryRequest.setQuery(boolQueryBuilder);
|
deleteByQueryRequest.setQuery(boolQueryBuilder);
|
||||||
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.api.dao.*;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.config.TestR4ConfigWithElasticsearchClient;
|
import ca.uhn.fhir.jpa.config.TestR4ConfigWithElasticsearchClient;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
|
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
|
||||||
|
import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
@ -57,6 +58,8 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
return myPlatformTransactionManager;
|
return myPlatformTransactionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObservationResourceProvider observationRp = new ObservationResourceProvider();
|
||||||
|
|
||||||
private final String observationCd0 = "code0";
|
private final String observationCd0 = "code0";
|
||||||
private final String observationCd1 = "code1";
|
private final String observationCd1 = "code1";
|
||||||
private final String observationCd2 = "code2";
|
private final String observationCd2 = "code2";
|
||||||
|
@ -101,6 +104,8 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
dataLoaded = true;
|
dataLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observationRp.setDao(myObservationDao);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createObservationsForPatient(IIdType thePatientId) {
|
private void createObservationsForPatient(IIdType thePatientId) {
|
||||||
|
@ -138,9 +143,13 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLastNNoParams() {
|
public void testLastNAllPatients() {
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam1 = new ReferenceParam("Patient", "", patient0Id.getValue());
|
||||||
|
ReferenceParam subjectParam2 = new ReferenceParam("Patient", "", patient1Id.getValue());
|
||||||
|
ReferenceParam subjectParam3 = new ReferenceParam("Patient", "", patient2Id.getValue());
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
|
|
||||||
List<String> sortedPatients = new ArrayList<>();
|
List<String> sortedPatients = new ArrayList<>();
|
||||||
sortedPatients.add(patient0Id.getValue());
|
sortedPatients.add(patient0Id.getValue());
|
||||||
|
@ -155,14 +164,39 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
executeTestCase(params, sortedPatients, sortedObservationCodes, null,90);
|
executeTestCase(params, sortedPatients, sortedObservationCodes, null,90);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLastNNoPatients() {
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.setLastNMax(1);
|
||||||
|
|
||||||
|
List<String> sortedPatients = new ArrayList<>();
|
||||||
|
|
||||||
|
List<String> sortedObservationCodes = new ArrayList<>();
|
||||||
|
sortedObservationCodes.add(observationCd0);
|
||||||
|
sortedObservationCodes.add(observationCd1);
|
||||||
|
sortedObservationCodes.add(observationCd2);
|
||||||
|
|
||||||
|
// executeTestCase(params, sortedPatients, sortedObservationCodes, null,3);
|
||||||
|
params.setLastN(true);
|
||||||
|
Map<String, String[]> requestParameters = new HashMap<>();
|
||||||
|
when(mySrd.getParameters()).thenReturn(requestParameters);
|
||||||
|
|
||||||
|
List<String> actual = toUnqualifiedVersionlessIdValues(myObservationDao.observationsLastN(params, mockSrd(),null));
|
||||||
|
|
||||||
|
assertEquals(3, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
private void executeTestCase(SearchParameterMap params, List<String> sortedPatients, List<String> sortedObservationCodes, List<String> theCategories, int expectedObservationCount) {
|
private void executeTestCase(SearchParameterMap params, List<String> sortedPatients, List<String> sortedObservationCodes, List<String> theCategories, int expectedObservationCount) {
|
||||||
List<String> actual;
|
List<String> actual;
|
||||||
params.setLastN(true);
|
params.setLastN(true);
|
||||||
|
|
||||||
Map<String, String[]> requestParameters = new HashMap<>();
|
Map<String, String[]> requestParameters = new HashMap<>();
|
||||||
String[] maxParam = new String[1];
|
// String[] maxParam = new String[1];
|
||||||
maxParam[0] = "100";
|
// maxParam[0] = "100";
|
||||||
requestParameters.put("max", maxParam);
|
// requestParameters.put("max", maxParam);
|
||||||
|
params.setLastNMax(100);
|
||||||
|
|
||||||
when(mySrd.getParameters()).thenReturn(requestParameters);
|
when(mySrd.getParameters()).thenReturn(requestParameters);
|
||||||
|
|
||||||
actual = toUnqualifiedVersionlessIdValues(myObservationDao.observationsLastN(params, mockSrd(),null));
|
actual = toUnqualifiedVersionlessIdValues(myObservationDao.observationsLastN(params, mockSrd(),null));
|
||||||
|
@ -297,6 +331,11 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// One category parameter.
|
// One category parameter.
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam1 = new ReferenceParam("Patient", "", patient0Id.getValue());
|
||||||
|
ReferenceParam subjectParam2 = new ReferenceParam("Patient", "", patient1Id.getValue());
|
||||||
|
ReferenceParam subjectParam3 = new ReferenceParam("Patient", "", patient2Id.getValue());
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
|
|
||||||
TokenParam categoryParam = new TokenParam(categorySystem, categoryCd0);
|
TokenParam categoryParam = new TokenParam(categorySystem, categoryCd0);
|
||||||
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam));
|
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam));
|
||||||
List<String> myCategories = new ArrayList<>();
|
List<String> myCategories = new ArrayList<>();
|
||||||
|
@ -315,6 +354,7 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// Another category parameter.
|
// Another category parameter.
|
||||||
params = new SearchParameterMap();
|
params = new SearchParameterMap();
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
categoryParam = new TokenParam(categorySystem, categoryCd2);
|
categoryParam = new TokenParam(categorySystem, categoryCd2);
|
||||||
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam));
|
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam));
|
||||||
myCategories = new ArrayList<>();
|
myCategories = new ArrayList<>();
|
||||||
|
@ -333,6 +373,11 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// Two category parameters.
|
// Two category parameters.
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam1 = new ReferenceParam("Patient", "", patient0Id.getValue());
|
||||||
|
ReferenceParam subjectParam2 = new ReferenceParam("Patient", "", patient1Id.getValue());
|
||||||
|
ReferenceParam subjectParam3 = new ReferenceParam("Patient", "", patient2Id.getValue());
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
|
|
||||||
TokenParam categoryParam1 = new TokenParam(categorySystem, categoryCd0);
|
TokenParam categoryParam1 = new TokenParam(categorySystem, categoryCd0);
|
||||||
TokenParam categoryParam2 = new TokenParam(categorySystem, categoryCd1);
|
TokenParam categoryParam2 = new TokenParam(categorySystem, categoryCd1);
|
||||||
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam1, categoryParam2));
|
params.add(Observation.SP_CATEGORY, buildTokenAndListParam(categoryParam1, categoryParam2));
|
||||||
|
@ -357,6 +402,11 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// One code parameter.
|
// One code parameter.
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam1 = new ReferenceParam("Patient", "", patient0Id.getValue());
|
||||||
|
ReferenceParam subjectParam2 = new ReferenceParam("Patient", "", patient1Id.getValue());
|
||||||
|
ReferenceParam subjectParam3 = new ReferenceParam("Patient", "", patient2Id.getValue());
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
|
|
||||||
TokenParam code = new TokenParam(codeSystem, observationCd0);
|
TokenParam code = new TokenParam(codeSystem, observationCd0);
|
||||||
params.add(Observation.SP_CODE, buildTokenAndListParam(code));
|
params.add(Observation.SP_CODE, buildTokenAndListParam(code));
|
||||||
List<String> sortedObservationCodes = new ArrayList<>();
|
List<String> sortedObservationCodes = new ArrayList<>();
|
||||||
|
@ -371,6 +421,7 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// Another code parameter.
|
// Another code parameter.
|
||||||
params = new SearchParameterMap();
|
params = new SearchParameterMap();
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
code = new TokenParam(codeSystem, observationCd2);
|
code = new TokenParam(codeSystem, observationCd2);
|
||||||
params.add(Observation.SP_CODE, buildTokenAndListParam(code));
|
params.add(Observation.SP_CODE, buildTokenAndListParam(code));
|
||||||
sortedObservationCodes = new ArrayList<>();
|
sortedObservationCodes = new ArrayList<>();
|
||||||
|
@ -385,6 +436,11 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseJpaTest {
|
||||||
|
|
||||||
// Two code parameters.
|
// Two code parameters.
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam1 = new ReferenceParam("Patient", "", patient0Id.getValue());
|
||||||
|
ReferenceParam subjectParam2 = new ReferenceParam("Patient", "", patient1Id.getValue());
|
||||||
|
ReferenceParam subjectParam3 = new ReferenceParam("Patient", "", patient2Id.getValue());
|
||||||
|
params.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam1, subjectParam2, subjectParam3));
|
||||||
|
|
||||||
TokenParam codeParam1 = new TokenParam(codeSystem, observationCd0);
|
TokenParam codeParam1 = new TokenParam(codeSystem, observationCd0);
|
||||||
TokenParam codeParam2 = new TokenParam(codeSystem, observationCd1);
|
TokenParam codeParam2 = new TokenParam(codeSystem, observationCd1);
|
||||||
params.add(Observation.SP_CODE, buildTokenAndListParam(codeParam1, codeParam2));
|
params.add(Observation.SP_CODE, buildTokenAndListParam(codeParam1, codeParam2));
|
||||||
|
|
|
@ -79,6 +79,8 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
private final String CODEFIRSTCODINGSYSTEM = "http://mycodes.org/fhir/observation-code";
|
private final String CODEFIRSTCODINGSYSTEM = "http://mycodes.org/fhir/observation-code";
|
||||||
private final String CODEFIRSTCODINGCODE = "test-code";
|
private final String CODEFIRSTCODINGCODE = "test-code";
|
||||||
|
|
||||||
|
private ReferenceAndListParam multiSubjectParams = null;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexObservationSingle() {
|
public void testIndexObservationSingle() {
|
||||||
indexSingleObservation();
|
indexSingleObservation();
|
||||||
|
@ -177,6 +179,8 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
|
|
||||||
// Check that all observations were indexed.
|
// Check that all observations were indexed.
|
||||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
||||||
|
//searchParameterMap.
|
||||||
List<String> observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, 10);
|
List<String> observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, 10);
|
||||||
assertEquals(100, observationIdsOnly.size());
|
assertEquals(100, observationIdsOnly.size());
|
||||||
|
|
||||||
|
@ -223,10 +227,14 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
categoryCodeableConcept2.setCoding(category2);
|
categoryCodeableConcept2.setCoding(category2);
|
||||||
categoryConcepts2.add(categoryCodeableConcept2);
|
categoryConcepts2.add(categoryCodeableConcept2);
|
||||||
|
|
||||||
|
ReferenceOrListParam subjectParams = new ReferenceOrListParam();
|
||||||
for (int patientCount = 0; patientCount < 10; patientCount++) {
|
for (int patientCount = 0; patientCount < 10; patientCount++) {
|
||||||
|
|
||||||
String subjectId = String.valueOf(patientCount);
|
String subjectId = String.valueOf(patientCount);
|
||||||
|
|
||||||
|
ReferenceParam subjectParam = new ReferenceParam("Patient", "", subjectId);
|
||||||
|
subjectParams.addOr(subjectParam);
|
||||||
|
|
||||||
for (int entryCount = 0; entryCount < 10; entryCount++) {
|
for (int entryCount = 0; entryCount < 10; entryCount++) {
|
||||||
|
|
||||||
Observation observation = new Observation();
|
Observation observation = new Observation();
|
||||||
|
@ -254,6 +262,9 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multiSubjectParams = new ReferenceAndListParam().addAnd(subjectParams);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -265,6 +276,7 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
assertNotNull(observation);
|
assertNotNull(observation);
|
||||||
|
|
||||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
||||||
List<String> observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, 10);
|
List<String> observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, 10);
|
||||||
assertEquals(100, observationIdsOnly.size());
|
assertEquals(100, observationIdsOnly.size());
|
||||||
assertTrue(observationIdsOnly.contains("55"));
|
assertTrue(observationIdsOnly.contains("55"));
|
||||||
|
|
|
@ -56,23 +56,40 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLastNNoCriteriaQuery() {
|
public void testLastNAllPatientsQuery() {
|
||||||
|
|
||||||
// execute Observation ID search (Composite Aggregation) last 3 observations for each patient
|
// execute Observation ID search (Composite Aggregation) last 3 observations for each patient
|
||||||
List<ObservationJson> observations = elasticsearchSvc.executeLastNWithAllFields(null, 3);
|
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||||
|
ReferenceParam subjectParam = new ReferenceParam("Patient", "", "0");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "1");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "2");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "3");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "4");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "5");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "6");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "7");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "8");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
subjectParam = new ReferenceParam("Patient", "", "9");
|
||||||
|
searchParameterMap.add(Observation.SP_SUBJECT, buildReferenceAndListParam(subjectParam));
|
||||||
|
|
||||||
validateQueryResponse(observations);
|
List<ObservationJson> observations = elasticsearchSvc.executeLastNWithAllFields(searchParameterMap, 3);
|
||||||
|
|
||||||
}
|
assertEquals(60, observations.size());
|
||||||
|
|
||||||
private void validateQueryResponse(List<ObservationJson> observationIdsOnly) {
|
|
||||||
assertEquals(60, observationIdsOnly.size());
|
|
||||||
|
|
||||||
// Observation documents should be grouped by subject, then by observation code, and then sorted by effective date/time
|
// Observation documents should be grouped by subject, then by observation code, and then sorted by effective date/time
|
||||||
// within each observation code. Verify the grouping by creating a nested Map.
|
// within each observation code. Verify the grouping by creating a nested Map.
|
||||||
Map<String, Map<String, List<Date>>> queriedPatientObservationMap = new HashMap<>();
|
Map<String, Map<String, List<Date>>> queriedPatientObservationMap = new HashMap<>();
|
||||||
ObservationJson previousObservationJson = null;
|
ObservationJson previousObservationJson = null;
|
||||||
for (ObservationJson observationJson : observationIdsOnly) {
|
for (ObservationJson observationJson : observations) {
|
||||||
assertNotNull(observationJson.getIdentifier());
|
assertNotNull(observationJson.getIdentifier());
|
||||||
assertNotNull(observationJson.getSubject());
|
assertNotNull(observationJson.getSubject());
|
||||||
assertNotNull(observationJson.getCode_concept_id());
|
assertNotNull(observationJson.getCode_concept_id());
|
||||||
|
@ -373,4 +390,19 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLastNNoParamsQuery() {
|
||||||
|
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||||
|
List<ObservationJson> observations = elasticsearchSvc.executeLastNWithAllFields(searchParameterMap, 1);
|
||||||
|
|
||||||
|
assertEquals(2, observations.size());
|
||||||
|
|
||||||
|
String observationCode1 = observations.get(0).getCode_coding_code_system_hash();
|
||||||
|
String observationCode2 = observations.get(1).getCode_coding_code_system_hash();
|
||||||
|
|
||||||
|
assertNotEquals(observationCode1, observationCode2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,9 @@ public class TestElasticsearchConfig {
|
||||||
return embeddedElastic;
|
return embeddedElastic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
// @PreDestroy
|
||||||
public void stop() {
|
// public void stop() {
|
||||||
embeddedElasticSearch().stop();
|
// embeddedElasticSearch().stop();
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class SearchParameterMap implements Serializable {
|
||||||
private SearchTotalModeEnum mySearchTotalMode;
|
private SearchTotalModeEnum mySearchTotalMode;
|
||||||
private QuantityParam myNearDistanceParam;
|
private QuantityParam myNearDistanceParam;
|
||||||
private boolean myLastN;
|
private boolean myLastN;
|
||||||
|
private Integer myLastNMax;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -322,6 +323,24 @@ public class SearchParameterMap implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, tells the server the maximum number of observations to return for each
|
||||||
|
* observation code in the result set of a lastn operation
|
||||||
|
*/
|
||||||
|
public Integer getLastNMax() {
|
||||||
|
return myLastNMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, tells the server the maximum number of observations to return for each
|
||||||
|
* observation code in the result set of a lastn operation
|
||||||
|
*/
|
||||||
|
public SearchParameterMap setLastNMax(Integer theLastNMax) {
|
||||||
|
myLastNMax = theLastNMax;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates a URL query string representation of the parameters in this
|
* This method creates a URL query string representation of the parameters in this
|
||||||
* object, excluding the part before the parameters, e.g.
|
* object, excluding the part before the parameters, e.g.
|
||||||
|
|
Loading…
Reference in New Issue