Special nodes in the network

So far we have covered the basic types of nodes present in PHREAK that allow us to create simple rules in Drools. But there are some others nodes with very specific behaviors that are used for some conditional elements we haven't discussed so far. This section will analyze the most commonly used of these conditional elements: not, e xists, accumulate, and from.

The Not Node

The not conditional element is the non-existential quantifier in Drools that checks for the absence of one or more patterns in the working memory.

Drools provides a specialized version of a Beta Node to implement the necessary logic of the not conditional element.

As an example, let's use the following rule:

rule "Sample Rule 1"
when
    $c: Customer()
    not (SuspiciousOperation(customer == $c))
then
    channels["clean-customer-channel"].send($c);
end

This rule is activated when there is a Customer in the session without any SuspiciousOperation. With this example, we can tell that the not element must be some kind of Beta Node because it is actually performing a join operation between two patterns. But the join operation is not the one we have covered so far. For this particular node, the execution should only continue if the negated pattern is not present in the session:

The Not Node

In the generated network, the Not Node looks like a regular Beta Node, but we now know that its behavior is not. If we first insert a Customer fact in our session, the Not Node will have data in one if its inputs (Customer OTN) but not in the other (SuspiciousOperation OTN). In this case, the execution will continue to the next node in the path.

If, before a Customer, we first insert a SuspiciousOperation fact, when the Not Node is evaluated it will have data in both of its inputs; the execution will then be terminated. If we then retract our SuspiciousOperation from the session, the Not Node will now evaluate to true and the next node in the path will be executed.

Let's now consider a situation where we want a rule to be executed when we don't have any SuspiciousOperation in our session regardless of the Customer. This rule could be written as follows:

rule "Sample Rule 1"
when
    not (SuspiciousOperation())
then
    channels["audit-channel"].send("OK");
end

We mentioned before that the Not Node is a specialized type of Beta Node. We also know that Beta Nodes require two inputs. But, in this scenario, there is no other pattern in our rule we can join to the Not Node. How does Drools solve this situation? In the previous version of this rule, the Customer pattern triggered the evaluation of the Not Node. In other words, when a Customer was inserted, the corresponding OTN was evaluated and then the Not Node was. But now we don't have any fact that could trigger our node:

The Not Node

The answer to this problem is the InitialFactImpl fact. The InitialFactImpl fact is a special fact that is always present (but not always used) in a PHREAK network. Every time a new KIE Session is created, an InitialFactImpl is automatically inserted into it. This will allow patterns such as the not conditional element to be evaluated in situations such as the one we have described here.

The implication of the InitialFactImpl fact in our particular PHREAK network is that, as soon as a KIE Session is created from it, the Sampl e Rule 1 rule will be activated.

The Exists Node

The exists conditional element is used to test the presence of one or more patterns in the working memory. No matter how often this pattern is present, the exists conditional element will only be triggered once. Just like the not conditional event, exists is also implemented in Drools by a specialized version of a Beta Node: the Exists Node.

To demonstrate how this node is implemented in Drools, let's take the opposite of the rule we introduced in the previous section: a rule that is activated when a Customer has one or more SuspiciousOperations:

rule "Sample Rule 1"
when
    $c: Customer()
    exists SuspiciousOperation(customer == $c)
then
    channels["dirty-customer-channel"].send($c);
end

Without the exists conditional element, this rule will be individually activated for each of the SuspiciousOperations a Customer may have. With the use of the exists conditional element, we are telling Drools that we only want this rule to be activated at most once per Customer. The PHREAK network generated by the preceding rule looks exactly like the one we had when using the not conditional element. The difference here is in the behavior of the Exists Node compared to the Not Node:

The Exists Node

In this case, the Exists Node will keep track of the SuspiciousOperations facts and will only evaluate to true when it has at least one of them in the corresponding input. As soon as this input is empty, the Exists Node will evaluate to false.

It is also common in Drools to use an exists conditional element without any other pattern preceding it. For example, a rule that is activated when at least one SuspiciousOperations is present in our session could be written as follows:

rule "Sample Rule 1"
when
    exists SuspiciousOperation()
then
    channels["audit-channel"].send("FAIL");
end

In this case, like when we were using the not conditional element, we don't have any pattern (or node, in our PHREAK network) that causes the evaluation of our Exists Node. The solution here is similar to the one before: the InitialFactImpl fact.

The Exists Node

In this case, the InitialFactImpl fact is used as an aid: its corresponding input in the Exists Node will always contain a fact. This means that the only fact this node, in this particular situation, is interested in, is the SuspiciousOperation one.

The Accumulate Node

Another very useful conditional element in Drools is the accumulate element. This conditional element was introduced in Chapter 4, Improving Our Rule Syntax, as a way to execute accumulate functions over the facts in a KIE Session. In PHREAK, an accumulate conditional element is represented with a variation of a Beta Node, called an Accumulate Node. The Accumulate Node will execute the corresponding accumulate functions over the facts incoming from one of its inputs. After the functions are applied, the execution will always continue to the next node in the path.

To see how an accumulate conditional element is treated by Drools, let's analyze the following rule:

rule "Sample Rule 1"
when
    $c: Customer()
    accumulate( Order(customer == $c), $n: count(1))
then
    channels["audit-channel"].send($n);
end

Nothing new here. The rule is just counting all the Orders of each Customer we have in our session. Let's now see how the corresponding PHREAK network looks:

The Accumulate Node

The first thing to notice in the network is the new Accumulate Node. In our scenario, the Accumulate Node will apply the count function to each of the incoming Order facts. Then, a tuple containing the result of the accumulate function and each of the Customers present in the other input will be propagated to the next node.

Another important thing to notice is that the constraints in the Order pattern (customer == $c) are not part of the network itself. The Accumulate Node will internally resolve any constraint before executing the corresponding accumulate function.

When an accumulate conditional element is used before any other pattern in a rule, the InitialFactImpl fact is again used as an aid. For example, the following rule could be used to count all the Order facts in a session:

rule "Sample Rule 1"
when
    accumulate( Order(), $n: count(1))
then
    channels["audit-channel"].send($n);
end

In this case, the generated PHREAK network will look like the following one:

The Accumulate Node

Once again, the InitialFactImpl fact comes to the rescue of Beta Nodes without two explicit input nodes.

The From Node

Chapter 4, Improving Our Rule Syntax also introduced a way to reason about objects that are not facts in our session through the use of the from conditional element. Because the PHREAK network is all about the evaluation of actual facts in a session, the implementation of the from conditional element in Drools is a bit obscure: the conditional element is represented in the PHREAK network as a single node, where both its right-hand side and left-hand side are executed and evaluated.

To illustrate how a from conditional element is represented in PHREAK, let's consider the following rule:

rule "Sample Rule 1"
when
    $o: Order()
    $ol: OrderLine(
item.category == Category.HIGH_RANGE,
quantity > 10) from $o.getOrderLines()
then
    channels["audit-channel"].send($ol);
end

The preceding rule is activated for each OrderLine in an Order fact containing more than 10 High Range items. In this case, the OrderLines themselves are not facts in the session: they are taken from each Order using a from conditional event. Now that we know how patterns and their constraints are represented in PHREAK, we would expect the generated network for this example to contain an OrderLine OTN followed by two Alpha Nodes: one for the category constraint and another for the quantity constraint:

The From Node

To our surprise, the entire left-hand side of the from conditional element was not translated into PHREAK nodes. As mentioned before, the truth is that the OrderLines we are evaluating in our rule are not facts; that is why the evaluation path is not represented in PHREAK. When the From Node is executed in the preceding network, the right-hand side will be executed and the pattern on the left-hand side evaluated for each of the resulting objects.

Now that we have some understanding of how Drools evaluates the rules in our knowledge bases, let's move to another topic that was not covered so far in this book: backward-chaining reasoning.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.74.25