[jboss-svn-commits] JBL Code SVN: r25346 - labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Language.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Thu Feb 19 09:46:01 EST 2009
Author: tirelli
Date: 2009-02-19 09:46:01 -0500 (Thu, 19 Feb 2009)
New Revision: 25346
Modified:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Language/Section-Rule.xml
Log:
Adding explanation on the interaction between 'from' and 'lock-on-active'. Contributed by Peter Samouelian
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Language/Section-Rule.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Language/Section-Rule.xml 2009-02-19 13:51:08 UTC (rev 25345)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Language/Section-Rule.xml 2009-02-19 14:46:01 UTC (rev 25346)
@@ -1487,6 +1487,182 @@
<para>The above example will cause the rule to fire once for each item
whose value is greater than 100 for each given order.</para>
+ <para>You must take caution, however, when using <emphasis
+ role="bold">from</emphasis>, especially in conjunction with the
+ <emphasis role="bold">lock-on-active</emphasis> rule attribute
+ as it may produce unexpected results. Consider the example provided earlier, but
+ now slightly modified as follows:</para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person( )
+ $a : Address( state == "NC") from $p.address
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person( )
+ $a : Address( city == "Raleigh") from $p.address
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>
+ In the above example, persons in Raleigh, NC should be assigned to sales region 1 and
+ receive a discount; i.e., you would expect both rules to activate and fire. Instead you
+ will find that only the second rule fires.</para>
+
+ <para>If you were to turn on the audit log, you would also see that when the second rule fires,
+ it deactivates the first rule. Since the rule attribute <emphasis role="bold">lock-on-active</emphasis>
+ prevents a rule from creating new activations when a set of facts change, the first rule fails to
+ reactivate. Though the set of facts have not changed, the use of
+ <emphasis role="bold">from</emphasis> returns a new fact for all intents and purposes each time
+ it is evaluated.
+ </para>
+
+ <para>First, it's important to review why you would use the above pattern. You may have
+ many rules across different rule-flow groups. When rules modify working memory and other rules
+ downstream of your RuleFlow (in different rule-flow groups) need to be reevaluated, the use of <emphasis role="bold">modify</emphasis>
+ is critical. You don't, however, want other rules in the same rule-flow group to place
+ activations on one another recursively. In this case, the <emphasis role="bold">no-loop</emphasis>
+ attribute is ineffective, as it would only prevent a rule from activating itself recursively. Hence,
+ you resort to <emphasis role="bold">lock-on-active</emphasis>.
+ </para>
+
+ <para>
+ There are several ways to address this issue:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Avoid the use of <emphasis role="bold">from</emphasis> when you can assert all facts into working memory
+ or use nested object references in your constraint expressions (shown below)</para>
+ </listitem>
+ <listitem>
+ <para>Place the variable assigned used in the modify block as the last sentence in your condition (LHS)</para>
+ </listitem>
+ <listitem>
+ <para>Avoid the use of <emphasis role="bold">lock-on-active</emphasis> when you can
+ explicitly manage how rules within the same rule-flow group place activations on one another
+ (explained below)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The preferred solution is to minimize use of <emphasis role="bold">from</emphasis>
+ when you can assert all your facts into working memory directly. In the example above,
+ both the Person and Address instance can be asserted into working memory. In this case, because
+ the graph is fairly simple, an even easier solution is to modify your rules as follows:
+ </para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person(address.state == "NC" )
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person(address.city == "Raleigh" )
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>Now, you will find that both rules fire as expected. However, it is not
+ always possible to access nested facts as above. Consider an example where a Person
+ holds one or more Addresses and you wish to use an existential quantifier to
+ match people with at least one address that meets certain conditions.
+ In this case, you would have to resort to
+ the use of <emphasis role="bold">from</emphasis> to reason over the collection.</para>
+
+ <para>
+ There are several ways to use <emphasis role="bold">from</emphasis>
+ to achieve this and not all of them exhibit an issue
+ with the use of <emphasis role="bold">lock-on-active</emphasis>. For example,
+ the following use of <emphasis role="bold">from</emphasis> causes both rules to fire as expected:
+ </para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person($addresses : addresses)
+ exists (Address(state == "NC") from $addresses)
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person($addresses : addresses)
+ exists (Address(city == "Raleigh") from $addresses)
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>However, the following slightly different approach does exhibit the problem:</para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test"
+lock-on-active true
+when
+ $assessment : Assessment()
+ $p : Person()
+ $addresses : List() from $p.addresses
+ exists (Address( state == "NC") from $addresses)
+then
+ modify ($assessment) {} #Modify assessment in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test"
+lock-on-active true
+when
+ $assessment : Assessment()
+ $p : Person()
+ $addresses : List() from $p.addresses
+ exists (Address( city == "Raleigh") from $addresses)
+then
+ modify ($assessment) {} #Modify assessment in a modify block
+end</programlisting></para>
+
+ <para>In the above example, the $addresses variable is returned from the
+ use of <emphasis role="bold">from</emphasis>. The example also introduces
+ a new object, assessment, to highlight one possible solution in this case.
+ If the $assessment variable assigned in the condition (LHS) is moved to the last condition
+ in each rule, both rules fire as expected.
+ </para>
+
+ <para>
+ Though the above examples demonstrate how to combine the use of <emphasis role="bold">from</emphasis>
+ with <emphasis role="bold">lock-on-active</emphasis> where no loss of rule activations occurs,
+ they carry the drawback of placing a dependency on the order of conditions on the LHS. In addition,
+ the solutions present greater complexity for the rule author in terms of keeping track of
+ which conditions may create issues.
+ </para>
+
+ <para>A better alternative is to
+ assert more facts into working memory. In this case, a person's addresses
+ may be asserted into working memory and the use of <emphasis role="bold">from</emphasis>
+ would not be necessary.</para>
+
+ <para>There are cases, however, where asserting all data into working memory is not
+ practical and we need to find other solutions. Another option is to reevaluate the
+ need for <emphasis role="bold">lock-on-active</emphasis>.
+ An alternative to <emphasis role="bold">lock-on-active</emphasis> is to
+ directly manage how rules within the same rule-flow group activate one another
+ by including conditions in each rule that prevent rules from activating each other recursively
+ when working memory is modified. For example, in the case above where a
+ discount is applied to citizens of Raleigh, a condition may be added to the rule
+ that checks whether the discount has already been applied. If so, the rule does not
+ activate.</para>
+
<para>The next example shows how we can reason over the results of a
hibernate query. The Restaurant pattern will reason over and bind with
each result in turn:</para>
More information about the jboss-svn-commits
mailing list