[jboss-svn-commits] JBL Code SVN: r13708 - labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Language.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Sun Jul 22 11:32:07 EDT 2007


Author: tirelli
Date: 2007-07-22 11:32:06 -0400 (Sun, 22 Jul 2007)
New Revision: 13708

Modified:
   labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Language/Section-Advanced-CEs.xml
Log:
Adding documentation for accumulate functions and forall

Modified: labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Language/Section-Advanced-CEs.xml
===================================================================
--- labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Language/Section-Advanced-CEs.xml	2007-07-22 14:02:36 UTC (rev 13707)
+++ labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Language/Section-Advanced-CEs.xml	2007-07-22 15:32:06 UTC (rev 13708)
@@ -13,7 +13,7 @@
 
   <itemizedlist>
     <listitem>
-      <para>from </para>
+      <para>from</para>
     </listitem>
 
     <listitem>
@@ -21,7 +21,7 @@
     </listitem>
 
     <listitem>
-      <para>accumulate </para>
+      <para>accumulate</para>
     </listitem>
 
     <listitem>
@@ -47,7 +47,7 @@
     elements.</para>
 
     <para>Here is a simple example of reasoning and binding on another pattern
-    sub-field: </para>
+    sub-field:</para>
 
     <para><programlisting>rule "validate zipcode"
 when
@@ -60,7 +60,7 @@
 
     <para>With all the flexibility from the new expressiveness in the Drools
     engine you can slice and dice this problem many ways. This is the same but
-    shows how you can use a graph notation with the 'from': </para>
+    shows how you can use a graph notation with the 'from':</para>
 
     <para><programlisting>rule "validate zipcode"
 when
@@ -93,7 +93,7 @@
 
     <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>
+    each result in turn:</para>
   </section>
 
   <section>
@@ -289,10 +289,10 @@
       <title>Accumulate Functions</title>
 
       <para>The accumulate CE is a very powerful CE, but it gets real
-      declarative and easy to use when we use predefined functions that are
+      declarative and easy to use when using predefined functions that are
       known as Accumulate Functions. They work exactly like accumulate, but
       instead of explicitly writing custom code in every accumulate CE, the
-      user can use predefined code for common operations. </para>
+      user can use predefined code for common operations.</para>
 
       <para>For instance, the rule to apply discount on orders written in the
       previous section, could be written in the following way, using
@@ -311,6 +311,222 @@
 
       <para>In the above example, sum is an AccumulateFunction and will sum
       the $value of all OrderItems and return the result.</para>
+
+      <para>Drools 4.0 ships with the following built in accumulate
+      functions:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>average</para>
+        </listitem>
+
+        <listitem>
+          <para>min</para>
+        </listitem>
+
+        <listitem>
+          <para>max</para>
+        </listitem>
+
+        <listitem>
+          <para>count</para>
+        </listitem>
+
+        <listitem>
+          <para>sum</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>These common functions accept any expression as input. For
+      instance, if someone wants to calculate the average profit on all items
+      of an order, a rule could be written using the average function:</para>
+
+      <programlisting>rule "Average profit"
+when
+    $order : Order()
+    $profit : Number() 
+              from accumulate( OrderItem( order == $order, $cost : cost, $price : price )
+                               average( 1 - $cost / $price ) )
+then
+    # average profit for $order is $profit
+end
+</programlisting>
+
+      <para>Accumulate Functions are all pluggable. That means that if needed,
+      custom, domain specific functions can easily be added to the engine and
+      rules can start to use them without any restrictions. To implement a new
+      Accumulate Functions all one needs to do is to create a java class that
+      implements the org.drools.base.acumulators.AccumulateFunction interface
+      and add a line to the configuration file or set a system property to let
+      the engine know about the new function. As an example of an Accumulate
+      Function implementation, the following is the implementation of the
+      "average" function:</para>
+
+      <programlisting>/*
+ * Copyright 2007 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Created on Jun 21, 2007
+ */
+package org.drools.base.accumulators;
+
+
+/**
+ * An implementation of an accumulator capable of calculating average values
+ * 
+ * @author etirelli
+ *
+ */
+public class AverageAccumulateFunction implements AccumulateFunction {
+
+    protected static class AverageData {
+        public int    count = 0;
+        public double total = 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#createContext()
+     */
+    public Object createContext() {
+        return new AverageData();
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#init(java.lang.Object)
+     */
+    public void init(Object context) throws Exception {
+        AverageData data = (AverageData) context;
+        data.count = 0;
+        data.total = 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#accumulate(java.lang.Object, java.lang.Object)
+     */
+    public void accumulate(Object context,
+                           Object value) {
+        AverageData data = (AverageData) context;
+        data.count++;
+        data.total += ((Number) value).doubleValue();
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#reverse(java.lang.Object, java.lang.Object)
+     */
+    public void reverse(Object context,
+                        Object value) throws Exception {
+        AverageData data = (AverageData) context;
+        data.count--;
+        data.total -= ((Number) value).doubleValue();
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#getResult(java.lang.Object)
+     */
+    public Object getResult(Object context) throws Exception {
+        AverageData data = (AverageData) context;
+        return new Double( data.count == 0 ? 0 : data.total / data.count );
+    }
+
+    /* (non-Javadoc)
+     * @see org.drools.base.accumulators.AccumulateFunction#supportsReverse()
+     */
+    public boolean supportsReverse() {
+        return true;
+    }
+
+}
+</programlisting>
+
+      <para>The code for the function is very simple, as we could expect, as
+      all the "dirty" integration work is done by the engine. Finally, to plug
+      the function into the engine, we added it to the configuration
+      file:</para>
+
+      <programlisting>drools.accumulate.function.average = org.drools.base.accumulators.AverageAccumulateFunction
+</programlisting>
+
+      <para>Where "drools.accumulate.function." is a prefix that must always
+      be used, "average" is how the function will be used in the rule file,
+      and "org.drools.base.accumulators.AverageAccumulateFunction" is the
+      fully qualified name of the class that implements the function
+      behavior.</para>
     </section>
   </section>
+
+  <section>
+    <title>Forall</title>
+
+    <para><emphasis role="bold">Forall</emphasis> is the Conditional Element
+    that completes the First Order Logic support in Drools. The syntax is very
+    simple: </para>
+
+    <programlisting>forall( <replaceable>&lt;select pattern&gt;</replaceable> <replaceable>&lt;constraint patterns&gt;</replaceable> )</programlisting>
+
+    <para>The <emphasis role="bold">forall</emphasis> Conditional Element will
+    evaluate to true when all facts that match the <replaceable>&lt;select
+    pattern&gt;</replaceable> match all the <replaceable>&lt;constraint
+    patterns&gt;</replaceable>. Example:</para>
+
+    <programlisting>rule "All english buses are red"
+when
+    forall( $bus : Bus( type == 'english') 
+                   Bus( this == $bus, color = 'red' ) )
+then
+    # all english buses are red
+end
+</programlisting>
+
+    <para>In the above rule, we "select" all Bus object whose type is
+    "english". Then, for each fact that matchs this pattern we evaluate the
+    following patterns and if they match, the forall CE will evaluate to true.
+    Another example:</para>
+
+    <programlisting>rule "all employees have health and dental care programs"
+when
+    forall( $emp : Employee()
+            HealthCare( employee == $emp )
+            DentalCare( employee == $emp )
+          )
+then
+    # all employees have health and dental care
+end
+</programlisting>
+
+    <para>Forall can be nested inside other CEs for complete expressiveness.
+    For instance, <emphasis role="bold">forall</emphasis> can be used inside a
+    <emphasis role="bold">not</emphasis> CE:</para>
+
+    <programlisting>rule "not all employees have health and dental care"
+when 
+    not forall( $emp : Employee()
+                HealthCare( employee == $emp )
+                DentalCare( employee == $emp )
+              )
+then
+    # not all employees have health and dental care
+end
+</programlisting>
+
+    <para>As a side note, forall Conditional Element is equivalent to
+    writing:</para>
+
+    <programlisting>not( <replaceable>&lt;select pattern&gt;</replaceable> and not ( and <replaceable>&lt;constraint patterns&gt;</replaceable> ) )</programlisting>
+
+    <para>Also, it is important to note that <emphasis role="bold">forall is a
+    scope delimiter</emphasis>, so it can use any previously bound variable,
+    but no variable bound inside it will be available to use outside of
+    it.</para>
+  </section>
 </section>
\ No newline at end of file




More information about the jboss-svn-commits mailing list