TSK-1718: Performance optimization for TaskService#getTask and TaskQuery#list
The execution time has been reduced from O(n²) to O(n)
This commit is contained in:
parent
591963cebc
commit
54428045dd
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.taskana.task.internal;
|
package pro.taskana.task.internal;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.ibatis.annotations.Delete;
|
import org.apache.ibatis.annotations.Delete;
|
||||||
|
|
@ -81,7 +82,7 @@ public interface AttachmentMapper {
|
||||||
@Result(property = "channel", column = "CHANNEL")
|
@Result(property = "channel", column = "CHANNEL")
|
||||||
@Result(property = "received", column = "RECEIVED")
|
@Result(property = "received", column = "RECEIVED")
|
||||||
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(
|
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(
|
||||||
@Param("taskIds") List<String> taskIds);
|
@Param("taskIds") Collection<String> taskIds);
|
||||||
|
|
||||||
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
|
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
|
||||||
void delete(@Param("attachmentId") String attachmentId);
|
void delete(@Param("attachmentId") String attachmentId);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
@ -312,18 +313,13 @@ public class TaskServiceImpl implements TaskService {
|
||||||
attachmentImpls = new ArrayList<>();
|
attachmentImpls = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ClassificationSummary> classifications;
|
Map<String, ClassificationSummary> classificationSummariesById =
|
||||||
classifications = findClassificationForTaskImplAndAttachments(resultTask, attachmentImpls);
|
findClassificationForTaskImplAndAttachments(resultTask, attachmentImpls);
|
||||||
List<Attachment> attachments =
|
addClassificationSummariesToAttachments(attachmentImpls, classificationSummariesById);
|
||||||
addClassificationSummariesToAttachments(attachmentImpls, classifications);
|
resultTask.setAttachments(new ArrayList<>(attachmentImpls));
|
||||||
resultTask.setAttachments(attachments);
|
|
||||||
|
|
||||||
String classificationId = resultTask.getClassificationSummary().getId();
|
String classificationId = resultTask.getClassificationSummary().getId();
|
||||||
ClassificationSummary classification =
|
ClassificationSummary classification = classificationSummariesById.get(classificationId);
|
||||||
classifications.stream()
|
|
||||||
.filter(c -> c.getId().equals(classificationId))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
if (classification == null) {
|
if (classification == null) {
|
||||||
throw new SystemException(
|
throw new SystemException(
|
||||||
"Could not find a Classification for task " + resultTask.getId());
|
"Could not find a Classification for task " + resultTask.getId());
|
||||||
|
|
@ -969,8 +965,8 @@ public class TaskServiceImpl implements TaskService {
|
||||||
|
|
||||||
private List<TaskSummaryImpl> augmentTaskSummariesByContainedSummariesWithoutPartitioning(
|
private List<TaskSummaryImpl> augmentTaskSummariesByContainedSummariesWithoutPartitioning(
|
||||||
List<TaskSummaryImpl> taskSummaries) {
|
List<TaskSummaryImpl> taskSummaries) {
|
||||||
List<String> taskIds =
|
Set<String> taskIds =
|
||||||
taskSummaries.stream().map(TaskSummaryImpl::getId).distinct().collect(Collectors.toList());
|
taskSummaries.stream().map(TaskSummaryImpl::getId).collect(Collectors.toSet());
|
||||||
|
|
||||||
if (taskIds.isEmpty()) {
|
if (taskIds.isEmpty()) {
|
||||||
taskIds = null;
|
taskIds = null;
|
||||||
|
|
@ -982,15 +978,17 @@ public class TaskServiceImpl implements TaskService {
|
||||||
+ "about to query for attachmentSummaries ",
|
+ "about to query for attachmentSummaries ",
|
||||||
taskSummaries);
|
taskSummaries);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AttachmentSummaryImpl> attachmentSummaries =
|
List<AttachmentSummaryImpl> attachmentSummaries =
|
||||||
attachmentMapper.findAttachmentSummariesByTaskIds(taskIds);
|
attachmentMapper.findAttachmentSummariesByTaskIds(taskIds);
|
||||||
|
Map<String, ClassificationSummary> classificationSummariesById =
|
||||||
List<ClassificationSummary> classifications =
|
|
||||||
findClassificationsForTasksAndAttachments(taskSummaries, attachmentSummaries);
|
findClassificationsForTasksAndAttachments(taskSummaries, attachmentSummaries);
|
||||||
|
Map<String, WorkbasketSummary> workbasketSummariesById = findWorkbasketsForTasks(taskSummaries);
|
||||||
|
|
||||||
addClassificationSummariesToTaskSummaries(taskSummaries, classifications);
|
addClassificationSummariesToAttachments(attachmentSummaries, classificationSummariesById);
|
||||||
addWorkbasketSummariesToTaskSummaries(taskSummaries);
|
addClassificationSummariesToTaskSummaries(taskSummaries, classificationSummariesById);
|
||||||
addAttachmentSummariesToTaskSummaries(taskSummaries, attachmentSummaries, classifications);
|
addWorkbasketSummariesToTaskSummaries(taskSummaries, workbasketSummariesById);
|
||||||
|
addAttachmentSummariesToTaskSummaries(taskSummaries, attachmentSummaries);
|
||||||
|
|
||||||
return taskSummaries;
|
return taskSummaries;
|
||||||
}
|
}
|
||||||
|
|
@ -1541,184 +1539,159 @@ public class TaskServiceImpl implements TaskService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addClassificationSummariesToTaskSummaries(
|
private Map<String, WorkbasketSummary> findWorkbasketsForTasks(
|
||||||
List<TaskSummaryImpl> tasks, List<ClassificationSummary> classifications) {
|
List<? extends TaskSummary> taskSummaries) {
|
||||||
|
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
if (tasks == null || tasks.isEmpty()) {
|
Set<String> workbasketIds =
|
||||||
return;
|
taskSummaries.stream()
|
||||||
}
|
.map(TaskSummary::getWorkbasketSummary)
|
||||||
// assign query results to appropriate tasks.
|
.map(WorkbasketSummary::getId)
|
||||||
for (TaskSummaryImpl task : tasks) {
|
.collect(Collectors.toSet());
|
||||||
String classificationId = task.getClassificationSummary().getId();
|
|
||||||
ClassificationSummary classificationSummary =
|
return queryWorkbasketsForTasks(workbasketIds).stream()
|
||||||
classifications.stream()
|
.collect(Collectors.toMap(WorkbasketSummary::getId, Function.identity()));
|
||||||
.filter(c -> c.getId().equals(classificationId))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
if (classificationSummary == null) {
|
|
||||||
throw new SystemException(
|
|
||||||
"Did not find a Classification for task (Id="
|
|
||||||
+ task.getId()
|
|
||||||
+ ",classification="
|
|
||||||
+ task.getClassificationSummary().getId()
|
|
||||||
+ ")");
|
|
||||||
}
|
|
||||||
// set the classification on the task object
|
|
||||||
task.setClassificationSummary(classificationSummary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ClassificationSummary> findClassificationsForTasksAndAttachments(
|
private Map<String, ClassificationSummary> findClassificationsForTasksAndAttachments(
|
||||||
List<? extends TaskSummaryImpl> taskSummaries,
|
List<? extends TaskSummary> taskSummaries,
|
||||||
List<? extends AttachmentSummaryImpl> attachmentSummaries) {
|
List<? extends AttachmentSummaryImpl> attachmentSummaries) {
|
||||||
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
||||||
return new ArrayList<>();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> classificationIdSet =
|
Set<String> classificationIds =
|
||||||
Stream.concat(
|
Stream.concat(
|
||||||
taskSummaries.stream().map(TaskSummary::getClassificationSummary),
|
taskSummaries.stream().map(TaskSummary::getClassificationSummary),
|
||||||
attachmentSummaries.stream().map(AttachmentSummary::getClassificationSummary))
|
attachmentSummaries.stream().map(AttachmentSummary::getClassificationSummary))
|
||||||
.map(ClassificationSummary::getId)
|
.map(ClassificationSummary::getId)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
return queryClassificationsForTasksAndAttachments(classificationIdSet);
|
return queryClassificationsForTasksAndAttachments(classificationIds).stream()
|
||||||
|
.collect(Collectors.toMap(ClassificationSummary::getId, Function.identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ClassificationSummary> findClassificationForTaskImplAndAttachments(
|
private Map<String, ClassificationSummary> findClassificationForTaskImplAndAttachments(
|
||||||
TaskImpl task, List<AttachmentImpl> attachmentImpls) {
|
TaskImpl task, List<AttachmentImpl> attachmentImpls) {
|
||||||
return findClassificationsForTasksAndAttachments(
|
return findClassificationsForTasksAndAttachments(
|
||||||
Collections.singletonList(task), attachmentImpls);
|
Collections.singletonList(task), attachmentImpls);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ClassificationSummary> queryClassificationsForTasksAndAttachments(
|
private List<ClassificationSummary> queryClassificationsForTasksAndAttachments(
|
||||||
Set<String> classificationIdSet) {
|
Set<String> classificationIds) {
|
||||||
|
|
||||||
String[] classificationIdArray = classificationIdSet.toArray(new String[0]);
|
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"getClassificationsForTasksAndAttachments() about to query classifications and exit");
|
"queryClassificationsForTasksAndAttachments() about to query classifications and exit");
|
||||||
}
|
}
|
||||||
// perform classification query
|
|
||||||
return this.classificationService
|
return this.classificationService
|
||||||
.createClassificationQuery()
|
.createClassificationQuery()
|
||||||
.idIn(classificationIdArray)
|
.idIn(classificationIds.toArray(new String[0]))
|
||||||
.list();
|
.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addWorkbasketSummariesToTaskSummaries(List<TaskSummaryImpl> taskSummaries) {
|
private List<WorkbasketSummary> queryWorkbasketsForTasks(Set<String> workbasketIds) {
|
||||||
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("queryWorkbasketsForTasks() about to query workbaskets and exit");
|
||||||
|
}
|
||||||
|
// perform classification query
|
||||||
|
return this.workbasketService
|
||||||
|
.createWorkbasketQuery()
|
||||||
|
.idIn(workbasketIds.toArray(new String[0]))
|
||||||
|
.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClassificationSummariesToTaskSummaries(
|
||||||
|
List<TaskSummaryImpl> tasks, Map<String, ClassificationSummary> classificationSummaryById) {
|
||||||
|
|
||||||
|
if (tasks == null || tasks.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// calculate parameters for workbasket query: workbasket keys
|
|
||||||
String[] workbasketIdArray =
|
|
||||||
taskSummaries.stream()
|
|
||||||
.map(t -> t.getWorkbasketSummary().getId())
|
|
||||||
.distinct()
|
|
||||||
.toArray(String[]::new);
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("addWorkbasketSummariesToTaskSummaries() about to query workbaskets");
|
|
||||||
}
|
|
||||||
WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery();
|
|
||||||
query.setUsedToAugmentTasks(true);
|
|
||||||
|
|
||||||
List<WorkbasketSummary> workbaskets = query.idIn(workbasketIdArray).list();
|
for (TaskSummaryImpl task : tasks) {
|
||||||
Iterator<TaskSummaryImpl> taskIterator = taskSummaries.iterator();
|
String classificationId = task.getClassificationSummary().getId();
|
||||||
while (taskIterator.hasNext()) {
|
ClassificationSummary classificationSummary = classificationSummaryById.get(classificationId);
|
||||||
TaskSummaryImpl task = taskIterator.next();
|
if (classificationSummary == null) {
|
||||||
String workbasketId = task.getWorkbasketSummaryImpl().getId();
|
throw new SystemException(
|
||||||
|
"Did not find a Classification for task (Id="
|
||||||
WorkbasketSummary workbasketSummary =
|
+ task.getId()
|
||||||
workbaskets.stream()
|
+ ",Classification="
|
||||||
.filter(x -> workbasketId != null && workbasketId.equals(x.getId()))
|
+ task.getClassificationSummary().getId()
|
||||||
.findFirst()
|
+ ")");
|
||||||
.orElse(null);
|
|
||||||
if (workbasketSummary == null) {
|
|
||||||
LOGGER.warn("Could not find a Workbasket for task {}.", task.getId());
|
|
||||||
taskIterator.remove();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
task.setClassificationSummary(classificationSummary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addWorkbasketSummariesToTaskSummaries(
|
||||||
|
List<TaskSummaryImpl> tasks, Map<String, WorkbasketSummary> workbasketSummaryById) {
|
||||||
|
if (tasks == null || tasks.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TaskSummaryImpl task : tasks) {
|
||||||
|
String workbasketId = task.getWorkbasketSummary().getId();
|
||||||
|
WorkbasketSummary workbasketSummary = workbasketSummaryById.get(workbasketId);
|
||||||
|
if (workbasketSummary == null) {
|
||||||
|
throw new SystemException(
|
||||||
|
"Did not find a Workbasket for task (Id="
|
||||||
|
+ task.getId()
|
||||||
|
+ ",Workbasket="
|
||||||
|
+ task.getWorkbasketSummary().getId()
|
||||||
|
+ ")");
|
||||||
|
}
|
||||||
task.setWorkbasketSummary(workbasketSummary);
|
task.setWorkbasketSummary(workbasketSummary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAttachmentSummariesToTaskSummaries(
|
private void addAttachmentSummariesToTaskSummaries(
|
||||||
List<TaskSummaryImpl> taskSummaries,
|
List<TaskSummaryImpl> taskSummaries, List<AttachmentSummaryImpl> attachmentSummaries) {
|
||||||
List<AttachmentSummaryImpl> attachmentSummaries,
|
|
||||||
List<ClassificationSummary> classifications) {
|
|
||||||
|
|
||||||
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
if (taskSummaries == null || taskSummaries.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// augment attachment summaries by classification summaries
|
Map<String, TaskSummaryImpl> taskSummariesById =
|
||||||
// Note:
|
taskSummaries.stream()
|
||||||
// the mapper sets for each Attachment summary the property classificationSummary.key from the
|
.collect(
|
||||||
// CLASSIFICATION_KEY property in the DB
|
Collectors.toMap(
|
||||||
addClassificationSummariesToAttachmentSummaries(
|
TaskSummary::getId,
|
||||||
attachmentSummaries, taskSummaries, classifications);
|
Function.identity(),
|
||||||
// assign attachment summaries to task summaries
|
// Currently, we still have a bug (TSK-1204), where the TaskQuery#list function
|
||||||
for (TaskSummaryImpl task : taskSummaries) {
|
// returns the same task multiple times when that task has more than one
|
||||||
for (AttachmentSummaryImpl attachment : attachmentSummaries) {
|
// attachment...Therefore, this MergeFunction is necessary.
|
||||||
if (attachment.getTaskId() != null && attachment.getTaskId().equals(task.getId())) {
|
(a, b) -> b));
|
||||||
task.addAttachmentSummary(attachment);
|
|
||||||
}
|
for (AttachmentSummaryImpl attachmentSummary : attachmentSummaries) {
|
||||||
|
String taskId = attachmentSummary.getTaskId();
|
||||||
|
TaskSummaryImpl taskSummary = taskSummariesById.get(taskId);
|
||||||
|
if (taskSummary != null) {
|
||||||
|
taskSummary.addAttachmentSummary(attachmentSummary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addClassificationSummariesToAttachmentSummaries(
|
private void addClassificationSummariesToAttachments(
|
||||||
List<AttachmentSummaryImpl> attachmentSummaries,
|
List<? extends AttachmentSummaryImpl> attachments,
|
||||||
List<TaskSummaryImpl> taskSummaries,
|
Map<String, ClassificationSummary> classificationSummariesById) {
|
||||||
List<ClassificationSummary> classifications) {
|
|
||||||
// prereq: in each attachmentSummary, the classificationSummary.key property is set.
|
if (attachments == null || attachments.isEmpty()) {
|
||||||
if (attachmentSummaries == null
|
|
||||||
|| attachmentSummaries.isEmpty()
|
|
||||||
|| taskSummaries == null
|
|
||||||
|| taskSummaries.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// iterate over all attachment summaries an add the appropriate classification summary to each
|
|
||||||
for (AttachmentSummaryImpl att : attachmentSummaries) {
|
for (AttachmentSummaryImpl attachment : attachments) {
|
||||||
String classificationId = att.getClassificationSummary().getId();
|
String classificationId = attachment.getClassificationSummary().getId();
|
||||||
ClassificationSummary classificationSummary =
|
ClassificationSummary classificationSummary =
|
||||||
classifications.stream()
|
classificationSummariesById.get(classificationId);
|
||||||
.filter(x -> classificationId != null && classificationId.equals(x.getId()))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
if (classificationSummary == null) {
|
|
||||||
throw new SystemException("Could not find a Classification for attachment " + att);
|
|
||||||
}
|
|
||||||
att.setClassificationSummary(classificationSummary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Attachment> addClassificationSummariesToAttachments(
|
|
||||||
List<AttachmentImpl> attachmentImpls, List<ClassificationSummary> classifications) {
|
|
||||||
|
|
||||||
if (attachmentImpls == null || attachmentImpls.isEmpty()) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Attachment> result = new ArrayList<>();
|
|
||||||
for (AttachmentImpl att : attachmentImpls) {
|
|
||||||
// find the associated task to use the correct domain
|
|
||||||
ClassificationSummary classificationSummary =
|
|
||||||
classifications.stream()
|
|
||||||
.filter(c -> c != null && c.getId().equals(att.getClassificationSummary().getId()))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
if (classificationSummary == null) {
|
if (classificationSummary == null) {
|
||||||
throw new SystemException("Could not find a Classification for attachment " + att);
|
throw new SystemException("Could not find a Classification for attachment " + attachment);
|
||||||
}
|
}
|
||||||
att.setClassificationSummary(classificationSummary);
|
attachment.setClassificationSummary(classificationSummary);
|
||||||
result.add(att);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskImpl initUpdatedTask(
|
private TaskImpl initUpdatedTask(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue