mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-17 02:15:22 +00:00
More work on performance
This commit is contained in:
parent
660c2bde72
commit
8284fcab1b
@ -1235,7 +1235,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||||||
Set<ResourceIndexedSearchParamCoords> coordsParams = null;
|
Set<ResourceIndexedSearchParamCoords> coordsParams = null;
|
||||||
Set<ResourceLink> links = null;
|
Set<ResourceLink> links = null;
|
||||||
|
|
||||||
Set<String> populatedResourceLinkParameters = null;
|
Set<String> populatedResourceLinkParameters = Collections.emptySet();
|
||||||
if (theDeletedTimestampOrNull != null) {
|
if (theDeletedTimestampOrNull != null) {
|
||||||
|
|
||||||
stringParams = Collections.emptySet();
|
stringParams = Collections.emptySet();
|
||||||
|
@ -986,8 +986,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
|
|
||||||
SearchBuilder builder = newSearchBuilder();
|
SearchBuilder builder = newSearchBuilder();
|
||||||
builder.setType(getResourceType(), getResourceName());
|
builder.setType(getResourceType(), getResourceName());
|
||||||
builder.search(theParams);
|
List<Long> result = builder.loadSearchPage(theParams, 0, 100);
|
||||||
return builder.doGetPids();
|
|
||||||
|
// FIXME: fail if too many results
|
||||||
|
|
||||||
|
HashSet<Long> retVal = new HashSet<Long>(result);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -120,33 +120,19 @@ public class SearchBuilder {
|
|||||||
private void addPredicateComposite(RuntimeSearchParam theParamDef, List<? extends IQueryParameterType> theNextAnd) {
|
private void addPredicateComposite(RuntimeSearchParam theParamDef, List<? extends IQueryParameterType> theNextAnd) {
|
||||||
// TODO: fail if missing is set for a composite query
|
// TODO: fail if missing is set for a composite query
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
|
||||||
cq.select(from.get("myId").as(Long.class));
|
|
||||||
|
|
||||||
IQueryParameterType or = theNextAnd.get(0);
|
IQueryParameterType or = theNextAnd.get(0);
|
||||||
if (!(or instanceof CompositeParam<?, ?>)) {
|
if (!(or instanceof CompositeParam<?, ?>)) {
|
||||||
throw new InvalidRequestException("Invalid type for composite param (must be " + CompositeParam.class.getSimpleName() + ": " + or.getClass());
|
throw new InvalidRequestException("Invalid type for composite param (must be " + CompositeParam.class.getSimpleName() + ": " + or.getClass());
|
||||||
}
|
}
|
||||||
CompositeParam<?, ?> cp = (CompositeParam<?, ?>) or;
|
CompositeParam<?, ?> cp = (CompositeParam<?, ?>) or;
|
||||||
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
|
||||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
|
||||||
|
|
||||||
RuntimeSearchParam left = theParamDef.getCompositeOf().get(0);
|
RuntimeSearchParam left = theParamDef.getCompositeOf().get(0);
|
||||||
IQueryParameterType leftValue = cp.getLeftValue();
|
IQueryParameterType leftValue = cp.getLeftValue();
|
||||||
predicates.add(createCompositeParamPart(builder, from, left, leftValue));
|
myPredicates.add(createCompositeParamPart(myBuilder, myResourceTableRoot, left, leftValue));
|
||||||
|
|
||||||
RuntimeSearchParam right = theParamDef.getCompositeOf().get(1);
|
RuntimeSearchParam right = theParamDef.getCompositeOf().get(1);
|
||||||
IQueryParameterType rightValue = cp.getRightValue();
|
IQueryParameterType rightValue = cp.getRightValue();
|
||||||
predicates.add(createCompositeParamPart(builder, from, right, rightValue));
|
myPredicates.add(createCompositeParamPart(myBuilder, myResourceTableRoot, right, rightValue));
|
||||||
|
|
||||||
createPredicateResourceId(builder, cq, predicates, from.get("myId").as(Long.class));
|
|
||||||
cq.where(builder.and(toArray(predicates)));
|
|
||||||
|
|
||||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
|
||||||
doSetPids(q.getResultList());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,32 +202,14 @@ public class SearchBuilder {
|
|||||||
Class<? extends IBaseResource> resourceType = targetResourceDefinition.getImplementingClass();
|
Class<? extends IBaseResource> resourceType = targetResourceDefinition.getImplementingClass();
|
||||||
Set<Long> match = myCallingDao.processMatchUrl(matchUrl, resourceType);
|
Set<Long> match = myCallingDao.processMatchUrl(matchUrl, resourceType);
|
||||||
if (match.isEmpty()) {
|
if (match.isEmpty()) {
|
||||||
doSetPids(new ArrayList<Long>());
|
// Pick a PID that can never match
|
||||||
return;
|
match = Collections.singleton(-1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinksByTarget", JoinType.LEFT);
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceLink> from = cq.from(ResourceLink.class);
|
Predicate predicate = join.get("mySourceResourcePid").in(match);
|
||||||
cq.select(from.get("myTargetResourcePid").as(Long.class));
|
myPredicates.add(predicate);
|
||||||
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
|
||||||
predicates.add(builder.equal(from.get("mySourceResourceType"), targetResourceType));
|
|
||||||
predicates.add(from.get("mySourceResourcePid").in(match));
|
|
||||||
predicates.add(createResourceLinkPathPredicate(myCallingDao, myContext, owningParameter, from, resourceType));
|
|
||||||
predicates.add(builder.equal(from.get("myTargetResourceType"), myResourceName));
|
|
||||||
createPredicateResourceId(builder, cq, predicates, from.get("myId").as(Long.class));
|
|
||||||
createPredicateLastUpdatedForResourceLink(builder, from, predicates);
|
|
||||||
|
|
||||||
cq.where(toArray(predicates));
|
|
||||||
|
|
||||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
|
||||||
doSetPids(q.getResultList());
|
|
||||||
if (doHaveNoResults()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,6 +371,7 @@ public class SearchBuilder {
|
|||||||
Predicate eq = myBuilder.equal(join.get("myTargetResourcePid"), next);
|
Predicate eq = myBuilder.equal(join.get("myTargetResourcePid"), next);
|
||||||
codePredicates.add(eq);
|
codePredicates.add(eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
List<Class<? extends IBaseResource>> resourceTypes;
|
List<Class<? extends IBaseResource>> resourceTypes;
|
||||||
@ -447,6 +416,7 @@ public class SearchBuilder {
|
|||||||
|
|
||||||
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
||||||
RuntimeResourceDefinition typeDef = myContext.getResourceDefinition(nextType);
|
RuntimeResourceDefinition typeDef = myContext.getResourceDefinition(nextType);
|
||||||
|
String subResourceName = typeDef.getName();
|
||||||
|
|
||||||
IFhirResourceDao<?> dao = myCallingDao.getDao(nextType);
|
IFhirResourceDao<?> dao = myCallingDao.getDao(nextType);
|
||||||
if (dao == null) {
|
if (dao == null) {
|
||||||
@ -509,7 +479,11 @@ public class SearchBuilder {
|
|||||||
myResourceTableRoot = subQfrom;
|
myResourceTableRoot = subQfrom;
|
||||||
myPredicates = new ArrayList<Predicate>();
|
myPredicates = new ArrayList<Predicate>();
|
||||||
|
|
||||||
|
// Create the subquery predicates
|
||||||
|
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), subResourceName));
|
||||||
|
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted")));
|
||||||
searchForIdsWithAndOr(chain, andOrParams);
|
searchForIdsWithAndOr(chain, andOrParams);
|
||||||
|
|
||||||
subQ.where(toArray(myPredicates));
|
subQ.where(toArray(myPredicates));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -726,7 +700,6 @@ public class SearchBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Join<ResourceTable, ResourceIndexedSearchParamUri> join = myResourceTableRoot.join("myParamsUri", JoinType.LEFT);
|
Join<ResourceTable, ResourceIndexedSearchParamUri> join = myResourceTableRoot.join("myParamsUri", JoinType.LEFT);
|
||||||
|
|
||||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||||
for (IQueryParameterType nextOr : theList) {
|
for (IQueryParameterType nextOr : theList) {
|
||||||
IQueryParameterType params = nextOr;
|
IQueryParameterType params = nextOr;
|
||||||
@ -739,7 +712,6 @@ public class SearchBuilder {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path<Object> fromObj = join.get("myUri");
|
|
||||||
Predicate predicate;
|
Predicate predicate;
|
||||||
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
|
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
|
||||||
|
|
||||||
@ -769,12 +741,12 @@ public class SearchBuilder {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate = fromObj.as(String.class).in(toFind);
|
predicate = join.<Object>get("myUri").as(String.class).in(toFind);
|
||||||
|
|
||||||
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
||||||
predicate = myBuilder.like(fromObj.as(String.class), createLeftMatchLikeExpression(value));
|
predicate = myBuilder.like(join.<Object>get("myUri").as(String.class), createLeftMatchLikeExpression(value));
|
||||||
} else {
|
} else {
|
||||||
predicate = myBuilder.equal(fromObj.as(String.class), value);
|
predicate = myBuilder.equal(join.<Object>get("myUri").as(String.class), value);
|
||||||
}
|
}
|
||||||
codePredicates.add(predicate);
|
codePredicates.add(predicate);
|
||||||
} else {
|
} else {
|
||||||
@ -783,8 +755,13 @@ public class SearchBuilder {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we haven't found any of the requested URIs in the candidates, then we'll
|
||||||
|
* just add a predicate that can never match
|
||||||
|
*/
|
||||||
if (codePredicates.isEmpty()) {
|
if (codePredicates.isEmpty()) {
|
||||||
doSetPids(new HashSet<Long>());
|
Predicate predicate = myBuilder.isNull(join.<Object>get("myUri").as(String.class));
|
||||||
|
myPredicates.add(predicate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1005,7 +982,7 @@ public class SearchBuilder {
|
|||||||
return singleCode;
|
return singleCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPredicateResourceId(CriteriaBuilder builder, CriteriaQuery<?> cq, List<Predicate> thePredicates, Expression<Long> theExpression) {
|
private void createPredicateResourceId(CriteriaBuilder builder, AbstractQuery<?> cq, List<Predicate> thePredicates, Expression<Long> theExpression) {
|
||||||
if (mySearchEntity.getTotalCount() > -1) {
|
if (mySearchEntity.getTotalCount() > -1) {
|
||||||
Subquery<Long> subQ = cq.subquery(Long.class);
|
Subquery<Long> subQ = cq.subquery(Long.class);
|
||||||
Root<SearchResult> subQfrom = subQ.from(SearchResult.class);
|
Root<SearchResult> subQfrom = subQ.from(SearchResult.class);
|
||||||
@ -1302,14 +1279,6 @@ public class SearchBuilder {
|
|||||||
return system;
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Long> doGetPids() {
|
|
||||||
HashSet<Long> retVal = new HashSet<Long>();
|
|
||||||
|
|
||||||
for (SearchResult next : mySearchResultDao.findWithSearchUuid(mySearchEntity)) {
|
|
||||||
retVal.add(next.getResourcePid());
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean doHaveNoResults() {
|
private boolean doHaveNoResults() {
|
||||||
return mySearchEntity.getTotalCount() == 0;
|
return mySearchEntity.getTotalCount() == 0;
|
||||||
@ -1387,9 +1356,6 @@ public class SearchBuilder {
|
|||||||
|
|
||||||
if (orders.size() > 0) {
|
if (orders.size() > 0) {
|
||||||
|
|
||||||
// TODO: why do we need the existing list for this join to work?
|
|
||||||
Collection<Long> originalPids = doGetPids();
|
|
||||||
|
|
||||||
LinkedHashSet<Long> loadPids = new LinkedHashSet<Long>();
|
LinkedHashSet<Long> loadPids = new LinkedHashSet<Long>();
|
||||||
cq.multiselect(from.get("myId").as(Long.class));
|
cq.multiselect(from.get("myId").as(Long.class));
|
||||||
cq.where(toArray(predicates));
|
cq.where(toArray(predicates));
|
||||||
@ -1406,11 +1372,11 @@ public class SearchBuilder {
|
|||||||
ArrayList<Long> pids = new ArrayList<Long>(loadPids);
|
ArrayList<Long> pids = new ArrayList<Long>(loadPids);
|
||||||
|
|
||||||
// Any ressources which weren't matched by the sort get added to the bottom
|
// Any ressources which weren't matched by the sort get added to the bottom
|
||||||
for (Long next : originalPids) {
|
// for (Long next : originalPids) {
|
||||||
if (loadPids.contains(next) == false) {
|
// if (loadPids.contains(next) == false) {
|
||||||
pids.add(next);
|
// pids.add(next);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
doSetPids(pids);
|
doSetPids(pids);
|
||||||
}
|
}
|
||||||
@ -1646,7 +1612,6 @@ public class SearchBuilder {
|
|||||||
|
|
||||||
} else if (nextParamName.equals(Constants.PARAM_HAS)) {
|
} else if (nextParamName.equals(Constants.PARAM_HAS)) {
|
||||||
|
|
||||||
// FIXME
|
|
||||||
addPredicateHas(andOrParams, null);
|
addPredicateHas(andOrParams, null);
|
||||||
|
|
||||||
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
||||||
|
@ -229,6 +229,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
|
|||||||
@IndexedEmbedded()
|
@IndexedEmbedded()
|
||||||
private Collection<ResourceLink> myResourceLinks;
|
private Collection<ResourceLink> myResourceLinks;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||||
|
private Collection<ResourceLink> myResourceLinksByTarget;
|
||||||
|
|
||||||
@Column(name = "RES_TYPE", length = RESTYPE_LEN)
|
@Column(name = "RES_TYPE", length = RESTYPE_LEN)
|
||||||
@Field
|
@Field
|
||||||
private String myResourceType;
|
private String myResourceType;
|
||||||
|
@ -8,4 +8,6 @@ public interface ISearchParamPresenceSvc {
|
|||||||
|
|
||||||
void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence);
|
void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence);
|
||||||
|
|
||||||
|
void flushCachesForUnitTest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -84,4 +84,9 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flushCachesForUnitTest() {
|
||||||
|
myResourceTypeToSearchParamToEntity.clear();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
|||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
@ -191,6 +192,8 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||||||
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected PlatformTransactionManager myTransactionMgr;
|
protected PlatformTransactionManager myTransactionMgr;
|
||||||
|
@Autowired
|
||||||
|
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||||
@After()
|
@After()
|
||||||
public void afterGrabCaches() {
|
public void afterGrabCaches() {
|
||||||
ourValueSetDao = myValueSetDao;
|
ourValueSetDao = myValueSetDao;
|
||||||
@ -219,6 +222,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||||||
public void beforePurgeDatabase() {
|
public void beforePurgeDatabase() {
|
||||||
final EntityManager entityManager = this.myEntityManager;
|
final EntityManager entityManager = this.myEntityManager;
|
||||||
purgeDatabase(entityManager, myTxManager);
|
purgeDatabase(entityManager, myTxManager);
|
||||||
|
mySearchParamPresenceSvc.flushCachesForUnitTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -1442,8 +1442,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||||||
SearchParameterMap params;
|
SearchParameterMap params;
|
||||||
|
|
||||||
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam("Patient", Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01")));
|
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam("Patient", Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01")));
|
||||||
assertEquals(1, result.size());
|
|
||||||
assertThat(result, containsInAnyOrder(obsId01));
|
assertThat(result, containsInAnyOrder(obsId01));
|
||||||
|
assertEquals(1, result.size());
|
||||||
|
|
||||||
params = new SearchParameterMap();
|
params = new SearchParameterMap();
|
||||||
params.add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01"));
|
params.add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01"));
|
||||||
@ -1459,6 +1459,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||||||
assertThat(result, containsInAnyOrder(obsId02));
|
assertThat(result, containsInAnyOrder(obsId02));
|
||||||
|
|
||||||
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesXX")));
|
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesXX")));
|
||||||
|
assertThat(result, containsInAnyOrder(obsId01));
|
||||||
assertEquals(1, result.size());
|
assertEquals(1, result.size());
|
||||||
|
|
||||||
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesYY")));
|
result = toUnqualifiedVersionlessIds(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesYY")));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user