用Optaplanner实现云资源优化:求解篇

580 阅读5分钟

引言

之前《用Optaplanner实现云资源优化:建模详解》一文中,讲解了Cloud Balanceing优化问题的建模过程。这次的内容会实操一下,在这个实操中,我们将一步步地运行程序,学习约束的设计和求解器的配置。具体来说,我们将介绍如何使用OptaPlanner解决Cloud Balancing问题,并讲解如何进行约束设计、求解器的配置等方面的内容。通过这个实操,我们可以深入了解OptaPlanner的实际应用,掌握如何利用其强大的功能解决实际问题。

执行Hello World

学习Java的第一步都是执行了一个“Hello World”,这次我们也是从Optaplanner的HelloWorld开始尝试运行下求解。

下载Cloud Balancing案例源代码

打开Optaplanner的官方github地址:github.com/kiegroup/op…
image.png
optaplanner-examples文件夹内有官方的所有的案例源码。因为这个文件夹也是一个Mave工程,所以下载完成后,用idea打开文件夹就可以。
image.png

需要注意:optaplanner 8.39.0 版本的代码,依赖的JDK需要是11以上的版本。

目录结构

在cloudBalancing子目录中,将看到一个pom.xml文件和一些Java源代码文件,Java源代码文件包括实体类、求解器类和测试类等。
image.png
domain包
domain 包通常包含了一个或多个实体类以及它们的属性。在当前例子中,包含了两个实体类 CloudComputer 和 CloudProcess。这些实体类通常用于表示领域模型中的对象,并包含了它们的属性和方法。
其中包含了一个名为 CloudBalance 的解决方案类。这个类通常用于表示整个问题的解决方案,并包含了各个实体类的集合以及它们的属性和方法。
score包
包含了各种约束条件的类。这些类通常使用 OptaPlanner 的注解来表示约束条件,并实现了相应的检查方法。
app包
在 OptaPlanner 中,app 包通常包含了应用程序的入口点,以及与用户界面、文件读写等相关的代码。包含了一个名为 CloudBalancingHelloWorld 的主类,它用于启动应用程序和执行求解器来求解问题。

执行求解

找到CloudBalancingHelloWorld运行类里面的main方法进行求解。
image.png
控制台输出以下内容时就代表程序已经运行成功了:

14:55:23.580 [main        ] INFO  CloudBalance 400computers-1200processes has 400 computers and 1200 processes with a search space of 10^3123.
14:55:23.888 [main        ] INFO  Solving started: time spent (275), best score (-1200init/0hard/0soft), environment mode (REPRODUCIBLE), move thread count (NONE), random (JDK with seed 0).
14:55:24.096 [main        ] DEBUG     CH step (0), time spent (483), score (-1199init/0hard/-550soft), selected move count (400), picked move (CloudProcess-0 {null -> CloudComputer-270}).

代码分析

CloudBalancingHelloWorld都做了哪些事情。

public class CloudBalancingHelloWorld {

    public static void main(String[] args) {
        // Build the Solver
        SolverFactory<CloudBalance> solverFactory = SolverFactory.create(new SolverConfig()
                .withSolutionClass(CloudBalance.class)
                .withEntityClasses(CloudProcess.class)
                .withConstraintProviderClass(CloudBalancingConstraintProvider.class)
                .withTerminationSpentLimit(Duration.ofMinutes(2)));
        Solver<CloudBalance> solver = solverFactory.buildSolver();

        // Load a problem with 400 computers and 1200 processes
        CloudBalance unsolvedCloudBalance = new CloudBalancingGenerator().createCloudBalance(400, 1200);

        // Solve the problem
        CloudBalance solvedCloudBalance = solver.solve(unsolvedCloudBalance);

        // Display the result
        System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n"
                + toDisplayString(solvedCloudBalance));
    }

这段代码主要执行了以下四个步骤,每个步骤都有相应的注释:

  1. 创建求解器工厂和求解器对象,并设置求解器参数:
// Build the Solver
SolverFactory<CloudBalance> solverFactory = SolverFactory.create(new SolverConfig()
        .withSolutionClass(CloudBalance.class)
        .withEntityClasses(CloudProcess.class)
        .withConstraintProviderClass(CloudBalancingConstraintProvider.class)
        .withTerminationSpentLimit(Duration.ofMinutes(2)));
Solver<CloudBalance> solver = solverFactory.buildSolver();

这个步骤创建了一个求解器工厂和一个求解器对象,用于解决 Cloud Balancing 问题。其中,SolverConfig 对象用于设置求解器的参数,包括解决方案类、实体类、约束条件提供者和终止条件等。

  1. 加载待解决的 Cloud Balance 问题:
// Load a problem with 400 computers and 1200 processes
CloudBalance unsolvedCloudBalance = new CloudBalancingGenerator().createCloudBalance(400, 1200);

这个步骤使用 CloudBalancingGenerator 类生成了一个包含 400 台计算机和 1200 个进程的 Cloud Balance 问题,用于求解器求解。

  1. 使用求解器对象解决 Cloud Balance 问题:
// Solve the problem
CloudBalance solvedCloudBalance = solver.solve(unsolvedCloudBalance);

这个步骤使用求解器对象对待解决的 Cloud Balance 问题进行求解,并得到一个最优解 solvedCloudBalance。

  1. 显示求解结果:
// Display the result
System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n"
        + toDisplayString(solvedCloudBalance));

这个步骤将求解结果输出到控制台,其中 toDisplayString() 方法用于将解决方案格式化为可读性高的字符串。

求解器配置

// Build the Solver
SolverFactory<CloudBalance> solverFactory = SolverFactory.create(new SolverConfig()
        .withSolutionClass(CloudBalance.class)
        .withEntityClasses(CloudProcess.class)
        .withConstraintProviderClass(CloudBalancingConstraintProvider.class)
        .withTerminationSpentLimit(Duration.ofMinutes(2)));
Solver<CloudBalance> solver = solverFactory.buildSolver();

这段代码创建了一个 SolverFactory 对象和一个 Solver 对象,并通过 with 方法设置了求解器的一些参数。下面逐个介绍每个 with 方法的作用

设置Solution

withSolutionClass(CloudBalance.class):设置解决方案类,即 CloudBalance 类。OptaPlanner 的求解器通过对解决方案进行求解来解决问题。

设置Entity

withEntityClasses(CloudProcess.class):设置实体类,即 CloudProcess 类。实体类通常用于表示问题中的对象,例如 Cloud Balancing 中的计算机和进程。

设置约束条件

withConstraintProviderClass(CloudBalancingConstraintProvider.class):设置约束条件提供者类,即 CloudBalancingConstraintProvider 类。约束条件提供者用于定义问题中的约束条件,例如计算机的容量限制和进程的数量限制等。

设置终止条件

withTerminationSpentLimit(Duration.ofMinutes(2)):设置终止条件,即求解器的最大运行时间。这里设置为 2 分钟,表示如果求解器在 2 分钟内无法找到更优的解决方案,则终止求解过程。

总结

通过本文,了解了 OptaPlanner 的基本概念和使用方法,包括如何定义问题、创建求解器、以及官方例子的运行。在下一遍文章里,会介绍 OptaPlanner 的 Constraint Streams 功能,以及如何使用它来实现高效的约束条件计算。

如果您想转载我的文章,请注明原作者和出处,谢谢。