Chapter 22. Performance tuning considerations with DRL The following key concepts or suggested practices can help you optimize DRL rules and decision engine performance. These concepts are summarized in this section as a convenience and are explained in more detail in the cross-referenced documentation, where applicable. This section will expand or change as needed with new releases of Red Hat Decision Manager. Define the property and value of pattern constraints from left to right In DRL pattern constraints, ensure that the fact property name is on the left side of the operator and that the value (constant or a variable) is on the right side. The property name must always be the key in the index and not the value. For example, write Person( firstName == "John" ) instead of Person( "John" == firstName ) . Defining the constraint property and value from right to left can hinder decision engine performance. For more information about DRL patterns and constraints, see Section 16.8, "Rule conditions in DRL (WHEN)" . Use equality operators more than other operator types in pattern constraints when possible Although the decision engine supports many DRL operator types that you can use to define your business rule logic, the equality operator == is evaluated most efficiently by the decision engine. Whenever practical, use this operator instead of other operator types. For example, the pattern Person( firstName == "John" ) is evaluated more efficiently than Person( firstName != "OtherName" ) . In some cases, using only equality operators might be impractical, so consider all of your business logic needs and options as you use DRL operators. List the most restrictive rule conditions first For rules with multiple conditions, list the conditions from most to least restrictive so that the decision engine can avoid assessing the entire set of conditions if the more restrictive conditions are not met. For example, the following conditions are part of a travel-booking rule that applies a discount to travelers who book both a flight and a hotel together. In this scenario, customers rarely book hotels with flights to receive this discount, so the hotel condition is rarely met and the rule is rarely executed. Therefore, the first condition ordering is more efficient because it prevents the decision engine from evaluating the flight condition frequently and unnecessarily when the hotel condition is not met. Preferred condition order: hotel and flight Inefficient condition order: flight and hotel For more information about DRL patterns and constraints, see Section 16.8, "Rule conditions in DRL (WHEN)" . Avoid iterating over large collections of objects with excessive from clauses Avoid using the from condition element in DRL rules to iterate over large collections of objects, as shown in the following example: Example conditions with from clause In such cases, the decision engine iterates over the large graph every time the rule condition is evaluated and impedes rule evaluation. Alternatively, instead of adding an object with a large graph that the decision engine must iterate over frequently, add the collection directly to the KIE session and then join the collection in the condition, as shown in the following example: Example conditions without from clause In this example, the decision engine iterates over the list only one time and can evaluate rules more efficiently. For more information about the from element or other DRL condition elements, see Section 16.8.7, "Supported rule condition elements in DRL (keywords)" . Use decision engine event listeners instead of System.out.println statements in rules for debug logging You can use System.out.println statements in your rule actions for debug logging and console output, but doing this for many rules can impede rule evaluation. As a more efficient alternative, use the built-in decision engine event listeners when possible. If these listeners do not meet your requirements, use a system logging utility supported by the decision engine, such as Logback, Apache Commons Logging, or Apache Log4j. For more information about supported decision engine event listeners and logging utilities, see Decision engine in Red Hat Decision Manager . Use the drools-metric module to identify the obstruction in your rules You can use the drools-metric module to identify slow rules especially when you process many rules. The drools-metric module can also assist in analyzing the decision engine performance. Note that the drools-metric module is not for production environment use. However, you can perform the analysis in your test environment. To analyze the decision engine performance using drools-metric , first add drools-metric to your project dependencies: Example project dependency for drools-metric <dependency> <groupId>org.drools</groupId> <artifactId>drools-metric</artifactId> </dependency> If you want to use drools-metric to enable trace logging, configure a logger for org.drools.metric.util.MetricLogUtils as shown in the following example: Example logback.xml configuration file <configuration> <logger name="org.drools.metric.util.MetricLogUtils" level="trace"/> ... <configuration> Alternatively, you can use drools-metric to expose the data using Micrometer . To expose the data, enable the Micrometer registry of your choice as shown in the following example: Example project dependency for Micrometer <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-jmx</artifactId> <!-- Discover more registries at micrometer.io. --> </dependency> Example Java code for Micrometer Metrics.addRegitry(new JmxMeterRegistry(s -> null, Clock.SYSTEM)); Regardless of whether you want to use logging or Micrometer, you need to enable MetricLogUtils by setting the system property drools.metric.logger.enabled to true . Optionally, you can change the microseconds threshold of metric reporting by setting the drools.metric.logger.threshold system property. Note Only node executions exceeding the threshold are reported. The default value is 500 . After configuring the drools-metric to use logging, rule execution produces logs as shown in the following example: Example rule execution output This example includes the following key parameters: evalCount is the number of constraint evaluations against inserted facts during the node execution. When evalCount is used with Micrometer, a counter with the data is called org.drools.metric.evaluation.count . elapsedMicro is the elapsed time of the node execution in microseconds. When elapsedMicro is used with Micrometer, look for a timer called org.drools.metric.elapsed.time . If you find an outstanding evalCount or elapsedMicro log, correlate the node name with ReteDumper.dumpAssociatedRulesRete() output to identify the rule associated with the node. Example ReteDumper usage ReteDumper.dumpAssociatedRulesRete(kbase); Example ReteDumper output

Commands:
when USDh:hotel() // Rarely booked USDf:flight()
when USDf:flight() USDh:hotel() // Rarely booked
when USDc: Company() USDe : Employee ( salary > 100000.00) from USDc.employees
when USDc: Company(); Employee (salary > 100000.00, company == USDc)
<dependency> <groupId>org.drools</groupId> <artifactId>drools-metric</artifactId> </dependency>
<configuration> <logger name="org.drools.metric.util.MetricLogUtils" level="trace"/> <configuration>
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-jmx</artifactId> <!-- Discover more registries at micrometer.io. --> </dependency>
Metrics.addRegitry(new JmxMeterRegistry(s -> null, Clock.SYSTEM));
TRACE [JoinNode(6) - [ClassObjectType class=com.sample.Order]], evalCount:1000, elapsedMicro:5962 TRACE [JoinNode(7) - [ClassObjectType class=com.sample.Order]], evalCount:100000, elapsedMicro:95553 TRACE [ AccumulateNode(8) ], evalCount:4999500, elapsedMicro:2172836 TRACE [EvalConditionNode(9)]: cond=com.sample.Rule_Collect_expensive_orders_combination930932360Eval1Invoker@ee2a6922], evalCount:49500, elapsedMicro:18787
ReteDumper.dumpAssociatedRulesRete(kbase);
[ AccumulateNode(8) ] : [Collect expensive orders combination]