8.7. 运行 7000 timetable 应用程序


创建 IANA 时间范围项目后,在开发模式下运行它。在开发模式中,您可以在应用程序运行时更新应用程序源和配置。您的更改将显示在正在运行的应用程序中。

先决条件

  • 您已创建了 phone timetable 项目。

流程

  1. 要将应用程序以开发模式编译,请从项目目录中输入以下命令:

    ./mvnw compile quarkus:dev
  2. 测试 REST 服务。您可以使用任何 REST 客户端。以下示例使用 Linux 命令 curl 发送 POST 请求:

    $ curl -i -X POST http://localhost:8080/timeTable/solve -H "Content-Type:application/json" -d '{"timeslotList":[{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"}],"roomList":[{"name":"Room A"},{"name":"Room B"}],"lessonList":[{"id":1,"subject":"Math","teacher":"A. Turing","studentGroup":"9th grade"},{"id":2,"subject":"Chemistry","teacher":"M. Curie","studentGroup":"9th grade"},{"id":3,"subject":"French","teacher":"M. Curie","studentGroup":"10th grade"},{"id":4,"subject":"History","teacher":"I. Jones","studentGroup":"10th grade"}]}'

    终止中指定的时间用 application.properties 文件中定义的时间后,服务会返回类似以下示例的输出:

    HTTP/1.1 200
    Content-Type: application/json
    ...
    
    {"timeslotList":...,"roomList":...,"lessonList":[{"id":1,"subject":"Math","teacher":"A. Turing","studentGroup":"9th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},"room":{"name":"Room A"}},{"id":2,"subject":"Chemistry","teacher":"M. Curie","studentGroup":"9th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"},"room":{"name":"Room A"}},{"id":3,"subject":"French","teacher":"M. Curie","studentGroup":"10th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},"room":{"name":"Room B"}},{"id":4,"subject":"History","teacher":"I. Jones","studentGroup":"10th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"},"room":{"name":"Room B"}}],"score":"0hard/0soft"}

    请注意,您的应用程序为两个时间插槽和两个空间之一分配了四个小活动。另请注意,它符合所有硬限制。例如,M. Curie 的两个定义位于不同的时间段内。

  3. 要查看在过期期间 OptaPlanner 执行的操作,请查看服务器端的信息日志。以下是 info 日志输出示例:

    ... Solving started: time spent (33), best score (-8init/0hard/0soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
    ... Construction Heuristic phase (0) ended: time spent (73), best score (0hard/0soft), score calculation speed (459/sec), step total (4).
    ... Local Search phase (1) ended: time spent (5000), best score (0hard/0soft), score calculation speed (28949/sec), step total (28398).
    ... Solving ended: time spent (5000), best score (0hard/0soft), score calculation speed (28524/sec), phase total (2), environment mode (REPRODUCIBLE).

8.7.1. 构建应用程序

良好的应用程序包括测试覆盖。这个示例在 Red Hat build of Quarkus 上测试红帽构建的 OptaPlanner Demo timetable 项目。它使用 JUnit 测试来生成测试数据集,并将其发送到 TimeTableController 来解决。

流程

  1. 使用以下内容创建 src/test/java/com/example/rest/TimeTableResourceTest.java 类:

    package com.exmaple.optaplanner.rest;
    
    import java.time.DayOfWeek;
    import java.time.LocalTime;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.inject.Inject;
    
    import io.quarkus.test.junit.QuarkusTest;
    import com.exmaple.optaplanner.domain.Room;
    import com.exmaple.optaplanner.domain.Timeslot;
    import com.exmaple.optaplanner.domain.Lesson;
    import com.exmaple.optaplanner.domain.TimeTable;
    import com.exmaple.optaplanner.rest.TimeTableResource;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.Timeout;
    
    import static org.junit.jupiter.api.Assertions.assertFalse;
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    @QuarkusTest
    public class TimeTableResourceTest {
    
        @Inject
        TimeTableResource timeTableResource;
    
        @Test
        @Timeout(600_000)
        public void solve() {
            TimeTable problem = generateProblem();
            TimeTable solution = timeTableResource.solve(problem);
            assertFalse(solution.getLessonList().isEmpty());
            for (Lesson lesson : solution.getLessonList()) {
                assertNotNull(lesson.getTimeslot());
                assertNotNull(lesson.getRoom());
            }
            assertTrue(solution.getScore().isFeasible());
        }
    
        private TimeTable generateProblem() {
            List<Timeslot> timeslotList = new ArrayList<>();
            timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(8, 30), LocalTime.of(9, 30)));
            timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(9, 30), LocalTime.of(10, 30)));
            timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(10, 30), LocalTime.of(11, 30)));
            timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(13, 30), LocalTime.of(14, 30)));
            timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(14, 30), LocalTime.of(15, 30)));
    
            List<Room> roomList = new ArrayList<>();
            roomList.add(new Room("Room A"));
            roomList.add(new Room("Room B"));
            roomList.add(new Room("Room C"));
    
            List<Lesson> lessonList = new ArrayList<>();
            lessonList.add(new Lesson(101L, "Math", "B. May", "9th grade"));
            lessonList.add(new Lesson(102L, "Physics", "M. Curie", "9th grade"));
            lessonList.add(new Lesson(103L, "Geography", "M. Polo", "9th grade"));
            lessonList.add(new Lesson(104L, "English", "I. Jones", "9th grade"));
            lessonList.add(new Lesson(105L, "Spanish", "P. Cruz", "9th grade"));
    
            lessonList.add(new Lesson(201L, "Math", "B. May", "10th grade"));
            lessonList.add(new Lesson(202L, "Chemistry", "M. Curie", "10th grade"));
            lessonList.add(new Lesson(203L, "History", "I. Jones", "10th grade"));
            lessonList.add(new Lesson(204L, "English", "P. Cruz", "10th grade"));
            lessonList.add(new Lesson(205L, "French", "M. Curie", "10th grade"));
            return new TimeTable(timeslotList, roomList, lessonList);
        }
    
    }

    此测试会验证之后,所有较少记录都会被分配给一个时间插槽和房间。它还会验证它发现了一个可行的解决方案(没有硬约束中断)。

  2. src/main/resources/application.properties 文件中添加 test 属性:

    # The solver runs only for 5 seconds to avoid a HTTP timeout in this simple implementation.
    # It's recommended to run for at least 5 minutes ("5m") otherwise.
    quarkus.optaplanner.solver.termination.spent-limit=5s
    
    # Effectively disable this termination in favor of the best-score-limit
    %test.quarkus.optaplanner.solver.termination.spent-limit=1h
    %test.quarkus.optaplanner.solver.termination.best-score-limit=0hard/*soft

通常,解析器会在 200 毫秒内找到可行的解决方案。请注意,application.properties 文件在测试期间如何覆盖 solver 终止,以便在找到可行的解决方案 (0hard thesoft) 时立即终止。这可避免硬编码一个固定时间,因为单元测试可能会在任意硬件上运行。这种方法可确保测试运行足够长,以找到可行的解决方案,即使在较慢的系统上也是如此。但是,即使在快速的系统上,它不会运行毫秒的时间超过其严格要求。

8.7.2. 日志记录

完成 Red Hat build of OptaPlanner 旧时间后,您可以使用日志信息来帮助微调 ConstraintProvider 中的限制。查看 info 日志文件中的分数计算速度,以评估对您的限制的影响。以调试模式运行应用程序,以显示应用程序采取的每个步骤,或使用 trace 日志记录来记录每个步骤和每次移动。

流程

  1. 在固定时间内运行 7000 timetable 应用程序,例如五分钟。
  2. 查看日志文件中的分数计算速度,如下例所示:

    ... Solving ended: ..., score calculation speed (29455/sec), ...
  3. 更改约束,在相同时间内再次运行 planning 应用程序,并查看日志文件中记录的分数计算速度。
  4. 以 debug 模式运行应用程序,以记录应用程序所做的每个步骤:

    • 要从命令行运行调试模式,请使用 -D 系统属性。
    • 要永久启用调试模式,请在 application.properties 文件中添加以下行:

      quarkus.log.category."org.optaplanner".level=debug

      以下示例以 debug 模式显示 日志文件中 的输出:

      ... Solving started: time spent (67), best score (-20init/0hard/0soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
      ...     CH step (0), time spent (128), score (-18init/0hard/0soft), selected move count (15), picked move ([Math(101) {null -> Room A}, Math(101) {null -> MONDAY 08:30}]).
      ...     CH step (1), time spent (145), score (-16init/0hard/0soft), selected move count (15), picked move ([Physics(102) {null -> Room A}, Physics(102) {null -> MONDAY 09:30}]).
      ...
  5. 使用 trace 日志记录来显示每个步骤,以及每个步骤的每次移动。
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部