My rule file as below,
import com.springapp.mvc.model.Person;
dialect "java"
rule "4"
when
$person:Person(((date > "20-Jan-2015") && (date < "20-Dec-2015")) && (call_count >= "299"))
then
System.out.println("Beep");
end
I added following person object and fire rules as below,
Person person = new Person();
person.date = "20-Feb-2015";
person.call_count = 400;
kSession.insert(person);
int fires = kSession.fireAllRules();
But it didn't print "Beep". I think conditions are not matched but I can't understand why this happen. How can I compare dates in drools?
My actual rule set,
package Customer_Loyalty_Categorization;
import com.springapp.mvc.model.Person;
dialect "java"
rule "4"
when
$person:Person(((date > "10-Nov-2015") && (date < "10-Dec-2015")) && (call_count >= "299"))
$person:Person(((date > "10-Nov-2015")&&(date < "30-Dec-2015")) && (call_count >= "299"))
then
System.out.println("Point rule runs.");
$person.points = ($person.call_count)*0.2;
end
rule "6"
when
$person:Person(call_count >= "599")
then
System.out.println("Category rule runs.");
$person.setCategory('PLATINUM');
end
And after changing type of the date variable of the person I got following exception,
java.lang.RuntimeException: Unable to Analyse Expression date > "20-Nov-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date > "20-Nov-2015" ....}]
^
[Line: 8, Column: 8] : [Rule name='4']
Unable to Analyse Expression date < "20-Dec-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date < "20-Dec-2015" ....}]
^
[Line: 8, Column: 8] : [Rule name='4']
Unable to Analyse Expression date > "01-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date > "01-Jan-2015" ....}]
^
[Line: 40, Column: 8] : [Rule name='1']
Unable to Analyse Expression date < "07-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date < "07-Jan-2015" ....}]
^
[Line: 40, Column: 8] : [Rule name='1']
Unable to Analyse Expression date > "01-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date > "01-Jan-2015" ....}]
^
[Line: 48, Column: 8] : [Rule name='2']
Unable to Analyse Expression date < "07-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date < "07-Jan-2015" ....}]
^
[Line: 48, Column: 8] : [Rule name='2']
Unable to Analyse Expression date > "05-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date > "05-Jan-2015" ....}]
^
[Line: 48, Column: 8] : [Rule name='2']
Unable to Analyse Expression date < "10-Jan-2015":
[Error: Comparison operation requires compatible types. Found class java.util.Date and class java.lang.String]
[Near : {... date < "10-Jan-2015" ....}]
^
[Line: 48, Column: 8] : [Rule name='2']
I'm generating rules as set of strings and convert them into knowledgebase using following function,
public void createKnowledgeBase(){
String ruleSet = loadRuleSet();//generate rules as strings.
try {
System.out.println(ruleSet);
long start = System.currentTimeMillis();
if(ruleSet!=null){
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
Resource myResource = ResourceFactory.newReaderResource(new StringReader(ruleSet));
knowledgeBuilder.add(myResource, ResourceType.DRL);
if (knowledgeBuilder.hasErrors()) {
throw new RuntimeException(knowledgeBuilder.getErrors().toString());
}
knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
knowledgeBase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());
}
long finish = System.currentTimeMillis();
System.out.println("Execution time = " + (finish-start) + " milliseconds.");
}
catch (Exception e) {
e.printStackTrace();
}
}
Apparently you have
class Person {
String date;
// ...
}
So that
when
$person:Person(((date > "20-Jan-2015") ...
results in a string (!) comparison of
"20-Feb-2015" > "20-Jan-2015" && "20-Feb-2015" < "20-Dec-2015"
which may even work at times, but mostly it wont. You should use
class Person {
java.util.Date date;
// ...
}
You need to change
person.date = new Date( 115, 1, 20 ); // or, preferably, parse a string
but you can leave the rule as it is; Drools will convert a string to a Date value (provided it corresponds to your locale setting).
Later After some experiments, I find that 6.3.0 (and probably earlier versions) have a rather weird behaviour when compiling comparisons of java.util.Date to String.
rule x1 when
Person(date > "10-Jan-2000") // OK
Person($date:date, date > "10-Jan-2000") // OK
Person($date:date, $date > "10-Jan-2000") // Error (types incompatible)
It is absolutely confusing when a programmer may not rely on the fact that a bound variable behaves like the property to which it is bound.
Finally: Don't use public fields in your fact classes. Stay with the Java Beans model and declare getters and setters. It turns out that Drools isn't using the automatic conversion from String to java.util.Date when a (public) instance variable itself is accessed due to the lack of a getter.