4.2. Solver Configuration

4.2.1. Solver Configuration by XML

Build a Solver instance with the SolverFactory. Configure it with a solver configuration XML file, provided as a classpath resource (as definied by ClassLoader.getResource()):
       SolverFactory solverFactory = SolverFactory.createFromXmlResource(
               "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");
       Solver solver = solverFactory.buildSolver();
In a typical project (following the Maven directory structure), that solverConfig XML file would be located at $PROJECT_DIR/src/main/resources/org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml. Alternatively, a SolverFactory can be created from a File, an InputStream or a Reader with methods such as SolverFactory.createFromXmlFile(). However, for portability reasons, a classpath resource is recommended.
Note
On some environments (OSGi, JBoss modules, ...), classpath resources (such as the solver config, score DRL's and domain classes) in your jars might not be available to the default ClassLoader of the optaplanner-core jar. In those cases, provide the ClassLoader of your classes as a parameter:
       SolverFactory solverFactory = SolverFactory.createFromXmlResource(
               ".../nqueensSolverConfig.xml", getClass().getClassLoader());
A solver configuration file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
  <!-- Define the model -->
  <solutionClass>org.optaplanner.examples.nqueens.domain.NQueens</solutionClass>
  <entityClass>org.optaplanner.examples.nqueens.domain.Queen</entityClass>

  <!-- Define the score function -->
  <scoreDirectorFactory>
    <scoreDefinitionType>SIMPLE</scoreDefinitionType>
    <scoreDrl>org/optaplanner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
  </scoreDirectorFactory>

  <!-- Configure the optimization algorithm(s) -->
  <termination>
    ...
  </termination>
  <constructionHeuristic>
    ...
  </constructionHeuristic>
  <localSearch>
    ...
  </localSearch>
</solver>
Notice the three parts in it:
  • Define the model
  • Define the score function
  • Configure the optimization algorithm(s)
These various parts of a configuration are explained further in this manual.
Planner makes it relatively easy to switch optimization algorithm(s) just by changing the configuration. There is even a Benchmarker utility which allows you to play out different configurations against each other and report the most appropriate configuration for your use case.

4.2.2. Solver Configuration by Java API

A solver configuration can also be configured with the SolverConfig API. This is especially useful to change some values dynamically at runtime. For example, to change the running time based on user input, before building the Solver:
        SolverFactory solverFactory = SolverFactory.createFromXmlResource(
                "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");

        TerminationConfig terminationConfig = new TerminationConfig();
        terminationConfig.setMinutesSpentLimit(userInput);
        solverFactory.getSolverConfig().setTerminationConfig(terminationConfig);

        Solver solver = solverFactory.buildSolver();
Every element in the solver configuration XML is available as a *Config class or a property on a *Config class in the package namespace org.optaplanner.core.config. These *Config classes are the Java representation of the XML format. They build the runtime components (of the package namespace org.optaplanner.core.impl) and assemble them into an efficient Solver.
Important
The SolverFactory is only multi-thread safe after its configured. So the getSolverConfig() method is not thread-safe. To configure a SolverFactory dynamically for each user request, build a SolverFactory as base during initialization and clone it with the cloneSolverFactory() method for a user request:
    private SolverFactory template;

    public void init() {
        SolverFactory base = SolverFactory.createFromXmlResource(
                "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");
        base.getSolverConfig().setTerminationConfig(new TerminationConfig());
    }

    // Called concurrently from different threads
    public void userRequest(..., long userInput)
        SolverFactory solverFactory = base.cloneSolverFactory();
        solverFactory.getSolverConfig().getTerminationConfig().setMinutesSpentLimit(userInput);
        Solver solver = solverFactory.buildSolver();
        ...
    }

4.2.3. Annotations Configuration

4.2.3.1. Automatic Scanning for Annotations

Instead of the declaring the classes that have a @PlanningSolution or @PlanningEntity manually:
<solver>
  <!-- Define the model -->
  <solutionClass>org.optaplanner.examples.nqueens.domain.NQueens</solutionClass>
  <entityClass>org.optaplanner.examples.nqueens.domain.Queen</entityClass>

  ...
</solver>
Planner can find scan the classpath and find them automatically:
<solver>
  <!-- Define the model -->
  <scanAnnotatedClasses/>

  ...
</solver>
If there are multiple models in your classpath (or just to speed up scanning), specify the packages to scan:
<solver>
  <!-- Define the model -->
  <scanAnnotatedClasses>
    <packageInclude>org.optaplanner.examples.cloudbalancing</packageInclude>
  </scanAnnotatedClasses>

  ...
</solver>
This will find all solution and entity classes in the package or subpackages.
Note
If scanAnnotatedClasses is not specified, the org.reflections transitive maven dependency can be excluded.

4.2.3.2. Annotation Alternatives

Planner needs to be told which classes in your domain model are planning entities, which properties are planning variables, etc. There are several ways to deliver this information:
  • Add class annotations and JavaBean property annotations on the domain model (recommended). The property annotations must be the getter method, not on the setter method. Such a getter does not need to be public.
  • Add class annotations and field annotations on the domain model. Such a field does not need to be public.
  • No annotations: externalize the domain configuration in an XML file. This is not yet supported.
This manual focuses on the first manner, but every features supports all 3 manners, even if it's not explicitly mentioned.