Skip to content

Commit dce69c0

Browse files
Development: Fix slow database query for Iris pipeline (#10930)
1 parent 5f9a9b5 commit dce69c0

File tree

14 files changed

+135
-11
lines changed

14 files changed

+135
-11
lines changed

src/main/java/de/tum/cit/aet/artemis/atlas/api/CompetencyApi.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package de.tum.cit.aet.artemis.atlas.api;
22

3+
import java.util.Set;
4+
35
import org.springframework.context.annotation.Conditional;
46
import org.springframework.stereotype.Controller;
57

68
import de.tum.cit.aet.artemis.atlas.config.AtlasEnabled;
9+
import de.tum.cit.aet.artemis.atlas.domain.competency.Competency;
10+
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository;
711
import de.tum.cit.aet.artemis.atlas.service.competency.CompetencyService;
812
import de.tum.cit.aet.artemis.lecture.domain.Lecture;
913

@@ -13,11 +17,18 @@ public class CompetencyApi extends AbstractAtlasApi {
1317

1418
private final CompetencyService competencyService;
1519

16-
public CompetencyApi(CompetencyService competencyService) {
20+
private final CompetencyRepository competencyRepository;
21+
22+
public CompetencyApi(CompetencyService competencyService, CompetencyRepository competencyRepository) {
1723
this.competencyService = competencyService;
24+
this.competencyRepository = competencyRepository;
1825
}
1926

2027
public void addCompetencyLinksToExerciseUnits(Lecture lecture) {
2128
competencyService.addCompetencyLinksToExerciseUnits(lecture);
2229
}
30+
31+
public Set<Competency> findAllByCourseId(long courseId) {
32+
return competencyRepository.findAllByCourseId(courseId);
33+
}
2334
}

src/main/java/de/tum/cit/aet/artemis/atlas/api/PrerequisitesApi.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package de.tum.cit.aet.artemis.atlas.api;
22

3+
import java.util.Set;
4+
35
import org.springframework.context.annotation.Conditional;
46
import org.springframework.stereotype.Controller;
57

@@ -25,4 +27,8 @@ public long countByCourse(Course course) {
2527
public void deleteAll(Iterable<Prerequisite> prerequisites) {
2628
prerequisiteRepository.deleteAll(prerequisites);
2729
}
30+
31+
public Set<Prerequisite> findAllByCourseId(long courseId) {
32+
return prerequisiteRepository.findAllByCourseId(courseId);
33+
}
2834
}

src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencyRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ public interface CompetencyRepository extends ArtemisJpaRepository<Competency, L
5555
""")
5656
Optional<Competency> findByIdWithLectureUnitsAndExercises(@Param("competencyId") long competencyId);
5757

58+
@Query("""
59+
SELECT c
60+
FROM Competency c
61+
WHERE c.course.id = :courseId
62+
""")
63+
Set<Competency> findAllByCourseId(@Param("courseId") long courseId);
64+
5865
default Competency findByIdWithLectureUnitsAndExercisesElseThrow(long competencyId) {
5966
return getValueElseThrow(findByIdWithLectureUnitsAndExercises(competencyId), competencyId);
6067
}

src/main/java/de/tum/cit/aet/artemis/atlas/repository/PrerequisiteRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ public interface PrerequisiteRepository extends ArtemisJpaRepository<Prerequisit
5454
""")
5555
Optional<Prerequisite> findByIdWithLectureUnits(@Param("competencyId") long competencyId);
5656

57+
@Query("""
58+
SELECT p
59+
FROM Prerequisite p
60+
WHERE p.course.id = :courseId
61+
""")
62+
Set<Prerequisite> findAllByCourseId(@Param("courseId") long courseId);
63+
5764
default Prerequisite findByIdWithLectureUnitsAndExercisesElseThrow(long competencyId) {
5865
return getValueElseThrow(findByIdWithLectureUnitsAndExercises(competencyId), competencyId);
5966
}

src/main/java/de/tum/cit/aet/artemis/core/repository/CourseRepository.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@ SELECT COUNT(c) > 0
143143
@EntityGraph(type = LOAD, attributePaths = { "exercises", "lectures", "lectures.lectureUnits", "lectures.attachments", "competencies", "prerequisites" })
144144
Optional<Course> findWithEagerExercisesAndLecturesAndLectureUnitsAndCompetenciesById(long courseId);
145145

146-
@EntityGraph(type = LOAD, attributePaths = { "exercises", "lectures", "lectures.lectureUnits", "lectures.attachments", "competencies", "prerequisites", "exams" })
147-
Optional<Course> findWithEagerExercisesAndLecturesAndAttachmentsAndLectureUnitsAndCompetenciesAndExamsById(long courseId);
148-
149146
@Query("""
150147
SELECT course
151148
FROM Course course

src/main/java/de/tum/cit/aet/artemis/exam/api/ExamApi.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package de.tum.cit.aet.artemis.exam.api;
22

3+
import java.time.ZonedDateTime;
4+
import java.util.Set;
5+
36
import org.springframework.context.annotation.Conditional;
47
import org.springframework.stereotype.Controller;
58

69
import de.tum.cit.aet.artemis.exam.config.ExamEnabled;
10+
import de.tum.cit.aet.artemis.exam.domain.Exam;
711
import de.tum.cit.aet.artemis.exam.domain.StudentExam;
812
import de.tum.cit.aet.artemis.exam.dto.StudentExamWithGradeDTO;
13+
import de.tum.cit.aet.artemis.exam.repository.ExamRepository;
914
import de.tum.cit.aet.artemis.exam.service.ExamService;
1015
import de.tum.cit.aet.artemis.exercise.domain.participation.StudentParticipation;
1116

@@ -15,8 +20,11 @@ public class ExamApi extends AbstractExamApi {
1520

1621
private final ExamService examService;
1722

18-
public ExamApi(ExamService examService) {
23+
private final ExamRepository examRepository;
24+
25+
public ExamApi(ExamService examService, ExamRepository examRepository) {
1926
this.examService = examService;
27+
this.examRepository = examRepository;
2028
}
2129

2230
public StudentExamWithGradeDTO getStudentExamGradeForDataExport(StudentExam studentExam) {
@@ -26,4 +34,8 @@ public StudentExamWithGradeDTO getStudentExamGradeForDataExport(StudentExam stud
2634
public boolean shouldStudentSeeResult(StudentExam studentExam, StudentParticipation participation) {
2735
return ExamService.shouldStudentSeeResult(studentExam, participation);
2836
}
37+
38+
public Set<Exam> findAllVisibleByCourseId(long courseId, ZonedDateTime now) {
39+
return examRepository.findAllVisibleByCourseId(courseId, now);
40+
}
2941
}

src/main/java/de/tum/cit/aet/artemis/exam/repository/ExamRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,14 @@ SELECT COUNT(studentExam)
397397
@Cacheable(cacheNames = "examTitle", key = "#examId", unless = "#result == null")
398398
String getExamTitle(@Param("examId") long examId);
399399

400+
@Query("""
401+
SELECT e
402+
FROM Exam e
403+
WHERE e.course.id = :courseId
404+
AND e.visibleDate <= :now
405+
""")
406+
Set<Exam> findAllVisibleByCourseId(@Param("courseId") long courseId, @Param("now") ZonedDateTime now);
407+
400408
/**
401409
* Get one exam by id with exercise groups.
402410
*

src/main/java/de/tum/cit/aet/artemis/exercise/repository/ExerciseRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ public interface ExerciseRepository extends ArtemisJpaRepository<Exercise, Long>
7474
""")
7575
Set<Exercise> findAllExercisesByCourseId(@Param("courseId") long courseId);
7676

77+
@Query("""
78+
SELECT e
79+
FROM Exercise e
80+
WHERE e.course.id = :courseId
81+
AND (e.releaseDate <=:now OR e.releaseDate IS NULL)
82+
""")
83+
Set<Exercise> findAllReleasedExercisesByCourseId(@Param("courseId") long courseId, @Param("now") ZonedDateTime now);
84+
7785
@Query("""
7886
SELECT e
7987
FROM Exercise e

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisPipelineService.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.lang.reflect.InvocationTargetException;
66
import java.lang.reflect.Method;
7+
import java.time.ZonedDateTime;
78
import java.util.HashMap;
89
import java.util.HashSet;
910
import java.util.List;
@@ -20,15 +21,22 @@
2021
import org.springframework.stereotype.Service;
2122

2223
import de.tum.cit.aet.artemis.atlas.api.LearningMetricsApi;
24+
import de.tum.cit.aet.artemis.atlas.api.PrerequisitesApi;
2325
import de.tum.cit.aet.artemis.atlas.config.AtlasNotPresentException;
26+
import de.tum.cit.aet.artemis.atlas.domain.competency.Competency;
2427
import de.tum.cit.aet.artemis.atlas.domain.competency.CompetencyJol;
28+
import de.tum.cit.aet.artemis.atlas.domain.competency.Prerequisite;
2529
import de.tum.cit.aet.artemis.atlas.dto.CompetencyJolDTO;
30+
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository;
2631
import de.tum.cit.aet.artemis.communication.domain.Post;
2732
import de.tum.cit.aet.artemis.core.domain.Course;
2833
import de.tum.cit.aet.artemis.core.repository.CourseRepository;
2934
import de.tum.cit.aet.artemis.core.repository.UserRepository;
35+
import de.tum.cit.aet.artemis.exam.domain.Exam;
36+
import de.tum.cit.aet.artemis.exam.repository.ExamRepository;
3037
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
3138
import de.tum.cit.aet.artemis.exercise.domain.participation.StudentParticipation;
39+
import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository;
3240
import de.tum.cit.aet.artemis.exercise.repository.StudentParticipationRepository;
3341
import de.tum.cit.aet.artemis.iris.domain.session.IrisCourseChatSession;
3442
import de.tum.cit.aet.artemis.iris.domain.session.IrisProgrammingExerciseChatSession;
@@ -47,6 +55,8 @@
4755
import de.tum.cit.aet.artemis.iris.service.pyris.dto.data.PyrisUserDTO;
4856
import de.tum.cit.aet.artemis.iris.service.pyris.dto.status.PyrisStageDTO;
4957
import de.tum.cit.aet.artemis.iris.service.websocket.IrisChatWebsocketService;
58+
import de.tum.cit.aet.artemis.lecture.domain.Lecture;
59+
import de.tum.cit.aet.artemis.lecture.repository.LectureRepository;
5060
import de.tum.cit.aet.artemis.programming.domain.ProgrammingExercise;
5161
import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission;
5262

@@ -76,12 +86,25 @@ public class PyrisPipelineService {
7686

7787
private final UserRepository userRepository;
7888

89+
// we cannot use the apis here in most cases as this leads to circular dependencies, so we use the repositories instead and ignore this class in the architecture tests
90+
private final Optional<LectureRepository> lectureRepository;
91+
92+
private final Optional<CompetencyRepository> competencyRepository;
93+
94+
private final Optional<PrerequisitesApi> prerequisitesApi;
95+
96+
private final Optional<ExamRepository> examRepository;
97+
98+
private final ExerciseRepository exerciseRepository;
99+
79100
@Value("${server.url}")
80101
private String artemisBaseUrl;
81102

82103
public PyrisPipelineService(PyrisConnectorService pyrisConnectorService, PyrisJobService pyrisJobService, PyrisDTOService pyrisDTOService,
83104
IrisChatWebsocketService irisChatWebsocketService, CourseRepository courseRepository, Optional<LearningMetricsApi> learningMetricsApi,
84-
StudentParticipationRepository studentParticipationRepository, UserRepository userRepository) {
105+
StudentParticipationRepository studentParticipationRepository, UserRepository userRepository, Optional<LectureRepository> lectureRepository,
106+
Optional<CompetencyRepository> competencyRepository, Optional<PrerequisitesApi> prerequisitesApi, Optional<ExamRepository> examRepository,
107+
ExerciseRepository exerciseRepository) {
85108
this.pyrisConnectorService = pyrisConnectorService;
86109
this.pyrisJobService = pyrisJobService;
87110
this.pyrisDTOService = pyrisDTOService;
@@ -90,6 +113,11 @@ public PyrisPipelineService(PyrisConnectorService pyrisConnectorService, PyrisJo
90113
this.learningMetricsApi = learningMetricsApi;
91114
this.studentParticipationRepository = studentParticipationRepository;
92115
this.userRepository = userRepository;
116+
this.lectureRepository = lectureRepository;
117+
this.competencyRepository = competencyRepository;
118+
this.prerequisitesApi = prerequisitesApi;
119+
this.examRepository = examRepository;
120+
this.exerciseRepository = exerciseRepository;
93121
}
94122

95123
/**
@@ -301,7 +329,31 @@ public void executeCourseChatPipeline(String variant, String customInstructions,
301329
* @param studentId the id of the student
302330
*/
303331
private Course loadCourseWithParticipationOfStudent(long courseId, long studentId) {
304-
Course course = courseRepository.findWithEagerExercisesAndLecturesAndAttachmentsAndLectureUnitsAndCompetenciesAndExamsById(courseId).orElseThrow();
332+
ZonedDateTime now = ZonedDateTime.now();
333+
Course course = courseRepository.findById(courseId).orElseThrow();
334+
Set<Exercise> releasedExercises = exerciseRepository.findAllReleasedExercisesByCourseId(courseId, now);
335+
Set<Lecture> visibleLectures = new HashSet<>();
336+
if (lectureRepository.isPresent()) {
337+
visibleLectures = lectureRepository.orElseThrow().findAllVisibleByCourseIdWithEagerLectureUnits(courseId, now);
338+
}
339+
Set<Competency> competencies = new HashSet<>();
340+
if (competencyRepository.isPresent()) {
341+
competencies = competencyRepository.orElseThrow().findAllByCourseId(courseId);
342+
}
343+
Set<Prerequisite> prerequisites = new HashSet<>();
344+
if (prerequisitesApi.isPresent()) {
345+
prerequisites = prerequisitesApi.orElseThrow().findAllByCourseId(courseId);
346+
}
347+
Set<Exam> visibleExams = new HashSet<>();
348+
if (examRepository.isPresent()) {
349+
visibleExams = examRepository.orElseThrow().findAllVisibleByCourseId(courseId, now);
350+
}
351+
course.setExercises(releasedExercises);
352+
course.setLectures(visibleLectures);
353+
course.setCompetencies(competencies);
354+
course.setPrerequisites(prerequisites);
355+
course.setExams(visibleExams);
356+
305357
List<StudentParticipation> participations = studentParticipationRepository.findByStudentIdAndIndividualExercisesWithEagerSubmissionsResultIgnoreTestRuns(studentId,
306358
course.getExercises());
307359

src/main/java/de/tum/cit/aet/artemis/lecture/api/LectureApi.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import de.tum.cit.aet.artemis.core.domain.Course;
1111
import de.tum.cit.aet.artemis.core.domain.User;
1212
import de.tum.cit.aet.artemis.lecture.domain.Lecture;
13+
import de.tum.cit.aet.artemis.lecture.repository.LectureRepository;
1314
import de.tum.cit.aet.artemis.lecture.service.LectureImportService;
1415
import de.tum.cit.aet.artemis.lecture.service.LectureService;
1516

@@ -24,9 +25,12 @@ public class LectureApi extends AbstractLectureApi {
2425

2526
private final LectureImportService lectureImportService;
2627

27-
public LectureApi(LectureService lectureService, LectureImportService lectureImportService) {
28+
private final LectureRepository lectureRepository;
29+
30+
public LectureApi(LectureService lectureService, LectureImportService lectureImportService, LectureRepository lectureRepository) {
2831
this.lectureService = lectureService;
2932
this.lectureImportService = lectureImportService;
33+
this.lectureRepository = lectureRepository;
3034
}
3135

3236
public Set<Lecture> filterVisibleLecturesWithActiveAttachments(Course course, Set<Lecture> lecturesWithAttachments, User user) {

src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureRepository.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ public interface LectureRepository extends ArtemisJpaRepository<Lecture, Long> {
3535
""")
3636
Set<Lecture> findAllByCourseId(@Param("courseId") Long courseId);
3737

38+
@Query("""
39+
SELECT lecture
40+
FROM Lecture lecture
41+
LEFT JOIN FETCH lecture.lectureUnits
42+
WHERE lecture.course.id = :courseId
43+
AND (lecture.visibleDate IS NULL OR lecture.visibleDate <= :now)
44+
""")
45+
Set<Lecture> findAllVisibleByCourseIdWithEagerLectureUnits(@Param("courseId") long courseId, @Param("now") ZonedDateTime now);
46+
3847
@Query("""
3948
SELECT lecture
4049
FROM Lecture lecture

src/test/java/de/tum/cit/aet/artemis/atlas/architecture/AtlasApiArchitectureTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Set;
44

55
import de.tum.cit.aet.artemis.atlas.config.AtlasNotPresentException;
6+
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository;
67
import de.tum.cit.aet.artemis.shared.architecture.module.AbstractModuleAccessArchitectureTest;
78

89
class AtlasApiArchitectureTest extends AbstractModuleAccessArchitectureTest {
@@ -14,6 +15,6 @@ public String getModulePackage() {
1415

1516
@Override
1617
protected Set<Class<?>> getIgnoredClasses() {
17-
return Set.of(AtlasNotPresentException.class);
18+
return Set.of(AtlasNotPresentException.class, CompetencyRepository.class);
1819
}
1920
}

src/test/java/de/tum/cit/aet/artemis/exam/architecture/ExamApiArchitectureTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Set;
44

55
import de.tum.cit.aet.artemis.exam.config.ExamApiNotPresentException;
6+
import de.tum.cit.aet.artemis.exam.repository.ExamRepository;
67
import de.tum.cit.aet.artemis.shared.architecture.module.AbstractModuleAccessArchitectureTest;
78

89
class ExamApiArchitectureTest extends AbstractModuleAccessArchitectureTest {
@@ -14,6 +15,6 @@ public String getModulePackage() {
1415

1516
@Override
1617
protected Set<Class<?>> getIgnoredClasses() {
17-
return Set.of(ExamApiNotPresentException.class);
18+
return Set.of(ExamApiNotPresentException.class, ExamRepository.class);
1819
}
1920
}

src/test/java/de/tum/cit/aet/artemis/lecture/architecture/LectureApiArchitectureTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Set;
44

55
import de.tum.cit.aet.artemis.lecture.config.LectureApiNotPresentException;
6+
import de.tum.cit.aet.artemis.lecture.repository.LectureRepository;
67
import de.tum.cit.aet.artemis.lecture.service.SlideUnhideScheduleService;
78
import de.tum.cit.aet.artemis.shared.architecture.module.AbstractModuleAccessArchitectureTest;
89

@@ -15,6 +16,6 @@ public String getModulePackage() {
1516

1617
@Override
1718
protected Set<Class<?>> getIgnoredClasses() {
18-
return Set.of(LectureApiNotPresentException.class, SlideUnhideScheduleService.class);
19+
return Set.of(LectureApiNotPresentException.class, SlideUnhideScheduleService.class, LectureRepository.class);
1920
}
2021
}

0 commit comments

Comments
 (0)