开发者

Drools conflict resolver with salience problem

I've found strange behavior of drools engine. I have two rules with different saliences. As described in drools documentation

3.3.4.1. Conflict Resolution

Conflict resolution is required when there are multiple rules on the agenda. (The basics to this are covered in chapter "Quick Start".) As firing a rule may have side effects on the working memory, the rule engine needs to know in what order the rules should fire (for instance, firing ruleA may cause ruleB to be removed from the agenda).

The default conflict resolution strategies employed by Drools are: Salience and LIFO (last in, first out).

The most visible one is salience (or priority), in which case a user can specify that a certain rule has a higher priority (by giving it a higher number) than other rules. In that case, the rule with higher salience will be preferred. LIFO priorities are based on the assigned Working Memory Action counter value, with all rules created during the same action receiving the same value. The execution order of a set of firings with the same priority value is arbitrary.

But executing my two rules with 5 objects for each type gives strange results - On some objects, rule with salience 1 is executed earlier than rule with salience 10. If I remove update from rule, first rules with salience 10 are开发者_运维知识库 executed, and only then with salience 1.

 package com.sample

import com.sample.DroolsTest.Message;
import com.sample.DroolsTest.Message2;



rule "Hello World2"
    salience 10
    when
        m : Message()
        m2 : Message2(status <0)
    then

        System.out.println( "Second Rule With Salience 10"); 
        System.out.println( "m status = "+m.getStatus()); 
        System.out.println( "m2 status = "+m2.getStatus()); 
        m2.setStatus(m2.getStatus()*(-1));
        update(m2);
end

rule "Hello World3"
    salience 1
    when
        m2 : Message2()
        m : Message()
    then
        System.out.println( "Third Rule With Salience 1"); 
        System.out.println( "m status = "+m.getStatus()); 
        System.out.println( "m2 status = "+m2.getStatus()); 
end

rule "GoodBye"
    salience 0
    when
        eval(true)
    then
        System.out.println( "End" );
end

And here is the java code to make you test it faster

    package com.sample;

    import org.drools.KnowledgeBase;
    import org.drools.KnowledgeBaseFactory;
    import org.drools.builder.KnowledgeBuilder;
    import org.drools.builder.KnowledgeBuilderError;
    import org.drools.builder.KnowledgeBuilderErrors;
    import org.drools.builder.KnowledgeBuilderFactory;
    import org.drools.builder.ResourceType;
    import org.drools.io.ResourceFactory;
    import org.drools.logger.KnowledgeRuntimeLogger;
    import org.drools.logger.KnowledgeRuntimeLoggerFactory;
    import org.drools.runtime.StatefulKnowledgeSession;

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

        public static final void main(String[] args) {
            try {
                // load up the knowledge base
                KnowledgeBase kbase = readKnowledgeBase();
                StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
                KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
                // go !
                System.out.println("Start");
                for(int i=0; i<5; i++){
                    Message message = new Message(i);
                    ksession.insert(message);
                    Message2 message2 = new Message2(-i);
                    ksession.insert(message2);
                }
                ksession.fireAllRules();
                logger.close();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }

        private static KnowledgeBase readKnowledgeBase() throws Exception {
            KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
            kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);
            KnowledgeBuilderErrors errors = kbuilder.getErrors();
            if (errors.size() > 0) {
                for (KnowledgeBuilderError error: errors) {
                    System.err.println(error);
                }
                throw new IllegalArgumentException("Could not parse knowledge.");
            }
            KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
            kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
            return kbase;
        }

        public static class Message {

            private int status;

            public int getStatus() {
                return this.status;
            }

            public Message(int status) {
                super();
                this.status = status;
            }

            public void setStatus(int status) {
                this.status = status;
            }

        }

    public static class Message2 {

            private int status;

            public Message2(int status) {
                this.status = status;
            }

            public int getStatus() {
                return this.status;
            }

            public void setStatus(int status) {
                this.status = status;
            }

        }

}

Thanks, I really appreciate your help. PS: I know, that rely on the sequence of rule firing is not a great idea, but salience seemed to me trustworthy, before I ran on this one.


looking at your drl file, your are giving condition "when" part m2 : Message2(status <0) ,Remember that LHS is only evaluated at assert time or when a modify()/update() on a given fact is called. So, at assert time, condition will evaluate to true and activate the rule. You never call modify()/update on the same object.Message2, and so,your condition is never re-evaluated. That is why you will get strange behavior. That is the reason why u will be getting desired behavior without update.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜