Сравните даты в слюнях

Мой файл правил, как показано ниже,

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

Я добавил следующий объект человека и правила огня, как показано ниже,

Person person = new Person();
person.date = "20-Feb-2015";
person.call_count = 400;
kSession.insert(person);
int fires = kSession.fireAllRules();

Но он не напечатал "Beep". Я думаю, что условия не совпадают, но я не могу понять, почему это происходит. Как я могу сравнить даты в слюнях?

Мой фактический набор правил,

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

И после изменения типа переменной даты человека я получил следующее исключение,

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']

Я создаю правила в виде набора строк и преобразовываю их в базу знаний, используя следующую функцию:

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();
        }
    }

person Hasitha    schedule 03.11.2015    source источник
comment
Я использую Drools 6.3.0. Если я удаляю часть сравнения дат, это правило работает нормально.   -  person Hasitha    schedule 03.11.2015
comment
Ааа, наконец-то пришла недостающая информация. Смотрите еще одно дополнение к моему ответу.   -  person laune    schedule 04.11.2015


Ответы (2)


Судя по всему у тебя

class Person {
    String date;
    // ...
}

Так что

when
    $person:Person(((date > "20-Jan-2015") ...

приводит к строковому (!) сравнению

"20-Feb-2015" > "20-Jan-2015" && "20-Feb-2015" < "20-Dec-2015"

который может даже работать время от времени, но в основном это не будет. Вы должны использовать

class Person {
    java.util.Date date;
    // ...
}

Вам нужно изменить

person.date = new Date( 115, 1, 20 ); // or, preferably, parse a string 

но вы можете оставить правило как есть; Drools преобразует строку в значение даты (при условии, что оно соответствует вашей локали).

Позже После некоторых экспериментов я обнаружил, что 6.3.0 (и, возможно, более ранние версии) ведут себя довольно странно при компиляции сравнений java.util.Date со строкой.

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)

Это абсолютно сбивает с толку, когда программист не может полагаться на тот факт, что связанная переменная ведет себя как свойство, с которым она связана.

И наконец: не используйте общедоступные поля в своих классах фактов. Оставайтесь с моделью Java Beans и объявляйте геттеры и сеттеры. Оказывается, Drools не использует автоматическое преобразование из String в java.util.Date при доступе к самой (общедоступной) переменной экземпляра из-за отсутствия геттера.

person laune    schedule 03.11.2015
comment
тогда мне нужно преобразовать 20 декабря 2015 года в значение даты, используя формат даты (например, формат DateFormat = new SimpleDateFormat (dd-MMM-yyyy, Locale.ENGLISH);). - person Hasitha; 03.11.2015
comment
Вам нужно только изменить назначение на person.date. Drools заботится о преобразовании строки, содержащей дату в условии. - Смотрите дополнение к моему ответу. - person laune; 03.11.2015
comment
Спасибо за поддержку, лаун. Но это дает мне исключение. (Для операции сравнения требуются совместимые типы. Найден класс java.util.Date и класс java.lang.String) - person Hasitha; 03.11.2015
comment
Хорошо. у меня работает, использую 6.2.0. Пожалуйста, добавьте дамп стека к вашему вопросу. - person laune; 03.11.2015
comment
это дает это исключение. java.lang.RuntimeException: невозможно проанализировать дату выражения › 20 ноября 2015 г.: [Ошибка: для операции сравнения требуются совместимые типы. Найден класс java.util.Date и класс java.lang.String] [Рядом: {... дата › 20 ноября 2015 г. ....}] - person Hasitha; 04.11.2015
comment
Хашита, вы не указали точное правило, в котором возникает проблема. - Смотрите мое дополнение к ответу. - person laune; 04.11.2015
comment
Мое точное правило такое же, как и в исходном сообщении, разница в том, что в нем есть эта строка. $person.points = ($person.call_count)*0,2; в тогда пункте правила. - person Hasitha; 04.11.2015
comment
Я только что добавил свой фактический набор правил и исключение в исходный пост. - person Hasitha; 04.11.2015
comment
Так и должно быть - теперь я ясно вижу, что вы напрямую обращаетесь к переменным экземпляра (дата, точки, call_count). Обязательно используйте геттеры и сеттеры. - person laune; 04.11.2015

Вы можете попробовать с org.apache.commons.lang.time.DateUtils. У меня такая же проблема, и это сработало для меня, может быть, сработает и для вас.

import org.apache.commons.lang.time.DateUtils; 

$person: Person((date > DateUtils.parseDate("20-01-2015", "dd-MM-yyyy") && date < DateUtils.parseDate("20-12-2015", "dd-MM-yyyy")) && (call_count >= "299"));
person ccc    schedule 03.11.2015
comment
перед созданием условия правила я не могу понять, каков тип переменной левой и правой части условия. Потому что я динамически генерирую правила, используя базу данных. - person Hasitha; 03.11.2015