Toggle navigation OptaPlanner logo
  • Home
  • Download
  • Learn
    • Documentation
    • Videos
    • Slides
    • Training
    • Use cases
    • Compatibility
    • Testimonials and case studies
  • Get help
  • Source
  • Team
  • Services
  • Star
  • @OptaPlanner
  • Fb
Fork me on GitHub
  • How to plan (and optimize) a Secret Santa
  • Workflow processes with AI scheduling

Constraint Streams - Modern Java constraints without the Drools Rule Language

Tue 7 April 2020

Avatar Geoffrey De Smet

Geoffrey De Smet


Twitter LinkedIn GitHub

OptaPlanner lead

Traditionally, to scale out with OptaPlanner, you had to learn DRL. No more. With the new Constraints Streams API, inspired by Java 8 Streams and SQL, you can now write your constraints in Java (or Kotlin or Scala) and still benefit from incremental calculation.

Underneath, Constraints Streams (CS) still use the powerful Drools engine. We also still fully support score DRLs too. They are not deprecated.

Let’s start with an example. In nurse rostering, to avoid assigning shifts to employee Ann, you would write this constraint in DRL:

rule "Don't assign Ann"
    when
        Shift(getEmployee().getName() == "Ann")
    then
        scoreHolder.addSoftConstraintMatch(kcontext, -1);
end

This is the same constraint in Java using Constraint Streams:

Constraint constraint = constraintFactory
        .from(Shift.class)
        .filter(shift -> shift.getEmployee().getName().equals("Ann"))
        .penalize("Don't assign Ann", HardSoftScore.ONE_SOFT);

If you’re familiar with SQL or Java 8 streams, this should look familiar. Given a potential solution with four shifts (two of which are assigned to Ann), those shifts flow through the Constraint Stream like this:

constraintStreamFilter part

This new approach to writing constraints has several benefits:

Incremental calculation

First off, unlike an EasyScoreCalculator, Constraint Streams still apply incremental score calculation to scale out, just like DRL. For example, when a move swaps the employee of two shifts, only the delta is calculated. That’s a huge scalability gain:

constraintStreamIncrementalCalculation

Indexing

When joining multiple types, just like an SQL JOIN operator, Constraint Streams apply hash lookups on indexes to scale better:

constraintStreamJoinWithJoiners

IDE support

Because ConstraintsStreams are written in the Java language, they piggy-back on very strong tooling support.

Code highlighting, code completion and debugging just work:

Code highlighting

DRL code in IntelliJ IDEA Ultimate:

codeHighlightingDRL

Java code using Constraint Streams in IntelliJ IDEA Ultimate, for the same constraints:

codeHighlightingConstraintStreams

Code completion

Code completion for Constraint Streams:

codeCompletionConstraintStreams

Of course, all API methods have Javadocs.

Debugging

Add a breakpoint in ConstraintStream’s filter():

codeDebuggingConstraintStreams1

To diagnose issues while debugging:

codeDebuggingConstraintStreams2

Java syntax

Constraints written in Java with Constraint Streams follow the Java Language Specification (JLS), for good or bad. Similar logic applies when using Constraint Streams from Kotlin or Scala.

When migrating between DRL and Constraint Streams, be aware of some differences between DRL and Java:

  • A DRL’s == operator translates to equals() in Java.

  • Besides getters, DRL also allows MVEL expressions that translate into getters in Java.

For example, this DRL has name and ==:

rule "Don't assign Ann"
    when
        Employee(name == "Ann")
    then ...
end

But the Java variant for the exact same constraint has getName() and equals() instead:

constraintFactory.from(Employee.class)
        .filter(employee -> employee.getName().equals("Ann"))
        .penalize("Don't assign Ann", ...);

Advanced functions

The Constraint Streams API allows us to add syntactic sugar and powerful new concepts, specifically tailored to help you build complex constraints.

Just to highlight one of these, let’s take a look at the powerful groupBy method:

constraintStreamGroupBy

Similar to an SQL GROUP BY operator or a Java 8 Stream Collector, it support sum(), count(), countDistinct(), min(), max(), toList() and even custom functions, again without loss of incremental score calculation.

Future work for Constraint Streams

First off, a big thanks to Lukáš Petrovický for all his work on Constraints Streams!

But this is just the beginning. We envision more advanced functions, such as load balancing/fairness methods to make such constraints easier to implement.

Right now, our first priority is to make it easier to unit test constraints in isolation. Think Test Driven Design. Stay tuned!


Comments Permalink
 tagged as feature coding constraint

Comments

Visit our forum to comment
  • How to plan (and optimize) a Secret Santa
  • Workflow processes with AI scheduling
Atom News feed
Don't want to miss a single blog post?
Follow us on
  • T
  • Fb
Blog archive
Latest release
  • 8.3.0.Final released
    Fri 5 March 2021
Upcoming events
  • KIE Live
    Worldwide - Tue 9 March 2021
    • Testing your constraints with OptaPlanner by Lukáš Petrovický, Karina Varela, Alex Porcelli
  • Javaland
    Worldwide - Tue 16 March 2021
    • AI on Quarkus: I love it when an OptaPlan comes together by Geoffrey De Smet
  • Red Hat Webinar
    Worldwide - Wed 24 March 2021
    • AI planning: Top 3 use cases and benefits by Ronald Meuwsen, Geoffrey De Smet
  • SouJava MOTU
    Worldwide - Thu 15 April 2021
    • Planejamento de Recursos com OptaPlanner by Karina Varela, Otávio Santana
Add event / Archive
Latest blog posts
  • Optimizing COVID-19 vaccination appointment scheduling
    Thu 4 March 2021
     Paul Brown
  • How much faster is Java 15?
    Tue 26 January 2021
     Michal Tomčo
  • Solve the facility location problem
    Fri 9 October 2020
     Jiří Locker
  • OptaPlanner Week 2020 recordings
    Mon 7 September 2020
     Geoffrey De Smet
  • Let’s OptaPlan your jBPM tasks (part 1) - Integrating the two worlds
    Fri 3 July 2020
     Walter Medvedeo
  • AI versus Covid-19: How Java helps nurses and doctors in this fight
    Fri 8 May 2020
     Christopher Chianelli
  • Workflow processes with AI scheduling
    Tue 5 May 2020
     Christopher Chianelli
Blog archive
Latest videos
  • YT Maintenance scheduling
    Wed 24 February 2021
     Julian Cui
  • YT Vaccination appointment scheduling
    Wed 3 February 2021
     Geoffrey De Smet
  • YT Shadow variables
    Tue 19 January 2021
     Geoffrey De Smet
  • YT Domain modeling and design patterns
    Tue 17 November 2020
     Geoffrey De Smet
  • YT Quarkus insights: AI constraint solving
    Tue 20 October 2020
     Geoffrey De Smet
  • YT AI in kotlin
    Wed 23 September 2020
     Geoffrey De Smet
  • YT Planning agility: continuous planning, real-time planning and more
    Thu 3 September 2020
     Geoffrey De Smet
Video archive

KIE projects

  • Drools rule engine
  • OptaPlanner constraint solver
  • jBPM workflow engine

Community

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

Code

  • Build from source
  • Submit a bug
  • License (Apache-2.0)
  • Release notes
  • Upgrade recipes
Sponsored by
Red Hat
More coder content at
Red Hat Developers
© Copyright 2006-2021, Red Hat, Inc. or third-party contributors - Privacy statement - Terms of use - Website info