流口水冲突解决程序与突出问题

发布于 2024-10-17 20:44:39 字数 4732 浏览 1 评论 0原文

我发现 drools 引擎有奇怪的行为。 我有两条具有不同重要性的规则。如 drools 文档中所述

3.3.4.1。冲突解决

以下情况需要解决冲突 有多项规则 议程。 (这的基础是 “快速入门”一章中有介绍。) 触发规则可能会产生副作用 工作记忆,规则引擎 需要知道规则的顺序 应该开火(例如,开火 规则 A 可能会导致规则 B 被删除 从议程)。

默认的冲突解决方案 Drools 采用的策略是: 显着性和 LIFO(后进先出) 出)。

最明显的一个是显着性(或 优先级),在这种情况下用户可以 指定某个规则具有 更高的优先级(通过给予它更高的 数)比其他规则。在那 case,具有较高显着性的规则 将被优先考虑。后进先出的优先事项是 基于分配的工作记忆 动作计数器值,符合所有规则 在同一操作期间创建 接收相同的值。这 一组触发的执行顺序 具有相同优先级值的是 任意。

但是,对每种类型使用 5 个对象执行两条规则会产生奇怪的结果 - 在某些对象上,显着性为 1 的规则比显着性为 10 的规则执行得更早。 如果我从规则中删除更新,则首先执行显着性为 10 的规则,然后才执行显着性 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

这里是 java 代码,可以让您更快地测试它

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

        }

}

谢谢,我非常感谢您的帮助。 PS:我知道,依赖规则触发的顺序并不是一个好主意,但在我运行这个之前,显着性对我来说似乎是值得信赖的。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧街凉风 2024-10-24 20:44:39

查看您的 drl 文件,您给出了条件“when”部分 m2 : Message2(status <0)
,请记住,LHS 仅在断言时或调用给定事实的修改()/更新()时进行评估。因此,在断言时,条件将评估为 true 并激活规则。您永远不会对同一个对象.Message2调用modify()/update,因此,您的条件永远不会被重新评估。这就是为什么你会出现奇怪的行为。
这就是为什么您无需更新即可获得所需行为的原因。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文