Skip to content

Commit

Permalink
Optimize further:
Browse files Browse the repository at this point in the history
 - replace for loops with streams
 - use sets instead of lists to avoid duplication
 - switch from using DFS to BFS in getting locations deep in the hierarchy
  • Loading branch information
lincmba committed Sep 25, 2024
1 parent ec06253 commit 77363cf
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -86,7 +90,9 @@ public List<LocationHierarchy> getLocationHierarchies(
List<String> preFetchAdminLevels,
List<String> postFetchAdminLevels,
Boolean filterInventory) {
return locationIds.parallelStream()
Set<String> uniqueLocationIds = new HashSet<>(locationIds);

return uniqueLocationIds.parallelStream()
.map(
locationId ->
getLocationHierarchy(
Expand All @@ -109,7 +115,7 @@ public LocationHierarchy getLocationHierarchyCore(
if (location != null) {
logger.info("Building Location Hierarchy of Location Id : {}", locationId);

List<Location> descendants = getDescendants(locationId, location, preFetchAdminLevels);
List<Location> descendants = getDescendants(locationId, preFetchAdminLevels, location);
if (filterInventory) {
descendants = filterLocationsByInventory(descendants);
}
Expand All @@ -136,12 +142,12 @@ public List<Location> getLocationHierarchyLocations(
List<Location> descendants;

if (CacheHelper.INSTANCE.skipCache()) {
descendants = getDescendants(locationId, parentLocation, preFetchAdminLevels);
descendants = getDescendants(locationId, preFetchAdminLevels, parentLocation);
} else {
descendants =
CacheHelper.INSTANCE.locationListCache.get(
locationId,
key -> getDescendants(locationId, parentLocation, preFetchAdminLevels));
key -> getDescendants(locationId, preFetchAdminLevels, parentLocation));
}
if (filterInventory) {
descendants = filterLocationsByInventory(descendants);
Expand All @@ -150,7 +156,7 @@ public List<Location> getLocationHierarchyLocations(
}

public List<Location> getDescendants(
String locationId, Location parentLocation, List<String> adminLevels) {
String locationId, List<String> adminLevels, Location parentLocation) {
IQuery<IBaseBundle> query =
getFhirClientForR4()
.search()
Expand All @@ -172,28 +178,35 @@ public List<Location> getDescendants(
adminLevelArray));
}

Bundle childLocationBundle =
query.usingStyle(SearchStyleEnum.POST).returnBundle(Bundle.class).execute();
Queue<String> locationQueue = new LinkedList<>();
locationQueue.add(locationId);

List<Location> allLocations = Collections.synchronizedList(new ArrayList<>());
if (parentLocation != null) {
allLocations.add(parentLocation);
}

if (childLocationBundle != null) {

childLocationBundle.getEntry().parallelStream()
.forEach(
childLocation -> {
Location childLocationEntity =
(Location) childLocation.getResource();
allLocations.add(childLocationEntity);
allLocations.addAll(
getDescendants(
childLocationEntity.getIdElement().getIdPart(),
null,
adminLevels));
});
while (!locationQueue.isEmpty()) {
String currentLocationId = locationQueue.poll();
Bundle childLocationBundle =
query.where(
new ReferenceClientParam(Location.SP_PARTOF)
.hasAnyOfIds(currentLocationId))
.usingStyle(SearchStyleEnum.POST)
.returnBundle(Bundle.class)
.execute();

if (childLocationBundle != null) {
childLocationBundle.getEntry().parallelStream()
.forEach(
childLocation -> {
Location childLocationEntity =
(Location) childLocation.getResource();
allLocations.add(childLocationEntity);
locationQueue.add(
childLocationEntity.getIdElement().getIdPart());
});
}
}

return allLocations;
Expand Down Expand Up @@ -356,6 +369,7 @@ public Bundle getPaginatedLocations(HttpServletRequest request, List<String> loc
List<String> postFetchAdminLevels =
generateAdminLevels(administrativeLevelMin, administrativeLevelMax);
Map<String, String[]> parameters = new HashMap<>(request.getParameterMap());
Set<String> uniqueLocationIds = new HashSet<>(locationIds);

int count =
pageSize != null
Expand All @@ -368,18 +382,18 @@ public Bundle getPaginatedLocations(HttpServletRequest request, List<String> loc

int start = Math.max(0, (page - 1)) * count;

List<Resource> resourceLocations = new ArrayList<>();
for (String identifier : locationIds) {
Location parentLocation = getLocationById(identifier);
List<Location> locations =
getLocationHierarchyLocations(
identifier,
parentLocation,
preFetchAdminLevels,
postFetchAdminLevels,
filterInventory);
resourceLocations.addAll(locations);
}
List<Resource> resourceLocations =
uniqueLocationIds.parallelStream()
.flatMap(
identifier ->
getLocationHierarchyLocations(
identifier,
getLocationById(identifier),
preFetchAdminLevels,
postFetchAdminLevels,
filterInventory)
.stream())
.collect(Collectors.toList());
int totalEntries = resourceLocations.size();

int end = Math.min(start + count, resourceLocations.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,11 @@ public void testGetDescendantsWithAdminLevelFiltersReturnsLocationsWithinAdminLe
Mockito.doReturn(queryMock).when(queryMock).and(any(ICriterion.class));
Mockito.doReturn(queryMock).when(queryMock).usingStyle(SearchStyleEnum.POST);
Mockito.doReturn(queryMock).when(queryMock).returnBundle(Bundle.class);

Mockito.doReturn(firstBundleMock, secondBundleMock).when(queryMock).execute();

List<Location> descendants =
locationHierarchyEndpointHelper.getDescendants(
locationId, parentLocation, adminLevels);
locationId, adminLevels, parentLocation);

Assert.assertNotNull(descendants);
Assert.assertEquals(2, descendants.size());
Expand Down

0 comments on commit 77363cf

Please sign in to comment.