The OpenRulesTM Tutorials            Home PREV TOP NEXT Decision tables
Divider

Using Natural Language Expressions Inside OpenRules Tables

This document will explain how rules could be expressed in plain English in OpenRules decision tables.  The concrete examples will be shown to demonstrate the use of natural language expressions to define different rules.  We will take a relatively complex decision table and will show how to use predefined OpenRules types such as FromToInt, CompareInt, and DomainString to simplify this table for a business user.  While simplicity is always a matter of taste, the actual objective is to demonstrate the use of natural language inside OpenRules tables.

Basic Example

Using FROM-TO Intervals

Comparing Integer and Real Numbers

Representing String Domains

Representing Domains of Numbers

Using Java Expressions

Expanding and Customizing Predefined Types

Performance Considerations

Basic Example  ►top

We will use a decision table "DebtResearchRules" from the sample rule project "Loan1" included into the standard OpenRules installation.  Here is the default representation of the debt research rules:

Rules void DebtResearchRules(LoanRequest loan, Customer c)
C1 C2 C3 C4 C5 C6 C7 A1
c.mortgageHolder.equals(YN) c.outsideCreditScore>min &&
c.outsideCreditScore<=max
c.loanHolder.equals(YN) op.compare(c.creditCardBalance,value) op.compare(c.educationLoanBalance,value) contains(rates,c.internalCreditRating) c.internalAnalystOpinion.equals(level) loan.debtResearchResult = level;
out("Debt Research Result:"+level);
String YN int min int max String YN Operator op int value Operator op int value String[] rates String level String level
IF
Mortgage Holder
AND
Outside Credit Score
AND
Loan Holder
AND
Credit Card Balance
AND
Education Loan Balance
AND
Internal Credit Rating
AND
Internal Analyst Opinion
THEN
Debt Research Recommendations
Min Max Oper Value Oper Value
Yes                           High
No 100 550                       High
No 550 900 Yes <= 0                 Mid
No 550 900 Yes > 0 > 0             High
No 550 900 Yes > 0 <= 0 A B C       High
No 550 900 Yes > 0 <= 0 D F         Mid
No 550 900 No > 0                 Low
No 550 900 No <= 0 <= 0             Low
No 550 900 No <= 0 > 0 D F         High
No 550 900 No <= 0 > 0 A B C       Low
                          High High
                          Mid Mid
                          Low Low
                             

We are going to modify conditions C2, C4, C5, and C6 by using different OpenRules representation options.

Using FROM-TO Intervals  ►top

The condition C2 above represents the fact that customers's outside credit score should be between min and max. To be exact, the condition is presented as the following Java snippet:

    c.outsideCreditScore>min && c.outsideCreditScore<=max

where min and max are parameters defined in two different sub-columns of the column C2.  Note that the comparison logic is hard-coded inside implementation: c.outsideCreditScore is strictly greater than min and less than or equals to max. We may easily switch to only one column and allow a business user him/herself to define the comparison logic for each particular rule using any reasonable representation of an interval min-max.  Here is an example of the properly modified condition C2:

C2
interval.contains(c.outsideCreditScore)
FromToInt interval
AND
Outside Credit Score
 
(100;550]
more than 550 and less or equal to 900
greater than 550 but less 901
551 - 900
551-900
551-900
551-900
from 551 to 900
between 551 and 900

Instead of two integer parameters min and max we are using one parameter interval of the predefined type FromToInt.  This allows us to use different texts inside rule cells to represent actual conditions.  Hopefully, this representation is intuitive enough.  However, we have to remember that natural language is not exact, and we have to make some assumptions.  For example, if it is commonly known that the interval (100;550] means 100 < c.outsideCreditScore <= 550.  Yet, in such expressions as "100-550" or "from 100 to 550" OpenRules assumes that both bounds 100 and 550 are included:  100 <= c.outsideCreditScore <= 550. 

You also may use many other ways to represent an interval of integers by specifying their two bounds or sometimes only one bound.  Here are some examples of valid integer intervals:

Cell Expression Comment

5

 equals to 5

[5,10]

 contains 5, 6, 7, 8, 9, and 10

5;10

 contains 5, 6, 7, 8, 9, and 10

[5,10)

 contains 5 but not 10

5 - 10

 contains 5 and 10

5-10

 contains 5 and 10

5- 10

 contains 5 and 10

-5 - 20

 contains -5 and 20

-5 - -20

 error: left bound is greater than the right one

-5 - -2

 contains -5 , -4, -3, -2

from 5 to 20

 contains 5 and 20

less 5

 does not contain 5

less than 5

 does not contain 5

less or equals 5

 contains 5

less or equal 5

 contains 5

less or equals to 5

 contains 5

smaller than 5

 does not contain 5

more 10

 does not contain 10

more than 10

 does not contain 10

10+

 more than 10

>10

 does not contain 10

>=10

 contains 10

between 5 and 10

 contains 5 and 10

no less than 10

 contains 10

no more than 5

 contains 5

equals to 5

 equals to 5

greater or equal than 5 and less than 10

 contains 5 but not 10

more than 5 less or equal than 10

 does not contain 5 and contains 10

more than 5,111,111 and less or equal than 10,222,222

 does not contain 5,111,111 and contains 10,222,222

[5'000;10'000'000)

 contains 5,000 but not 10,000,000

[5,000;10,000,000)

 contains 5,000 but not 10,000,000

(5;100,000,000]

 contains 5,000 and 10,000,000

You may use many other ways to represent integer intervals as you usually do in plain English.  The only limitation is the following: min should always go before max!

Similarly to integer intervals, one may use the predefined type FromToDouble to represent intervals of real numbers.  The bounds of double intervals could be integer or real numbers such as [2.7; 3.14).

Comparing Integer and Real Numbers  ►top

Now we will replace conditions C4 and C5 of the original decision table.   The condition C4 above represents the fact that customers's credit card balance should be less or strictly less that a certain value. The basic implementation uses two sub-columns: one for a comparison operator and another one for a value, with which c.creditCardBalance should be compared.  We may use only one column and allow a business user to define any comparison operator together with a value inside the same cell.  Here is an example of the properly modified condition C4:

C4
value.compare( c.creditCardBalance)
CompareToInt value
AND
Credit Card Balance
 
 
<= 0
>0
> 0
>0
>0
<=0
<=0
<=0

Here we use the predefined type CompareToInt that is a simplified version of FromToInt. Comparison operators should go before a comparison value.  Examples of acceptable operators:

Cell Expression Comment
<= 5 less or equals to 5
< 5 strictly less than 5
> 5 strictly more than 5
>= 5 more or equals to 5
!= not equal to 5
5 equals to 5.
Note that absence of a comparison operator means equality. You cannot use an explicit operator "=" (not to be confused with Excel's formulas).

Similarly to CompareToInt  one may use the predefined type CompareToDouble to represent comparisons with real numbers.  The comparison values may be presented as integer or real numbers, e.g. "<= 25.4" and "> 0.5".

The modified decision table with corrected conditions C2, C4, and C5 will look like:

Rules void DebtResearchRules(LoanRequest loan, Customer c)
C1 C2 C3 C4 C5 C6 C7 A1
c.mortgageHolder.equals(YN) interval.contains(c.outsideCreditScore) c.loanHolder.equals(YN) value.compare( c.creditCardBalance) value.compare(c.educationLoanBalance) contains(rates,c.internalCreditRating) c.internalAnalystOpinion.equals(level) loan.debtResearchResult = level;
out("Debt Research Result:"+level);
String YN FromToInt interval String YN CompareToInt value CompareToInt value String[] rates String level String level
IF
Mortgage Holder
AND
Outside Credit Score
AND
Loan Holder
AND
Credit Card Balance
AND
Education Loan Balance
AND
Internal Credit Rating
AND
Internal Analyst Opinion
THEN
Debt Research Recommendations
Yes                     High
No (100;550]                   High
No more than 550 and less or equal to 900 Yes <= 0               Mid
No greater than 550 but less 901 Yes >0 >0             High
No 551 - 900 Yes > 0 <= 0 A B C       High
No 551-900 Yes >0 <=0 D F         Mid
No 551-900 No >0               Low
No 551-900 No <=0 <= 0             Low
No from 551 to 900 No <=0 >0 D F         High
No between 551 and 900 No <=0 >0 A B C       Low
                    High High
                    Mid Mid
                    Low Low
  901+                   ?

Representing String Domains  ►top

Now let's look at condition C6. It states that customer's internal credit score should be one of several acceptable rates such as "A B C" and "D F".  To avoid a necessity to create multiple sub-columns for similar conditions, we may put all possible string values inside the same cell and separate them by space or commas.   Here is an example of the properly modified condition C6:

C6
domain.contains(c.internalCreditRating)
DomainString domain
AND
Internal Credit Rating
 
 
 
 
A B C
D F
 
 
D F
A B C

Here we use the predefined type DomainString that defines a domain of strings (words) separated by whitespaces. The method "contains(String string)" of the class DomainString checks if the parameter "string" is forund among all strings listed in the current "domain". You also may use the method "containsIgnoreCase(String string)" that allows to ignore the case during the comparison.

If possible values may contain several words, one may use the predefined type DomainStringC where "C" indicates that commas will be used as a string separator.  For example, we may use DomainStringC to specify such domain as "Very Hot, Hot, Warm, Cold, Very Cold". 

The modified decision table with corrected conditions C2, C4, C5, and C6 will look like:

Rules void DebtResearchRules(LoanRequest loan, Customer c)
C1 C2 C3 C4 C5 C6 C7 A1
c.mortgageHolder.equals(YN) interval.contains(c.outsideCreditScore) c.loanHolder.equals(YN) value.compare(c.creditCardBalance) value.compare(c.educationLoanBalance) domain.contains(c.internalCreditRating) c.internalAnalystOpinion.equals(level) loan.debtResearchResult = level;
out("Debt Research Result:"+level);
String YN FromToInt interval String YN CompareToInt value CompareToInt value DomainString domain String level String level
IF
Mortgage Holder
AND
Outside Credit Score
AND
Loan Holder
AND
Credit Card Balance
AND
Education Loan Balance
AND
Internal Credit Rating
AND
Internal Analyst Opinion
THEN
Debt Research Recommendations
Yes             High
No (100;550]           High
No more than 550 and less or equal to 900 Yes <= 0       Mid
No greater than 550 but less 901 Yes >0 >0     High
No 551 - 900 Yes > 0 <= 0 A B C   High
No 551-900 Yes >0 <=0 D F   Mid
No 551-900 No >0       Low
No 551-900 No <=0 <= 0     Low
No from 551 to 900 No <=0 >0 D F   High
No between 551 and 900 No <=0 >0 A B C   Low
            High High
            Mid Mid
            Low Low
  >900           ?

 

Representing Domains of Numbers  ►top

If you need to represent domains of integer or double values, there are several predefined types similar to DomainString:

For example, here is a condition column with eligible loan terms:

C8
domain.contains(c.loanTerm)
DomainIntC domain
Eligible Loan Terms
24,36,72
36,72
72

 

Using Java Expressions  ►top

Instead of using any predefined types it is possible to use Java expressions placed directly inside decision table cells.  There are two ways to do it:

  1. Use curly brackets as in this example: {  c.creditCardBalance <= 0; }
  2. Use of ":=" indicator as in this example: := c.credirCardBalance > 0

The following is the condition C4 represented with Java expressions:

C4
truefalse
boolean truefalse
AND
Credit Card Balance
 
 
{ c.creditCardBalance <= 0; }
{ c.creditCardBalance >0; }
{ c.creditCardBalance > 0; }
{ c.creditCardBalance>0; }
:= c.creditCardBalance >0
{ c.creditCardBalance <= 0; }
{ c.creditCardBalance <=0; }
{ c.creditCardBalance <=0; }

Java expressions inside table cells are useful when you  have many completely different conditions and want to avoid creating too many columns.

Expanding and Customizing Predefined Types  ►top

All mentioned above predefined types are implemented in the Java package com.openrules.types.  You may get the source code of this package and expand and/or customize the proper classes.  In particular, for internationalization purposes you may translate the English key words to utilize in your national language.  You may change the default assumptions about inclusion/exclusion of bounds inside integer and real intervals.  You may add new types of intervals and domains.

Performance Considerations  ►top

The use of expressions inside OpenRules tables come with some price - mainly in the performance.  It is understandable because for every cell with an expression OpenRules will create a separate instance of the proper Java class during rules execution.  A slowdown in rules execution maybe essential especially for large decision tables.  A rules table representation provided in the basic example is probably the most efficient one.  However, having multiple representation options allows a  rules designer to find a reasonable compromise between performance and expressiveness.

►top

This document is located on the Web at http://openrules.com/docs/Tutotial.NL.htm.

_________________________________________________

© Copyright 2007, OpenRules, Inc. All rights reserved