2015-01-02 39 views
0

正如標題所述,我想更改我的Drools項目中的衝突解決程序。我發現下面的代碼片段在這個site如何更改默認衝突解決程序

ConflictResolver[] conflictResolvers = 
new ConflictResolver[] { SalienceConflictResolver.getInstance(), 
         FifoConflictResolver.getInstance() }; 

RuleBase ruleBase = java.io.RuleBaseLoader(url, CompositeConflitResolver(conflictResolver)); 

但是它缺少的信息放在哪裏,什麼sholud是url參數。

非常感謝您的幫助。

+0

此鏈接指向相當古老的信息。 - 你有改變衝突解決方案的切實原因嗎? – laune

+0

我想說明的是,觸發規則的順序對系統輸出沒有任何影響。是否有另一種按隨機順序執行規則的方法? – kedzia

回答

1

由於文件說:

Drools的4.0支持的自定義衝突解決策略;雖然此功能仍然存在於Drools中,但它尚未通過Drools 5.0中的知識api暴露給最終用戶 。 http://docs.jboss.org/drools/release/5.2.0.Final/drools-expert-docs/html/ch04.html

所以,如果你正在使用Drools的5+你將不能夠改變衝突解決除非你做一些反思魔術。 Conflict Resolver在StatefulKnowledgeSession對象的Agenda對象中解決。您可以通過使用調試器(它的議程對象的內容)看到這一點:

enter image description here

要更換ConflictResolver,首先你需要StatefulKnowledgeSession的情況下(這將在下面的代碼片段ksession)。然後,您需要提取一些嵌套的專用字段,然後您可以用例如RandomConflictResolver的實例替換字段值。完整代碼:

 Agenda agenda = ksession.getAgenda(); 
     Field agendaField = agenda.getClass().getDeclaredField("agenda"); 
     agendaField.setAccessible(true); 
     Object agendaObject = agendaField.get(agenda); 


     Field mainField = agendaObject.getClass().getDeclaredField("main"); 
     mainField.setAccessible(true); 
     Object mainObject = mainField.get(agendaObject); 

     Field queueField = mainObject.getClass().getDeclaredField("queue"); 
     queueField.setAccessible(true); 
     Object queueObject = queueField.get(mainObject); 

     Field comparatorField = queueObject.getClass().getDeclaredField("comparator"); 
     comparatorField.setAccessible(true); 
     Object comparator = comparatorField.get(queueObject); 

     ConflictResolver randomResolver = org.drools.conflict.RandomConflictResolver.getInstance(); 
     comparatorField.set(queueObject, randomResolver); 

基於:documentation和調試器會話。

0

爲了證明點火順序不會影響整體結果,我會使用AgendaFilter。我正在使用6.x來勾畫大綱,但自從5.x以來,這個API並沒有改變。

KieBase kieBase = ...; 
Collection<KiePackage> packages = kieBase.getKiePackages(); 
List<Rule> rules = new ArrayList<>(); 
for(KiePackage p: packages){ 
    rules.addAll(p.getRules()); 
} 

現在你有所有的規則。建立這個簡單的過濾器,它接受一個規則:

class Selector implements AgendaFilter { 
    List<Rule> rules; 
    int ruleIndex; 
    Selector(List<Rule> rules){ 
     this.rules = rules; 
    } 
    void setRuleIndex(int value){ this.ruleIndex = value; } 
    int getRulesSize(){ return rules.size(); } 
    boolean accept(Match match){ 
     return match.getRule().equals(rules.get(ruleIndex)); 
    } 
} 

實例化:

Selector selector = newSelector(rules); 

現在你可以被激活的所有規則(見下文):

for(int i = 0; i < selector.getRulesSize(); ++i){ 
    int fired = kieSession.fireAllRules(selector, i); 
} 

任何其他0..size-1的置換可能會產生另一個發射序列。您可以爲少數規則系統地執行此操作,也可以使用一些隨機排列。

更高效的測試將跟蹤在第一次運行時傳遞給過濾器的匹配數據,並僅將這些數據用於後續執行。

注意到目前爲止概述的方法在工作內存中不考慮更改。規則n可能會被激活,當某些規則n + k被觸發。如果你確實有工作記憶的變化,你必須

do { 
    int sumf = 0; 
    for(int i : somePermutation){ 
     int fired = kieSession.fireAllRules(selector, i); 
     sumf += fired; 
    } 
} while(sumf > 0); 

我從來沒有做過這樣的測試。看來,根據規則解除的先天順序來獲得正確的結果是非常罕見的,與從這個順序中得到各種錯誤結果形成對比。

注意規則觸發順序的其他排列由DRL改變規則的順序(或在他們的包?),或者通過改變事實的插入順序進入工作記憶是可能的。對於某些情況,即使這可能會提供足夠的測試用例來顯示您的意圖。