Skip to content

Commit

Permalink
Merge pull request #6227 from BartChris/3_7_speed_up_parent_editor_view
Browse files Browse the repository at this point in the history
[3.7] Speed up display of parent processes
  • Loading branch information
solth authored Sep 19, 2024
2 parents 73113f2 + 9865b98 commit 5a4e4ec
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

Expand All @@ -25,6 +27,9 @@
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Request;
Expand All @@ -36,6 +41,7 @@
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.SortBuilder;
import org.kitodo.data.elasticsearch.KitodoRestClient;
import org.kitodo.data.elasticsearch.exceptions.CustomResponseException;
Expand Down Expand Up @@ -193,6 +199,42 @@ SearchHits getDocument(String type, QueryBuilder query, SortBuilder sort, Intege
}
}

/**
* Retrieves a map of document IDs to their corresponding base type for the given list of IDs.
*
* @param type the type of documents being requested, used to determine the index.
* @param ids the list of document IDs to search for.
* @return a map where each key is a document ID and the value is the corresponding base type of the document.
*/
public Map<Integer, String> fetchIdToBaseTypeMap(String type, List<Integer> ids) throws CustomResponseException, DataException {
Map<Integer, String> idToBaseTypeMap = new HashMap<>();

try {
// Create a MultiGetRequest to fetch multiple documents with only baseType field
MultiGetRequest multiGetRequest = new MultiGetRequest();
for (Integer id : ids) {
MultiGetRequest.Item item = new MultiGetRequest.Item(this.indexBase + "_" + type, String.valueOf(id));
// Only fetch baseType field
item.fetchSourceContext(new FetchSourceContext(true, new String[]{"baseType"}, null));
multiGetRequest.add(item);
}
MultiGetResponse multiGetResponse = highLevelClient.mget(multiGetRequest, RequestOptions.DEFAULT);
for (MultiGetItemResponse itemResponse : multiGetResponse.getResponses()) {
if (!itemResponse.isFailed() && itemResponse.getResponse().isExists()) {
String baseType = (String) itemResponse.getResponse().getSourceAsMap().get("baseType");
Integer id = Integer.parseInt(itemResponse.getResponse().getId());
idToBaseTypeMap.put(id, baseType);
}
}
} catch (ResponseException e) {
handleResponseException(e);
} catch (IOException | NumberFormatException e) {
throw new DataException(e);
}

return idToBaseTypeMap;
}

private String performRequest(String type, HttpEntity entity, String httpMethod, String urlRequest)
throws CustomResponseException, DataException {
String output = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ public Aggregations aggregateDocuments(QueryBuilder query, AggregationBuilder ag
return restClient.aggregateDocuments(this.type, query, aggregation);
}

/**
* Retrieves a mapping of document IDs to their corresponding base type for the given list of IDs.
* Delegates to the `SearchRestClient`.
*
* @param ids
* the list of document IDs to search for.
* @return a map where each key is a document ID and the value is the corresponding base type of the document.
*/
public Map<Integer, String> fetchIdToBaseTypeMap(List<Integer> ids) throws CustomResponseException, DataException {
SearchRestClient restClient = initiateRestClient();
return restClient.fetchIdToBaseTypeMap(this.type,ids);
}

/**
* Find document by id.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,29 @@ private DefaultTreeNode buildStructureTree() {
invisibleRootNode.setExpanded(true);
invisibleRootNode.setType(STRUCTURE_NODE_TYPE);
addParentLinksRecursive(dataEditor.getProcess(), invisibleRootNode);
buildStructureTreeRecursively(structure, invisibleRootNode);
List<Integer> processIds = getAllLinkedProcessIds(structure);
Map<Integer, String> processTypeMap = processIds.isEmpty() ? Collections.emptyMap() : fetchProcessTypes(processIds);
Map<String, StructuralElementViewInterface> viewCache = new HashMap<>();
buildStructureTreeRecursively(structure, invisibleRootNode, processTypeMap, viewCache);
return invisibleRootNode;
}

private List<Integer> getAllLinkedProcessIds(LogicalDivision structure) {
return structure.getAllChildren().stream()
.filter(division -> division.getLink() != null)
.map(division -> ServiceManager.getProcessService().processIdFromUri(division.getLink().getUri()))
.collect(Collectors.toList());
}

private Map<Integer, String> fetchProcessTypes(List<Integer> processIds) {
try {
return ServiceManager.getProcessService().getIdBaseTypeMap(processIds);
} catch (DataException e) {
Helper.setErrorMessage("metadataReadError", e.getMessage(), logger, e);
return Collections.emptyMap();
}
}

/**
* Constructs a page range string by combining the labels of the first and last view
* of the provided logical division.
Expand All @@ -582,33 +601,35 @@ private String buildPageRangeFromLogicalDivision(LogicalDivision structure) {
/**
* Build a StructureTreeNode for a logical division, which is then visualized in the logical structure tree.
*
* @param structure the logical division
* @return the StructureTreeNode instance
* @param structure the logical division for which the tree node is being constructed
* @param idTypeMap the mapping of process id to basetype
* @param viewCache a cache for storing and retrieving already processed StructuralElementViews
* @return the constructed {@link StructureTreeNode} instance representing the given logical division
*/
private StructureTreeNode buildStructureTreeNode(LogicalDivision structure) {
private StructureTreeNode buildStructureTreeNode(LogicalDivision structure, Map<Integer, String> idTypeMap,
Map<String, StructuralElementViewInterface> viewCache) {
StructureTreeNode node;
if (Objects.isNull(structure.getLink())) {
StructuralElementViewInterface divisionView = dataEditor.getRulesetManagement().getStructuralElementView(
structure.getType(), dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
StructuralElementViewInterface divisionView = viewCache.computeIfAbsent(structure.getType(), key ->
dataEditor.getRulesetManagement().getStructuralElementView(
key, dataEditor.getAcquisitionStage(), dataEditor.getPriorityList())
);
String label = divisionView.getLabel();
String pageRange = buildPageRangeFromLogicalDivision(structure);
boolean undefined = divisionView.isUndefined() && Objects.nonNull(structure.getType());
node = new StructureTreeNode(label, pageRange, undefined, false, structure);
} else {
node = new StructureTreeNode(structure.getLink().getUri().toString(), null, true, true, structure);
for (Process child : dataEditor.getCurrentChildren()) {
try {
String type = ServiceManager.getProcessService().getBaseType(child.getId());
if (child.getId() == ServiceManager.getProcessService()
.processIdFromUri(structure.getLink().getUri())) {
StructuralElementViewInterface view = dataEditor.getRulesetManagement().getStructuralElementView(
type, dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
node = new StructureTreeNode("[" + child.getId() + "] " + view.getLabel() + " - "
+ child.getTitle(), null, view.isUndefined(), true, structure);
}
} catch (DataException e) {
Helper.setErrorMessage("metadataReadError", e.getMessage(), logger, e);
node = new StructureTreeNode(child.getTitle(), null, true, true, child);
if (child.getId() == ServiceManager.getProcessService().processIdFromUri(structure.getLink().getUri())) {
String type = idTypeMap.get(child.getId());
// Retrieve the view from cache if it exists, otherwise compute and cache it
StructuralElementViewInterface view = viewCache.computeIfAbsent(type, key ->
dataEditor.getRulesetManagement().getStructuralElementView(
key, dataEditor.getAcquisitionStage(), dataEditor.getPriorityList())
);
node = new StructureTreeNode("[" + child.getId() + "] " + view.getLabel() + " - "
+ child.getTitle(), null, view.isUndefined(), true, structure);
}
}
}
Expand All @@ -620,10 +641,13 @@ private StructureTreeNode buildStructureTreeNode(LogicalDivision structure) {
*
* @param structure the current logical structure
* @param result the current corresponding primefaces tree node
* @param processTypeMap the mapping of process id to basetype
* @param viewCache a cache for storing and retrieving already processed StructuralElementViews
* @return a collection of views that contains all views of the full sub-tree
*/
private Collection<View> buildStructureTreeRecursively(LogicalDivision structure, TreeNode result) {
StructureTreeNode node = buildStructureTreeNode(structure);
private Collection<View> buildStructureTreeRecursively(LogicalDivision structure, TreeNode result, Map<Integer,
String> processTypeMap, Map<String, StructuralElementViewInterface> viewCache) {
StructureTreeNode node = buildStructureTreeNode(structure, processTypeMap, viewCache);
/*
* Creating the tree node by handing over the parent node automatically
* appends it to the parent as a child. That’s the logic of the JSF
Expand All @@ -637,15 +661,16 @@ private Collection<View> buildStructureTreeRecursively(LogicalDivision structure
Set<View> viewsShowingOnAChild = new HashSet<>();
if (!this.logicalStructureTreeContainsMedia()) {
for (LogicalDivision child : structure.getChildren()) {
viewsShowingOnAChild.addAll(buildStructureTreeRecursively(child, parent));
viewsShowingOnAChild.addAll(buildStructureTreeRecursively(child, parent, processTypeMap, viewCache));
}
} else {
// iterate through children and views ordered by the ORDER attribute
List<Pair<View, LogicalDivision>> merged = mergeLogicalStructureViewsAndChildren(structure);
for (Pair<View, LogicalDivision> pair : merged) {
if (Objects.nonNull(pair.getRight())) {
// add child and their views
viewsShowingOnAChild.addAll(buildStructureTreeRecursively(pair.getRight(), parent));
viewsShowingOnAChild.addAll(buildStructureTreeRecursively(pair.getRight(), parent,
processTypeMap, viewCache));
} else if (!viewsShowingOnAChild.contains(pair.getLeft())) {
// add views of current logical division as leaf nodes
DefaultTreeNode viewNode = addTreeNode(buildViewLabel(pair.getLeft()), false, false, pair.getLeft(), parent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,17 @@ public String getBaseType(int processId) throws DataException {
return "";
}

/**
* Retrieves a mapping of process IDs to their corresponding base types.
*
* @param processIds
* list of document IDs to retrieve and process.
* @return a map where the keys are document IDs and the values are their associated base types
*/
public Map<Integer, String> getIdBaseTypeMap(List<Integer> processIds) throws DataException {
return fetchIdToBaseTypeMap(processIds);
}

/**
* Filter for correction / solution messages.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -458,6 +459,21 @@ public S findById(Integer id, boolean related) throws DataException {
}
}

/**
* Retrieves a mapping of document IDs to their corresponding base types for the given list of IDs.
*
* @param ids
* list of document IDs to retrieve and process.
* @return a map where the keys are document IDs and the values are their associated base types.
*/
public Map<Integer, String> fetchIdToBaseTypeMap(List<Integer> ids) throws DataException {
try {
return searcher.fetchIdToBaseTypeMap(ids);
} catch (CustomResponseException e) {
throw new DataException(e);
}
}

/**
* Find list of DTO objects by query.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.kitodo.DummyRulesetManagement;
import org.kitodo.api.dataeditor.rulesetmanagement.StructuralElementViewInterface;
import org.kitodo.api.dataformat.LogicalDivision;
import org.kitodo.api.dataformat.mets.LinkedMetsResource;
import org.kitodo.data.database.beans.Process;
import org.kitodo.data.database.beans.Template;
import org.kitodo.data.database.beans.Workflow;
import org.kitodo.production.services.ServiceManager;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

Expand All @@ -47,12 +51,15 @@ public void testBuildStructureTreeRecursively() throws Exception {
LinkedMetsResource link = new LinkedMetsResource();
link.setUri(URI.create("database://?process.id=42"));
structure.setLink(link);
Map<Integer, String> processTypeMap = new HashMap<>();
Map<String, StructuralElementViewInterface> viewCache = new HashMap<>();
processTypeMap.put(ServiceManager.getProcessService().processIdFromUri(link.getUri()), "Monograph");
TreeNode result = new DefaultTreeNode();

Method buildStructureTreeRecursively = StructurePanel.class.getDeclaredMethod("buildStructureTreeRecursively",
LogicalDivision.class, TreeNode.class);
LogicalDivision.class, TreeNode.class, Map.class, Map.class);
buildStructureTreeRecursively.setAccessible(true);
buildStructureTreeRecursively.invoke(underTest, structure, result);
buildStructureTreeRecursively.invoke(underTest, structure, result, processTypeMap, viewCache);

assertTrue(((StructureTreeNode) result.getChildren().get(0).getData()).isLinked());
}
Expand Down

0 comments on commit 5a4e4ec

Please sign in to comment.