OptaPlanner logo
  • Download
  • Learn
    • Documentation
    • Videos

    • Use cases
    • Compatibility
    • Testimonials and case studies
  • Get help
  • Blog
  • Source
  • Team
  • Services
  • Star
  • T
  • L
  • F
  • YT
Fork me on GitHub

Domain modeling guide

Wed 26 October 2016
Avatar Geoffrey De Smet
Geoffrey De Smet

Twitter LinkedIn GitHub

OptaPlanner creator

New OptaPlanner users sometimes struggle to create a good domain model, especially if their use case is complex. But a good domain model can go a long way. It can simplify the constraints, improve performance and increase flexibility for future needs. So how do we design a good domain model for OptaPlanner cases?

The goal

The goal is simple: determine which classes are planning entities and which of their properties are planning variables. Often, there is only one planning entity class with only one planning variable. The other classes are problem facts. The other properties are problem properties.

Ideally, we want to impact the existing domain as little as possible, so we can reuse existing code. So we’ll mainly only add a few OptaPlanner annotations.

The guide

A more up-to-date version of this guide is part of the documentation (in 7.0.0.Beta3 or later), in the chapter Design Patterns.

  1. Draw a class diagram of your domain model. Normalize it get rid of duplicate data.

    • Write down some sample instances for each class.

      • For example in employee rostering, the samples for the Employee class are Ann, Bert and Carl.

  2. Determine which relationships (or fields) change during planning. Color them orange. Often there is only 1 such relationship (or field). One side of these relationships will become a planning variable later on.

    • For example in employee rostering, the Shift to Employee relationship changes during planning, so it is orange. Other relationships, such as from Employee to Skill, are immutable during planning because OptaPlanner can’t decide to give an employee an extra skill.

  3. If there are multiple relationships (or fields): check for shadow variables. A shadow variable does change during planning, but its value can be calculated based on one or more genuine planning variables, without dispute. Color those shadow relationships (or fields) purple.

    • Only one side of a bi-directional relationship can be a genuine planning variable, the other side will become an inverse relation shadow variable later on. Keep those relationships in orange.

  4. Check for chained planning variables. In a chained variable design, the focus lies on deciding the order of a set of planning entity instances, instead of assigning them to a date/time (although there can be an assigned date/time as a shadow variable). A typical use case is vehicle routing.

  5. If there is an orange many-to-many relationship, replace that many-to-many relationship with a one-to-many and a many-to-one relationship to a new intermediate class.

    • OptaPlanner currently doesn’t support a @PlanningVariable on a collection. Although a future version will support it for flexibility reasons, it probably has an inherent performance and complexity cost, so it might be better to avoid it anyway.

    • For example in employee rostering the ShiftAssignment class is the many-to-many relationship between the Shift and Employee. It’s effectively every spot that needs to be filled with an employee.

      employeeShiftRosteringModelingGuideA
  6. In a many-to-one relationship, usually the many side is the planning entity class. Annotate it with a @PlanningEntity annotation.

    • For example in employee rostering, the ShiftAssignment class has a @PlanningEntity annotation.

  7. The planning entity class should have at least one problem property. So a planning entity class cannot consist of only planning variables (or even an id and only planning variables). Remove a surplus @PlanningVariable so it becomes a problem property. This heavily decreases the search space size and heavily increases solving efficiency.

    • For example in employee rostering, the ShiftAssignment class should not annotate both the shift and employee relationship with @PlanningVariable.

    • When all planning variables are null (which occurs when the planning solution is still uninitialized), a planning entity instance should still be describable to the business people.

      • So a surrogate ID does not suffice as the required minimum of one problem property.

    • This way, there is no need to add a hard constraint to assure that two planning entities are different: they are already different due to their problem properties.

    • In some cases, multiple planning entity instances have the same set of problem properties. In such cases, it can be useful to create an extra problem property to distinguish them.

      • For example in employee rostering, the ShiftAssignment class has besides the problem property Shift also the problem property indexInShift (which is an int).

  8. Choose the model in which the number of planning entities is fixed during planning.

    • For example in employee rostering, it’s impossible to know in advance how many shifts each employee will have before OptaPlanner solves it (and it can even differ per best solution found). On the other hand, the number of employees per shift is known in advance, so it’s better to make the Shift relationship a problem property and the Employee relationship a planning variable.

      employeeShiftRosteringModelingGuideB

Going further

To find more inspiration on modeling your domain, take a look at the examples. Also check out the details of shadow variables and chained variables in the documentation.

Does this guide help you to create a better model?


Permalink
 tagged as howto design

Comments

Visit our forum to comment
AtomNews feed
Don’t want to miss a single blog post?
Follow us on
  • T
  • L
  • F
Blog archive
Latest release
  • 8.35.0.Final released
    Fri 3 March 2023
Upcoming events
    Add event / Archive
Latest blog posts
  • OptaPlanner 9 is coming
    Tue 21 February 2023
    Lukáš Petrovický
  • Farewell - a new lead
    Tue 15 November 2022
    Geoffrey De Smet
  • Run OptaPlanner workloads on OpenShift, part II
    Wed 9 November 2022
    Radovan Synek
  • Bavet - A faster score engine for OptaPlanner
    Tue 6 September 2022
    Geoffrey De Smet
  • Run OptaPlanner workloads on OpenShift, part I.
    Thu 9 June 2022
    Radovan Synek
  • OptaPlanner deprecates score DRL
    Thu 26 May 2022
    Lukáš Petrovický
  • Real-time planning meets SolverManager
    Mon 7 March 2022
    Radovan Synek
  • Blog archive
Latest videos
  • The Vehicle Routing Problem
    Fri 23 September 2022
    Geoffrey De Smet
  • Introduction to OptaPlanner AI constraint solver
    Thu 25 August 2022
    Anna Dupliak
  • On schedule: Artificial Intelligence plans that meet expectations
    Sat 23 July 2022
    Geoffrey De Smet
  • Host your OptaPlanner app on OpenShift (Kubernetes)
    Mon 7 February 2022
    Geoffrey De Smet
  • OptaPlanner - A fast, easy-to-use, open source AI constraint solver for software developers
    Mon 31 January 2022
  • Order picking planning with OptaPlanner
    Fri 31 December 2021
    Anna Dupliak
  • AI lesson scheduling on Quarkus with OptaPlanner
    Thu 18 November 2021
    Geoffrey De Smet
  • Video archive

OptaPlanner is open. All dependencies of this project are available under the Apache Software License 2.0 or a compatible license. OptaPlanner is trademarked.

This website was built with JBake and is open source.

Community

  • Blog
  • Get Help
  • Team
  • Governance
  • Academic research

Code

  • Build from source
  • Issue tracker
  • Release notes
  • Upgrade recipes
  • Logo and branding
CC by 3.0 | Privacy Policy
Sponsored by Red Hat