Work on perf

This commit is contained in:
James Agnew 2017-04-14 09:50:05 -04:00
parent 1039bbec97
commit f6acb5633b
5 changed files with 146 additions and 53 deletions

View File

@ -977,15 +977,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override @Override
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams) { public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams) {
theParams.setPersistResults(false);
SearchBuilder builder = newSearchBuilder(); SearchBuilder builder = newSearchBuilder();
builder.setType(getResourceType(), getResourceName()); builder.setType(getResourceType(), getResourceName());
List<Long> result = builder.loadSearchPage(theParams, 0, 100);
// FIXME: fail if too many results // FIXME: fail if too many results
HashSet<Long> retVal = new HashSet<Long>(result); HashSet<Long> retVal = new HashSet<Long>();
Iterator<Long> iter = builder.createQuery(theParams);
while (iter.hasNext()) {
retVal.add(iter.next());
}
return retVal; return retVal;
} }

View File

@ -1559,11 +1559,12 @@ public class SearchBuilder {
/* /*
* Now perform the search * Now perform the search
*/ */
TypedQuery<Long> query = myEntityManager.createQuery(outerQuery); final TypedQuery<Long> query = myEntityManager.createQuery(outerQuery);
final Iterator<Long> results = query.getResultList().iterator();
final Set<Long> pidSet = new HashSet<Long>();
return new Iterator<Long>() { return new Iterator<Long>() {
private final Set<Long> myPidSet = new HashSet<Long>();
private Iterator<Long> myResultsIterator;
private Long myNext; private Long myNext;
@Override @Override
@ -1578,10 +1579,13 @@ public class SearchBuilder {
} }
private void fetchNext() { private void fetchNext() {
if (myResultsIterator == null) {
myResultsIterator = query.getResultList().iterator();
}
if (myNext == null) { if (myNext == null) {
while (results.hasNext()) { while (myResultsIterator.hasNext()) {
Long next = results.next(); Long next = myResultsIterator.next();
if (next != null && pidSet.add(next)) { if (next != null && myPidSet.add(next)) {
myNext = next; myNext = next;
break; break;
} }
@ -1604,45 +1608,42 @@ public class SearchBuilder {
private static Long NO_MORE = Long.valueOf(-1); private static Long NO_MORE = Long.valueOf(-1);
public IBundleProvider search(final SearchParameterMap theParams) { public IBundleProvider search(final SearchParameterMap theParams) {
myParams = theParams; // myParams = theParams;
StopWatch w = new StopWatch(); // StopWatch w = new StopWatch();
//
if (theParams.isLoadSynchronous()) { // if (theParams.isLoadSynchronous()) {
//
} // }
//
mySearchEntity = new Search(); // mySearchEntity = new Search();
mySearchEntity.setUuid(UUID.randomUUID().toString()); // mySearchEntity.setUuid(UUID.randomUUID().toString());
mySearchEntity.setCreated(new Date()); // mySearchEntity.setCreated(new Date());
mySearchEntity.setTotalCount(-1); // mySearchEntity.setTotalCount(-1);
mySearchEntity.setPreferredPageSize(myParams.getCount()); // mySearchEntity.setPreferredPageSize(myParams.getCount());
mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH); // mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH);
mySearchEntity.setLastUpdated(myParams.getLastUpdated()); // mySearchEntity.setLastUpdated(myParams.getLastUpdated());
mySearchEntity.setResourceType(myResourceName); // mySearchEntity.setResourceType(myResourceName);
//
for (Include next : myParams.getIncludes()) { // for (Include next : myParams.getIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse())); // mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse()));
} // }
for (Include next : myParams.getRevIncludes()) { // for (Include next : myParams.getRevIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse())); // mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse()));
} // }
//
List<Long> firstPage = loadSearchPage(theParams, 0, 999); // List<Long> firstPage = loadSearchPage(theParams, 0, 999);
mySearchEntity.setTotalCount(firstPage.size()); // mySearchEntity.setTotalCount(firstPage.size());
//
myEntityManager.persist(mySearchEntity); // myEntityManager.persist(mySearchEntity);
for (SearchInclude next : mySearchEntity.getIncludes()) { // for (SearchInclude next : mySearchEntity.getIncludes()) {
myEntityManager.persist(next); // myEntityManager.persist(next);
} // }
//
IBundleProvider retVal = doReturnProvider(); // IBundleProvider retVal = doReturnProvider();
//
ourLog.info("Search initial phase completed in {}ms", w); // ourLog.info("Search initial phase completed in {}ms", w);
return retVal; // return retVal;
} return null;
public List<Long> loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) {
} }
// public IBundleProvider loadPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { // public IBundleProvider loadPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) {

View File

@ -0,0 +1,5 @@
package ca.uhn.fhir.jpa.search;
public class ISearchCoordinatorSvc {
}

View File

@ -125,15 +125,15 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
// List<Long> pidsSubList = sb.loadSearchPage(parameterMap, theFromIndex, theToIndex);()); // List<Long> pidsSubList = sb.loadSearchPage(parameterMap, theFromIndex, theToIndex);());
List<Long> pidsSubList = null; List<Long> pidsSubList = null;
Set<Long> revIncludedPids = new HashSet<Long>(); Set<Long> includedPids = new HashSet<Long>();
if (mySearchEntity.getSearchType() == SearchTypeEnum.SEARCH) { if (mySearchEntity.getSearchType() == SearchTypeEnum.SEARCH) {
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toRevIncludesList(), true, mySearchEntity.getLastUpdated())); includedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toRevIncludesList(), true, mySearchEntity.getLastUpdated()));
} }
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toIncludesList(), false, mySearchEntity.getLastUpdated())); includedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toIncludesList(), false, mySearchEntity.getLastUpdated()));
// Execute the query and make sure we return distinct results // Execute the query and make sure we return distinct results
List<IBaseResource> resources = new ArrayList<IBaseResource>(); List<IBaseResource> resources = new ArrayList<IBaseResource>();
SearchBuilder.loadResourcesByPid(pidsSubList, resources, revIncludedPids, false, myEntityManager, myContext, myDao); SearchBuilder.loadResourcesByPid(pidsSubList, resources, includedPids, false, myEntityManager, myContext, myDao);
return resources; return resources;
} }

View File

@ -0,0 +1,83 @@
package ca.uhn.fhir.jpa.search;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.persistence.EntityManager;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.transaction.PlatformTransactionManager;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IDao;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.rest.server.IBundleProvider;
public class SearchCoordinatorSvcImpl {
public SearchCoordinatorSvcImpl() {
CustomizableThreadFactory threadFactory = new CustomizableThreadFactory("search_coord_");
myExecutor = Executors.newCachedThreadPool(threadFactory);
}
public IBundleProvider registerSearch(IDao theCallingDao, SearchParameterMap theParams) {
StopWatch w = new StopWatch();
if (theParams.isLoadSynchronous()) {
SearchBuilder sb = theCallingDao.newSearchBuilder();
Iterator<Long> resultIter = sb.createQuery(theParams);
// Load the results synchronously
List<Long> pids = new ArrayList<Long>();
while (resultIter.hasNext()) {
pids.add(resultIter.next());
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
break;
}
}
resources = sb.loadResourcesByPid(pids, theResourceListToPopulate, theRevIncludedPids, theForHistoryOperation, entityManager, context, theDao);
}
mySearchEntity = new Search();
mySearchEntity.setUuid(UUID.randomUUID().toString());
mySearchEntity.setCreated(new Date());
mySearchEntity.setTotalCount(-1);
mySearchEntity.setPreferredPageSize(myParams.getCount());
mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH);
mySearchEntity.setLastUpdated(myParams.getLastUpdated());
mySearchEntity.setResourceType(myResourceName);
for (Include next : myParams.getIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse()));
}
for (Include next : myParams.getRevIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse()));
}
List<Long> firstPage = loadSearchPage(theParams, 0, 999);
mySearchEntity.setTotalCount(firstPage.size());
myEntityManager.persist(mySearchEntity);
for (SearchInclude next : mySearchEntity.getIncludes()) {
myEntityManager.persist(next);
}
IBundleProvider retVal = doReturnProvider();
ourLog.info("Search initial phase completed in {}ms", w);
return retVal;
}
}