Nested "If-else" statements in CodeEffects rule - rule-engine

I am using CodeEffects rule editor for writing business rules in our application. I have many if-else conditions which are actually nested-if type rules. With no support of nested-if, I need to re-write all if conditions every time.
But I can't find any way to write rule as mentioned below.
if (Condition1)
(
if (sub-condition1)( ....)
else if (....)
)
else
(
....
)

The best way to substitute nested IFs is to use the same sub-conditions multiple times:
if condition1 and sub-condition1 then DoOneThing
else if sub-condition1 then DoAnotherThing
else DoSomethingElse
It's not perfect but it'll do.

Related

Drools rule is running then clause multiply times

I have just started learning Drools and have written the following rule
rule "matematikk"
when
class( code == "MAT1003") or class( code == "MAT1008")
or
class( code == "REA3022") or class( code == "REA3024") or class( code == "REA3026") or class( code == "REA3028")
or
class(code == "MAT1006") and class(code == "MAT1010") or class( code == "MAT1001") and class( code == "MAT1005")
or
class(code == "MAT1002") or class(code == "MAT1007")
then
logger.info("passed");
end
when I run this rule I will get three passed prints in the terminal? which is correct since only three of the line are true, but how do I make it process the entire "when" block and after that go to the "then" section.
cheers,
ehsan
also if I remove the "or" between the lines I won't get any results.
Your rule doesn't really make sense. You've got "ands" and "ors" mixed up in here in no particular order. Setting things on separate lines doesn't create any sort of "grouping". Proximity similarly doesn't provide any sort of inherent relationship. The "and"s on the third 'line' are particularly confusing -- I have no idea what they're supposed to be and-ing.
Generally, if you want to represent an "or" condition, you'd write the conditional like this:
class( code in ("MAT1003", "MAT1008", ... ))
(Where "..." represents additional values.)
This is read as "There is a 'class' that has code MAT1003 or MAT1008."
For an "and" you'd simply have two different statements; only if both match will the rule be 'triggered'. For example:
exists(class(code == "MAT1006"))
exists(class(code == "MAT1010"))
This would trigger if there are at least 2 "class" instances in working memory, and there is at least one with code MAT1006 and at least one with code MAT1010.
I used exists because you don't actually need a reference to the matching instance for use in the right hand side; I also presumed you only need to trigger once regardless of how many instances matched your condition.
Finally -- I strongly suggest not naming your class "class" since it's a reserved word in Java. If it is representing some sort of educational class (eg at university), may I suggest calling it Course instead?

Accumulate/Collect vs single java loop

I have a use case in which let's say I have 100,000 pojos in the kiesession of type A and I want to apply some rules on it out of which two are -
Check is a duplicate value of type A exist.
sum of A.someInt is equal to the givenValue.
class A {
private int someInt;
private String someString;
}
For these two rules should I go with creating separate rules for them in drools like this
$sumSomeInt: Integer(this > 90) from accumulate(A( $SomeInt: someInt ), sum($SomeInt))
function boolean checkDuplicate(List input) {
int a = input.size();
int b = ((List) input.stream().distinct().collect(Collectors.toList())).size();
return a!=b;
}
dialect "java"
rule "ADuplicateRule"
when
$input : List( ) from collect(A())
eval(checkDuplicate($input))
then
throw new Exception("A list has duplicate values");
end
Or is it better to apply this in java using a single loop for this and doing both the things what I want to know is will applying these two approaches on 100k records give us a major performance difference
just a reminder I also have other rules so I have to use drools I don't want to apply some validation in java and some in drools unless there is a major performance boost
Drools optimizes the "when" clause. The "then", which is pure Java, is not optimized and is executed "as-is". eval statements are not optimized either and are bad practice and should be avoided at all costs. Just about anything you can do in an 'eval', you can do in a Drools native fashion.
Given the choice, in the "when", of doing something in Java via an eval, and doing something using Drools built-in structures and methods, always prefer doing it the Drools native way. 100k records isn't very many so it probably won't be noticeable at such a scale.
And you shouldn't be throwing exceptions -- that's also not a good practice. retract your inputs or something to force execution to terminate early.
I shared a better way of doing duplicate detection in your other question.

Drools condition for when fact exists or does not exist

I'm trying to set up a drools rule that would achieve something like this:
rule "Rule 1"
salience 100
activation-group "..."
when
$fact: Fact exists, or fact does not exist
then
if $fact exists then do X. Else, do Y.
I know I can do this by having two different rules, one for when the fact exists, and one for when the fact does not exist. Is there any way I can combine these conditions into one? For the when statement, I have tried:
$fact: Fact() || not Fact()
which didn't work. Is there a correct way to write the "when" statement in drools?
If we revert to boolean logic, A || !A is the same as true so you can omit the condition entirely.
You're already doing this correctly. Rule 1: if X exists, then do A(). Rule 2: if X does not exist, then do B(). That is the correct way to do things:
rule "Fact exists"
when
exists(Fact())
then
doX()
end
rule "Fact does not exist"
when
not(Fact())
then
doY()
end
That's good rule design and how you should do this. I can't think of a good reason to compress it into one rule. If you can clarify a legitimate use case for why you'd want to collapse it into a single rule, it might be possible to give a better or more concrete response.
You may be able to abuse conditional and named consequences for this, though it's definitely not designed for this (nor recommended.)

How to use Drools backward chaining to list what initial facts are needed to satisfy a goal?

I'm trying to use Drools backward chaining to find out which facts are needed to get an object inserted in the working memory.
In the following example, I expect to get the fact "go2".
rule "ins a"
when
String( this == "go2" )
then
insert(new A());
end
rule "Run"
when
then
insert(new String("go1"));
end
rule "Test isThereAnyA"
when
String( this == "go1" )
isThereAnyA(a;)
then
System.out.println( "you can get " + a );
end
query isThereAnyA (A a)
a := A()
end
I've been looking at examples in the official documentation
http://docs.jboss.org/drools/release/6.1.0.Final/drools-docs/html_single/index.html#d0e21289
but they show a different situation (the rules in those examples doesn't creates new fact)
From the chart
http://docs.jboss.org/drools/release/6.1.0.Final/drools-docs/html_single/index.html#d0e21240
I think it should work but I haven't found a way to specify a query that gives me the expected results.
Thank you in advance.
Short answer:
Unfortunately backward chaining can not be used for this purpose.
It will not give you "go2" in this case.
Long answer:
In Drools, Backward chaining (BC) is a way to query the WM in a goal-driven fashion, not a way to trace back the derivation graph of a normal forward chaining inference process.
BC allows rule "Test" to retrieve As through the query "isThereAnyA", and possibly invoke other queries, but will not allow to find the "production" link between "A" and "go2". The reason is that "when..then..insert.." does not create any link between the triggering facts and the asserted conclusion, and backward chaining will not change it.
What you could do with BC is this:
query isThereAnyA_InPresenceOfA_String( A a )
isThereAnyString( $s ; )
a := A()
end
query isThereAnyString( String $s )
$s := String( this == "go2" )
end
This will pick up As only if a String "go2" is (still) present. However you'll notice that the connection between a particular instance of A and a the particular String which led to its assertion is still missing.
To know exactly which objects led to the assertion of another object you may need a different approach. Options include:
make the connection explicit : new A( $s ) // $s bound to "go2"
use "insertLogical" to establish a dependency between "go2" and A, then query the TruthMaintenanceSystem
The TMS-based one would be my tentative choice, but it also depends on your exact requirements.
This use case is common, there may be other options, including a few which are experimental as they are being developed in 6.3, but I'd rather ask a few questions first.
That is: when do you need exactly to discover the facts - during the execution of the rules, or "offline"? Is it purely for auditing purposes, or does it impact your business logic? Can you have multiple rules asserting the "same" object?
Hope this helps
Davide

Methods of simplifying ugly nested if-else trees in C#

Sometimes I'm writing ugly if-else statements in C# 3.5; I'm aware of some different approaches to simplifying that with table-driven development, class hierarchy, anonimous methods and some more.
The problem is that alternatives are still less wide-spread than writing traditional ugly if-else statements because there is no convention for that.
What depth of nested if-else is normal for C# 3.5? What methods do you expect to see instead of nested if-else the first? the second?
if i have ten input parameters with 3 states in each, i should map functions to combination of each state of each parameter (really less, because not all the states are valid, but sometimes still a lot). I can express these states as a hashtable key and a handler (lambda) which will be called if key matches.
It is still mix of table-driven, data-driven dev. ideas and pattern matching.
what i'm looking for is extending for C# such approaches as this for scripting (C# 3.5 is rather like scripting)
http://blogs.msdn.com/ericlippert/archive/2004/02/24/79292.aspx
Good question. "Conditional Complexity" is a code smell. Polymorphism is your friend.
Conditional logic is innocent in its infancy, when it’s simple to understand and contained within a
few lines of code. Unfortunately, it rarely ages well. You implement several new features and
suddenly your conditional logic becomes complicated and expansive. [Joshua Kerevsky: Refactoring to Patterns]
One of the simplest things you can do to avoid nested if blocks is to learn to use Guard Clauses.
double getPayAmount() {
if (_isDead) return deadAmount();
if (_isSeparated) return separatedAmount();
if (_isRetired) return retiredAmount();
return normalPayAmount();
};
The other thing I have found simplifies things pretty well, and which makes your code self-documenting, is Consolidating conditionals.
double disabilityAmount() {
if (isNotEligableForDisability()) return 0;
// compute the disability amount
Other valuable refactoring techniques associated with conditional expressions include Decompose Conditional, Replace Conditional with Visitor, Specification Pattern, and Reverse Conditional.
There are very old "formalisms" for trying to encapsulate extremely complex expressions that evaluate many possibly independent variables, for example, "decision tables" :
http://en.wikipedia.org/wiki/Decision_table
But, I'll join in the choir here to second the ideas mentioned of judicious use of the ternary operator if possible, identifying the most unlikely conditions which if met allow you to terminate the rest of the evaluation by excluding them first, and add ... the reverse of that ... trying to factor out the most probable conditions and states that can allow you to proceed without testing of the "fringe" cases.
The suggestion by Miriam (above) is fascinating, even elegant, as "conceptual art;" and I am actually going to try it out, trying to "bracket" my suspicion that it will lead to code that is harder to maintain.
My pragmatic side says there is no "one size fits all" answer here in the absence of a pretty specific code example, and complete description of the conditions and their interactions.
I'm a fan of "flag setting" : meaning anytime my application goes into some less common "mode" or "state" I set a boolean flag (which might even be static for the class) : for me that simplifies writing complex if/then else evaluations later on.
best, Bill
Simple. Take the body of the if and make a method out of it.
This works because most if statements are of the form:
if (condition):
action()
In other cases, more specifically :
if (condition1):
if (condition2):
action()
simplify to:
if (condition1 && condition2):
action()
I'm a big fan of the ternary operator which get's overlooked by a lot of people. It's great for assigning values to variables based on conditions. like this
foobarString = (foo == bar) ? "foo equals bar" : "foo does not equal bar";
Try this article for more info.
It wont solve all your problems, but it is very economical.
I know that this is not the answer you are looking for, but without context your questions is very hard to answer. The problem is that the way to refactor such a thing really depends on your code, what it is doing, and what you are trying to accomplish. If you had said that you were checking the type of an object in these conditionals we could throw out an answer like 'use polymorphism', but sometimes you actually do just need some if statements, and sometimes those statements can be refactored into something more simple. Without a code sample it is hard to say which category you are in.
I was told years ago by an instructor that 3 is a magic number. And as he applied it it-else statements he suggested that if I needed more that 3 if's then I should probably use a case statement instead.
switch (testValue)
{
case = 1:
// do something
break;
case = 2:
// do something else
break;
case = 3:
// do something more
break;
case = 4
// do what?
break;
default:
throw new Exception("I didn't do anything");
}
If you're nesting if statements more than 3 deep then you should probably take that as a sign that there is a better way. Probably like Avirdlg suggested, separating the nested if statements into 1 or more methods. If you feel you are absolutely stuck with multiple if-else statements then I would wrap all the if-else statements into a single method so it didn't ugly up other code.
If the entire purpose is to assign a different value to some variable based upon the state of various conditionals, I use a ternery operator.
If the If Else clauses are performing separate chunks of functionality. and the conditions are complex, simplify by creating temporary boolean variables to hold the true/false value of the complex boolean expressions. These variables should be suitably named to represent the business sense of what the complex expression is calculating. Then use the boolean variables in the If else synatx instead of the complex boolean expressions.
One thing I find myself doing at times is inverting the condition followed by return; several such tests in a row can help reduce nesting of if and else.
Not a C# answer, but you probably would like pattern matching. With pattern matching, you can take several inputs, and do simultaneous matches on all of them. For example (F#):
let x=
match cond1, cond2, name with
| _, _, "Bob" -> 9000 // Bob gets 9000, regardless of cond1 or 2
| false, false, _ -> 0
| true, false, _ -> 1
| false, true, _ -> 2
| true, true, "" -> 0 // Both conds but no name gets 0
| true, true, _ -> 3 // Cond1&2 give 3
You can express any combination to create a match (this just scratches the surface). However, C# doesn't support this, and I doubt it will any time soon. Meanwhile, there are some attempts to try this in C#, such as here: http://codebetter.com/blogs/matthew.podwysocki/archive/2008/09/16/functional-c-pattern-matching.aspx. Google can turn up many more; perhaps one will suit you.
try to use patterns like strategy or command
In simple cases you should be able to get around with basic functional decomposition. For more complex scenarios I used Specification Pattern with great success.