Menu Close
Settings Close

Language and Page Formatting Options

第9章 OptaPlanner SolverManager

SolverManagerは、RESTおよびその他のエンタープライズサービスの計画問題の解決を簡素化するための1つ以上のソルバーインスタンスのファサードです。

Solver.solve (...)メソッドとは異なり、SolverManagerは、次の特性があります。

  • SolverManager.solve (…)はすぐに戻ります。呼び出し元のスレッドをブロックせずに、非同期解決の問題をスケジュールします。これにより、HTTPおよびその他のテクノロジーのタイムアウトの問題が回避されます。
  • SolverManager.solve (…)は、同じドメインの複数の計画問題を並行して解決します。

内部的には、 SolverManagerは、Solver.solve (…)を呼び出すソルバースレッドのスレッドプールと、最適なソリューション変更イベントを処理するコンシューマースレッドのスレッドプールを管理します。

QuarkusとSpringBootでは、 SolverManagerインスタンスがコードに自動的に挿入されます。QuarkusまたはSpringBoot以外のプラットフォームを使用している場合は、 create (…)メソッドを使用してSolverManagerインスタンスをビルドします。

SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../cloudBalancingSolverConfig.xml");
SolverManager<CloudBalance, UUID> solverManager = SolverManager.create(solverConfig, new SolverManagerConfig());

SolverManager.solve (…)メソッドに送信される各問題には、一意の問題IDが必要です。後でgetSolverStatus (problemId)またはterminateEarly (problemId)を呼び出すと、その問題IDを使用して計画の問題を区別します。問題IDは、LongStringjava.util.UUIDなどのイミュータブルなクラスである必要があります。

SolverManagerConfigクラスには、並行して実行されるソルバーの数を制御するparallelSolverCountプロパティがあります。たとえば、 parallelSolverCountプロパティ `が4に設定されていて、5つの問題を送信すると、4つの問題がすぐに解決を開始し、最初の問題の1つが終了すると5番目の問題が開始します。これらの問題がそれぞれ5分間解決した場合、5番目の問題は10分で終了します。デフォルトでは、 parallelSolverCountAUTOに設定されており、ソルバーのmoveThreadCountに関係なく、CPUコアの半分に解決されます。

最適なソリューションを取得するには、終了を解決した後、通常はSolverJob.getFinalBestSolution()を使用します。

CloudBalance problem1 = ...;
UUID problemId = UUID.randomUUID();
// Returns immediately
SolverJob<CloudBalance, UUID> solverJob = solverManager.solve(problemId, problem1);
...
CloudBalance solution1;
try {
    // Returns only after solving terminates
    solution1 = solverJob.getFinalBestSolution();
} catch (InterruptedException | ExecutionException e) {
    throw ...;
}

ただし、ユーザーがソリューションを必要とする前にバッチの問題を解決する方法と、ユーザーがソリューションを積極的に待っている間にライブで解決する方法の両方について、より良いアプローチがあります。

現在のSolverManager実装は単一のコンピューターノードで実行されますが、将来の作業は、クラウド全体にソルバーの負荷を分散することを目的としています。

9.1. 問題のバッチ解決

バッチ解決とは、複数のデータセットを並行して解決することです。バッチ解決は夜間処理で特に役立ちます。

  • 通常、深夜には問題の変化はほとんどまたはまったくありません。一部の組織は期限を強制します。たとえば、深夜零時までに休日のリクエストを送信するといったものです。
  • ソルバーは、結果を待つ人が誰もいないため、CPUリソースが安価であることが多いため、はるかに長く、多くの場合は数時間実行できます。
  • 翌営業日に従業員が職場に到着したときにソリューションが利用できます。

手順

parallelSolverCountによって制限した上で並列バッチでの問題解決するには、各データセットのためには、以下のクラスによって作成した以下の各データについてsolve (...)を呼び出します。

+

public class TimeTableService {

    private SolverManager<TimeTable, Long> solverManager;

    // Returns immediately, call it for every data set
    public void solveBatch(Long timeTableId) {
        solverManager.solve(timeTableId,
                // Called once, when solving starts
                this::findById,
                // Called once, when solving ends
                this::save);
    }

    public TimeTable findById(Long timeTableId) {...}

    public void save(TimeTable timeTable) {...}

}