-
Notifications
You must be signed in to change notification settings - Fork 126
Frequently Asked Questions
1. Does RuleBook persist state between Rules?
Yes! State is transferred from one Rule to the next in a RuleBook using facts (objects of type NameValueReferrable). Facts, as their type implies, contain a name and a reference. If a fact is changed or added in a Rule then that change or addition is present for other Rules down the rule chain.
2. What is a Result? When would I need a RuleBook Result?
Put simply, a RuleBook Result is an object that refers to another object. Results are useful for RuleBooks that are expected to produce a single value (object) of a particular type. Since the current value of a RuleBook's Result is propagated to every Rule invoked in the RuleBook, each Rule can both view and manipulate the value of the RuleBook's Result.
3. Why do some RuleBooks have a Result and others don't?
Not every RuleBook needs a Result. Some RuleBooks might just perform actions or manipulate facts. That's why a RuleBook's Result is optional.
4. How does RuleBook chain Rules together?
Currently, the default (and only) RuleBook packaged with rulebook-core is CoRRuleBook. CoRRuleBook uses the Chain of Responsibility (CoR) pattern to chain Rules together in the order in which they are added to a RuleBook. A planned future update to RuleBook includes adding other algorithms. And of course, you can always create your own RuleBook with your own algorithm by implementing the RuleBook interface.
5. Does Chain of Responsibility Scale? How is it different from Rete?
Chain of Responsibility will scale to thousands of Rules and perhaps more. Just imagine trying to keep track of thousands of Rules.
Rete is a high performance matching algorithm. Rete may execute rules in any order where the rules available for execution meet the conditions necessary for their execution. It presumes that the ordering of rules is not relevant for their execution. For these reasons, Rete can scale well for computation at an increased memory cost. The caveat is that Rete requires that rules be written in a way that works best for Rete, which is not the most intuitive way to write rules. It also means that Rete is a very poor candidate for workflow and related applications.
Chain of Responsibility, on the other hand, favors simplicity and predictability over performance. That's not to say that Chain of Responsibility isn't fast or that it can't scale. But it does mean that with Chain of Responsibility, the order in which Rules are invoked is completely predictable, which makes it easy to learn and use. It also means that Chain of Responsibility can be used for workflow. The tradeoff is the maximum number of rules that should be added to the rule chain is in the thousands, instead of the millions, which is still more than sufficient for most applications.
6. How do I specify the order that Rules are invoked?
The default implementation (and currently the only packaged implementation) of RuleBook is CoRRuleBook, which chains Rules using the Chain of Responsibility pattern. Rules added using that implementation are invoked in the order in which they are added.
If you are using POJO rules, ordering can be specified in the @Rule annotation as follows:
@Rule(order = 1)
public class MyPojoRule { ...
A rule with an order = 1 will be invoked prior to a rule with an order = 2, and so on. Rules with the same order may be invoked in any sequence.
7. How can I break the Rule chain on the first Rule whose condition is met?
Using the RuleBook DSL, if the stop() method is used, then the Rule will break the rule chain if the following 2 conditions are met (1) the Rule's condition evaluates to true and (2) the Rule's action (i.e. then() functionality) executes successfully.
RuleBook ruleBook = RuleBookBuilder.create()
.addRule(
RuleBuilder.create()
.withFactType(String.class)
.when(facts -> true)
.then(someAction)
.stop() //signals that the rule should break the rule chain upon successful completion
.build())
.addRule(
RuleBuilder.create()
.withFactType(String.class)
.when(facts -> true)
.then(someOtherAction)
.build())
.build();
ruleBook.run(factMap);
In the above example, someAction will be invoked and then break the Rule chain. someOtherAction will never be invoked because the Rule chain would have been broken prior to executing the second Rule.
Similar functionality can be achieved using POJO rules as follows:
@Rule
public class MyPojoRule {
@When
public boolean when() {
return true; //the condition is true, so the @Then method will be called
}
@Then
public RuleState then() {
return RuleState.BREAK; //breaks the rule chain
}
}
8. Is RuleBook thread safe?
Yes! RuleBook is thread safe! This means that the same RuleBook can be run in different threads with different facts without conflicts. What's more is that RuleBook results are also partitioned on a per thread basis and there's support for thread pooling too. So, running the same RuleBook with different facts will produce a different different result for different threads without conflict.