Home » Java » Enterprise Java » Constraint Streams – Modern Java constraints without the Drools Rule Language

About Geoffrey De Smet

Geoffrey De Smet (Red Hat) is the lead and founder of OptaPlanner. Before joining Red Hat in 2010, he was formerly employed as a Java consultant, an A.I. researcher and an enterprise application project lead. He has contributed to many open source projects (such as drools, jbpm, pressgang, spring-richclient, several maven plugins, weld, arquillian, ...). Since he started OptaPlanner in 2006, he’s been passionately addicted to planning optimization.

Constraint Streams – Modern Java constraints without the Drools Rule Language

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:

1
2
3
4
5
6
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:

1
2
3
4
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:

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:

Indexing

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

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:

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

Code completion

Code completion for Constraint Streams:

Of course, all API methods have Javadocs.

Debugging

Add a breakpoint in ConstraintStream’s filter():

To diagnose issues while debugging:

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 ==:

1
2
3
4
5
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:

1
2
3
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:

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!

Published on Java Code Geeks with permission by Geoffrey De Smet, partner at our JCG program. See the original article here: Constraint Streams – Modern Java constraints without the Drools Rule Language

Opinions expressed by Java Code Geeks contributors are their own.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

I have read and agree to the terms & conditions

 

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments