drools always true 规则只触发一次

drools always true rule fires only once

我有这两条规则:

rule "challenge 1" salience 10
    when
        ClientTransaction(amount < 30)
    then
        challenge.setChallenge("challenge1");
end

rule "challenge 2" salience 0
    when
        eval( true )
    then
        challenge.setChallenge("challenge2");
end

和这个 java 代码:


public class ComputeChallengeDroolsRulesImplementation implements IComputeChallenge {
    private KieServices kieServices = KieServices.Factory.get();
    private KieSession kieSession = getKieSession();
    private static final String RULES_PATH = "rules/";

    public KieFileSystem getKieFileSystem() throws IOException {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        String[] rules = new File(getClass().getClassLoader().getResource(RULES_PATH).getFile()).list();
        for (String rule : rules) {
            kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + rule));
        }
        return kieFileSystem;
    }

    public KieContainer getKieContainer() throws IOException {
        getKieRepository();

        KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem());
        kb.buildAll();

        KieModule kieModule = kb.getKieModule();
        KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());

        return kContainer;
    }

    public void getKieRepository() {
        final KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(
                new KieModule() {
                    public ReleaseId getReleaseId() {
                        return kieRepository.getDefaultReleaseId();
                    }
                });
    }

    @Bean
    public KieSession getKieSession() {
        try {
            return getKieContainer().newKieSession();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Challenge2 computeChallenge(ClientTransaction clientTransaction) {
        kieSession.insert(clientTransaction);
        Challenge2 challenge = new Challenge2();
        kieSession.setGlobal("challenge", challenge);
        kieSession.fireAllRules();
        return challenge;
    }

}

这是 ClientTransation class :


public class ClientTransaction {
  private String id;
  private String merchant;
  private double amount;

  public ClientTransaction() {
  }

  public ClientTransaction(String id, String merchant, double amount) {
    this.id = id;
    this.merchant = merchant;
    this.amount = amount;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getMerchant() {
    return merchant;
  }

  public void setMerchant(String merchant) {
    this.merchant = merchant;
  }

  public double getAmount() {
    return amount;
  }

  public void setAmount(double amount) {
    this.amount = amount;
  }
}

这是挑战2 class :


public class Challenge2 {
  private String challenge;

  public Challenge2() {
  }

  public Challenge2(String challenge) {
    this.challenge = challenge;
  }

  public String getChallenge() {
    return challenge;
  }

  public void setChallenge(String challenge) {
    this.challenge = challenge;
  }
}


当我多次调用金额小于 30 的 ComputeChallengeDroolsRulesImplementation.computeChallenge 时,它会按预期多次 return 具有 "challenge1" 值的挑战对象。

但是当我多次调用 ComputeChallengeDroolsRulesImplementation.computeChallenge 且金额 >= 30 时,第一次它 return 一个 "challenge2" 值,但随后每次它 return 具有空值的 Challenge2 对象 ?

我是不是做错了什么?

谢谢

我假设您只想在 ClientTransaction 事件发生时触发 challenge 2 规则。您可以通过仅在流口水规则的 when 部分调用默认构造函数来基于事件的发生对规则添加无条件检查。尝试改变你的挑战 2 规则如下:

rule "challenge 2" salience 0
    when
        ClientTransaction()
    then
        challenge.setChallenge("challenge2");
end

另外,不建议在drools rule里用那么多eval。有关最佳实践的更多信息,请查看 here

如以下文档所述: https://docs.jboss.org/drools/release/5.2.0.Final/drools-expert-docs/html/ch05.html#d0e3313

The engine cannot be notified about value changes of globals and does not track their changes. Incorrect use of globals in constraints may yield surprising results - surprising in a bad way.

[…]

Globals are not designed to share data between rules and they should never be used for that purpose. Rules always reason and react to the working memory state, so if you want to pass data from rule to rule, assert the data as facts into the working memory.

It is strongly discouraged to set or change a global value from inside your rules. We recommend to you always set the value from your application using the working memory interface.