Drools:规则2未被触发,而规则1在内部触发(进入循环)

时间:2016-04-22 12:08:03

标签: java drools

我想解雇所有规则并退出。在我的例子中,我只有2条规则,但它们是相互关联的,即规则2应该在规则1之后被解雇。 问题是它只打印出规则1的输出。此外,它看起来像进入循环并在内部打印出相同的消息(Client is interested in skiing)。

package com.sample;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

/**
 * This is a sample class to launch a rule.
 */
public class TestSimpleRules {

    public static final void main(String[] args) {
        try {
            // load up the knowledge base
            KieServices ks = KieServices.Factory.get();
            KieContainer kContainer = ks.getKieClasspathContainer();
            KieSession kSession = kContainer.newKieSession("ksession-rules");

            // go !
            Client client = new Client();
            Season season = new Season();
            client.addProduct("snowboard");
            client.addProduct("ski poles");
            season.setSeason("winter");
            kSession.insert(client);
            kSession.insert(season);
            kSession.fireAllRules();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public static class Client {

        private Set<String> buyingHistory;
        private String interestedIn;

        public Client()
        {
            buyingHistory = new HashSet<String>();
        }

        public Set<String> getBuyingHistory() {
            return this.buyingHistory;
        }

        public void addProduct(String product) {
            this.buyingHistory.add(product);
        }

        public String getInterestedIn() {
            return this.interestedIn;
        }

        public void setInterestedIn(String interestedI) {
            this.interestedIn = interestedIn;
        }

    }

    public static class Season {

        private String currentSeason;

        public String getSeason() {
            return this.currentSeason;
        }

        public void setSeason(String season) {
            this.currentSeason = season;
        }

    }

}

规则:

package com.javacodegeeks.drools;

import com.sample.TestSimpleRules.Client;
import com.sample.TestSimpleRules.Season;

rule "Rule #1"
    when
        c : Client( Client.getBuyingHistory() contains "snowboard", thisBuyingHistory : buyingHistory) and
        s: Season( Season.getSeason() == "winter" )
    then
        System.out.println( thisBuyingHistory );
        c.setInterestedIn("skiing");
        System.out.println("Client is interested in skiing");
        update( c );
end

rule "Rule #2"
    when
       c: Client( Client.getInterestedIn() == "skiing" && !(Client.getBuyingHistory() contains "ski jacket"), thisBuyingHistory : buyingHistory) 
    then
       System.out.println("Ski jacket is recommended");
end

1 个答案:

答案 0 :(得分:0)

首先是几个技术细节:

  1. 不要使用类名限定方法调用。
  2. 要引用字段,仅使用字段名称就足够了 - 无需调用getter。
  3. 没有必要在最外层使用and,这是隐含的。
  4. 您可以将变量绑定到字段,并在单个构造中为该字段编写断言。
  5. 首选使用modify更新事实。
  6. 有一个运算符not contains,因此您不需要编写否定约束。
  7. (以上所有内容均可从Drools手册中学习。)

    rule "Rule #1"
    when
        c: Client( buyHist: buyingHistory contains "snowboard" ) 
        s: Season( season == "winter" )
    then
        System.out.println( buyHist );
        modify( c ){ setInterestedIn("skiing") }
        System.out.println("Client is interested in skiing");
    end
    
    rule "Rule #2"
    when
        c: Client( interestedIn == "skiing",
                   buyingHistory not contains "ski jacket" ) 
    then
        System.out.println("Ski jacket is recommended");
    end
    

    触发第一条规则的循环是由于字段interestedIn的修改,导致重新评估涉及某些Client事实的所有规则。由于"Rule #1"没有限制它取消发射资格,它再次发射。安全的补救措施是仅在interestedIn不等于"skiing"时限制规则才会触发:

    rule "Rule #1"
    when
        c: Client( buyHist: buyingHistory contains "snowboard"
                   interestedIn != "skiing" ) 
        s: Season( season == "winter" )
    then ... end
    

    还有其他方法可以处理这种情况。规则属性no-loop并非如此安全。检查上述文档以了解其他选项。