Saturday, April 20, 2024
HomeJavaBavet - A sooner rating engine for OptaPlanner - Java Code Geeks

Bavet – A sooner rating engine for OptaPlanner – Java Code Geeks


Drools is an especially quick rule engine. Below the hood, OptaPlanner has used Drools as a rating engine for ages. At this time, we’re asserting a sooner, light-weight different: Bavet.

Bavet is a function of OptaPlanner. It’s not a rule engine. It’s a pure, single-purpose, incremental rating calculation implementation of the ConstraintStreams API. Bavet is function full as of OptaPlanner 8.27.0.Remaining. You’ll be able to change from Drools to Bavet in a single line of code.

Twice as quick rating calculation. Zero API adjustments.

Sooner

For 20 various use instances, we in contrast Bavet and Drools for OptaPlanner rating calculation. We ran JMH benchmarks on OpenJDK 17 (ParallelGC, Xmx1G) on a steady benchmark machine (Intel® Xeon® Silver (12 cores whole / 24 threads) and 128 GiB RAM reminiscence) with out every other computational demanding processes operating.

On common, Bavet is twice as quick as Drools for rating calculation. Within the Automobile Routing Drawback, Bavet is even 3 times as quick as Drools:

Use case Drools Bavet Velocity up
cheaptime 4,349 14,543 +234%
cloudbalancing 162,820 608,204 +274%
coachShuttleGathering 38,543 111,991 +191%
conferenceScheduling 1,072 1,264 +18%
curriculumCourse 32,272 38,933 +21%
examination 11,821 25,712 +118%
flightCrewScheduling 97,020 126,563 +30%
funding 68,935 401,806 +483%
machineReassignment 13,384 28,619 +114%
meetingscheduling 2,291 2,158 -6%
nQueens 177,528 285,268 +61%
nurserostering 10,657 21,090 +98%
pas 50,971 47,551 -7%
projectjobscheduling 23,715 78,291 +230%
rockTour 33,997 152,472 +348%
taskAssigning 10,531 20,680 +96%
tennis 106,172 236,437 +123%
travelingtournament 49,428 77,143 +56%
tsp 169,125 430,384 +154%
vehicleRouting 8,247 26,187 +218%
Common: 53,644 136,765 +132%

Bavet is quicker than Drools for 90% of the use instances. In fact, your mileage could fluctuate. Activate Bavet and if it’s not sooner in your use case, tell us.

Drools and Bavet are each nonetheless enhancing. This efficiency race is much from over.

Scaling

Does Bavet scale effectively?

On commodity {hardware}, we ran a 5 minutes VRP benchmark on completely different dataset sizes, to check how Drools and Bavet scale up:

  belgium-n50-k10 belgium-n100-k10 belgium-n500-k20 belgium-n1000-k20 belgium-n2750-k55 Common
Drools 76,919/s 58,365/s 36,609/s 23,394/s 29,770/s 45,011/s
Bavet 307,290/s 242,400/s 147,595/s 89,850/s 91,115/s 175,650/s
Velocity up +299.50% +315.32% +303.17% +284.07% +206.06% +290.24%

Similar story, however the efficiency hole does shut as the dimensions goes up.

Not a rule engine

Bavet is not a rule engine. It intentionally doesn’t help inference, nor Complicated Occasion Processing (CEP), nor different frequent enterprise rule engine options:

OptaPlanner solely requires a rating engine. Its Drools implementation solely makes use of a small subset of Drools’s options. Bavet however, is a rating engine tailor-made to OptaPlanner. It’s a part of OptaPlanner. It has no use outdoors of OptaPlanner.

For incremental rating calculation, Bavet borrows methods from the RETE algorithm and Drools’s Phreak algorithm. For instance, the JoinNode in Bavet comprises insert(), replace() and retract() strategies. However under the floor, it’s a really completely different implementation. Evaluate it with the strategy signatures of comparable strategies within the JoinNode in Drools.

Historical past and naming

I created Bavet as a POC in 2019 and added it into OptaPlanner as an experimental, quick, incomplete function. There it sat frozen. For 3 years. Till just lately, when Lukáš Petrovický and me accomplished all lacking options and refactored it to the efficiency sensation is right this moment.

Naming sensible, bavet is a Flemish (Dutch) slang phrase for a bib. Very helpful in case your child is drooling. I got here up with that title after we had been consuming with our youngsters at a spaghetti restaurant known as Bavet, whereas dealing with this mural:

Okay, perhaps I didn’t put a lot effort into that.

Nevertheless it doesn’t actually need title. It’s simply one in all OptaPlanner’s rating calculation choices. An implementation element, actually.

Stability

We consider Bavet may be very steady. We efficiently run our 48+ hours stress exams on Bavet repeatedly. These stress exams stomp out rating corruption by fixing numerous datasets throughout many use instances.

Extra light-weight

In OpenShift and Kubernetes clouds, the dimensions of pods matter. Through the use of Bavet, you possibly can slim down OptaPlanner’s classpath to exclude the Drools dependencies. The Bavet jar is 400 KB.

On the OptaPlanner hello-world quickstart, a Maven meeting of jar-with-dependencies with solely Bavet included is 10 MB smaller:

Core dependencies Dimension Discount Core exclusions
All (default) 17.5 MB 0% none
Drools CS solely 17.1 MB -2% optaplanner-constraint-drl, optaplanner-constraint-streams-bavet
Bavet CS solely 7.0 MB -60% optaplanner-constraint-drl, optaplanner-constraint-streams-drools

By default, optaplanner-core contains each Drools and Bavet, so you must explicitly exclude it in Maven or Gradle:

<dependency>
      <groupId>org.optaplanner</groupId>
      <artifactId>optaplanner-core</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.optaplanner</groupId>
          <artifactId>optaplanner-constraint-drl</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.optaplanner</groupId>
          <artifactId>optaplanner-constraint-streams-drools</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

This reduces optaplanner-core from 42 to 17 transitive dependencies. Particularly, all these jars are eliminated out of your classpath:

- org.optaplanner:optaplanner-constraint-streams-drools:...
   +- org.drools:drools-engine:...
   |  +- org.kie:kie-api:...
   |  +- org.kie:kie-internal:...
   |  +- org.drools:drools-core:...
   |  |  +- org.kie:kie-util-xml:...
   |  |  +- org.drools:drools-wiring-api:...
   |  |  +- org.drools:drools-wiring-static:...
   |  |  +- org.drools:drools-util:...
   |  |  - commons-codec:commons-codec:...
   |  +- org.drools:drools-wiring-dynamic:...
   |  +- org.drools:drools-kiesession:...
   |  +- org.drools:drools-tms:...
   |  +- org.drools:drools-compiler:...
   |  |  +- org.drools:drools-drl-parser:...
   |  |  +- org.drools:drools-drl-extensions:...
   |  |  +- org.drools:drools-drl-ast:...
   |  |  +- org.kie:kie-memory-compiler:...
   |  |  +- org.drools:drools-ecj:...
   |  |  +- org.kie:kie-util-maven-support:...
   |  |  - org.antlr:antlr-runtime:...
   |  +- org.drools:drools-model-compiler:...
   |  |  - org.drools:drools-canonical-model:...
   |  - org.drools:drools-model-codegen:...
   |     +- org.drools:drools-codegen-common:...
   |     +- com.github.javaparser:javaparser-core:...
   |     +- org.drools:drools-mvel-parser:...
   |     - org.drools:drools-mvel-compiler:...
   - org.drools:drools-alphanetwork-compiler:...

Bavet (optaplanner-constraint-streams-bavet) has no transitive dependencies (apart from optaplanner-constraint-streams-common).

Attempt it out

First improve to OptaPlanner 8.27.0.Remaining or later, should you haven’t already. In the event you’re utilizing the deprecated scoreDRL method, migrate from scoreDRL to constraint streams first.

By default, OptaPlanner nonetheless makes use of Drools for constraint streams. To make use of Bavet as a substitute, explicitly change the ConstraintStreamImplType to BAVET:

Plain Java

Change to Bavet in both your *.java file:

SolverFactory<TimeTable> solverFactory = SolverFactory.create(new SolverConfig()
        ...
        .withConstraintStreamImplType(ConstraintStreamImplType.BAVET)
        ...);

or in your solverConfig.xml:

<scoreDirectorFactory>
    ...
    <constraintStreamImplType>BAVET</constraintStreamImplType>
  </scoreDirectorFactory>

Quarkus

Change to Bavet in src/important/sources/utility.properties:

quarkus.optaplanner.solver.constraintStreamImplType=BAVET

Spring

Change to Bavet in src/important/sources/utility.properties:

optaplanner.solver.constraintStreamImplType=BAVET
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments