java drools
像Drools這樣的規則引擎通常使用自定義語言來定義一組規則。 例如,Drools編譯器将drl檔案轉換為内部表示形式(KiePackages),該内部表示形式随後用于生成ReteOO / Phreak網絡,該網絡将執行規則評估。
最終使用者從未真正打算使用這種内部表示形式。 這種複雜性使得難以以程式設計方式編寫規則,而建議是在DRL級别上生成文本規則。 這意味着drl本身是目前在Drools中定義一組規則的唯一實用形式符号。
當時,流口水的内部構造有多個假設,這些假設不再是真實的或不可取的。 在Java 8之前,需要考慮perm gen的存在,是以使用了各種解決方案來解決這一問題-例如基于反射的MVEL。 Java 8現在将代碼放在堆上,是以不再需要。 作為引擎級别,它還檢查并生成了索引,并将其與DRL生成的表達式相關聯–這使多語言無法實作。 最後,它自由地使用類加載器和反射,這使得在不同環境下執行執行時很難進行編譯。
引擎獨立規則模型
為克服此限制并提供以程式設計方式在純Java中定義一組規則的可能性,我們開發了一種模型,旨在提供規則集和規則集的規範表示。
流利的DSL以友善地建立此模型的執行個體。 該模型本身完全獨立于Drools,理論上可以被其他引擎重用。 它還引入了将引擎與必須了解任何語言完全分開的層。 例如,它不會檢查和生成索引,而是希望從上面的層提供這些索引。 另一個優點是,現在Drools對其執行的内容具有開發人員友好的看法,因為它們全都是純底層的pojo規則。
除了為所有Java開發人員提供一種以純Java編寫規則的幹淨方法之外,該模型還将使我們的團隊能夠更快地嘗試新功能,進而使我們免于負擔實作內建新功能的相應解析器和編譯器部件的負擔。具有drl表示法的功能。
讓我們來看一個使用上述DSL定義的規則模型的實際示例:
Rule rule = rule( "Persons older than Mark" )
.view(
expr("exprA", markV, p -> p.getName().equals("Mark"))
.indexedBy( String.class, ConstraintType.EQUAL, Person::getName, "Mark" )
.reactOn( "name", "age" ),
expr("exprB", olderV, p -> !p.getName().equals("Mark"))
.indexedBy( String.class, ConstraintType.NOT_EQUAL, Person::getName, "Mark" )
.reactOn( "name" ),
expr("exprC", olderV, markV, (p1, p2) -> p1.getAge() > p2.getAge())
.indexedBy( int.class, ConstraintType.GREATER_THAN, Person::getAge, Person::getAge )
.reactOn( "age" )
)
.then(on(olderV, markV)
.execute((p1, p2) -> System.out.println( p1.getName() + " is older than " + p2.getName())));
這等效于drl中表達的以下規則:
rule "Persons older than Mark" when
$p1 : Person(name == \"Mark\")
$p2 : Person(name != \"Mark\", age > $p1.age)
then
System.out.println($p2.getName() + \" is older than \" + $p1.getName());
end
顯然,DSL版本更加冗長,需要指定更多詳細資訊,而當Drols編譯器解析以drl編寫的規則時,這些細節反過來又由drools編譯器推斷出來。
正如預期的那樣,這樣做是有目的的,因為模型必須明确包含生成ReteOO / Phreak網絡的一部分以評估該規則所需的所有資訊,而無需執行任何位元組碼檢查或使用任何其他複雜,易碎和非便攜式自省技術。 在這些簡單的示例中,索引包含與expr相同的邏輯,因為每個DRL表達式可以包含的不僅僅是索引。 索引将由較高的語言層推斷并隐式添加。
為了闡明這一方面,讓我們更詳細地分析單個LHS限制:
expr("exprA", [1]
markV, [2]
p -> p.getName().equals("Mark") ) [3]
.indexedBy( String.class, ConstraintType.EQUAL, Person::getName, "Mark" ) [4]
.reactOn( "name", "age" ) [5]
在此語句中,您可以注意到以下部分:
[1]這是用于确定其身份的限制的标簽。
兩個相同的限制必須具有相同的标簽,而兩個不同的限制必須具有不同的标簽,以使引擎在可能的情況下正确實作節點共享。
可以選擇省略此标簽,在這種情況下,它将通過對實作限制的lambda表達式的位元組碼進行自動自省生成。
但是,正如預期的那樣,最好避免使用任何自省機制,然後在可能的情況下顯式提供限制标簽。
[2]這是在建立規則之前定義的變量,用于将實際事實與用于評估條件的lambda表達式的形式參數綁定在一起。
它等效于用drl表示法編寫的規則中的變量聲明。
[3]執行限制評估的lambda表達式。
[4]此限制的類型的規範以及引擎必須如何對其進行索引。
[5]此限制必須為React性的Person對象的屬性名稱。
建立并執行模型
您可以以程式設計方式将規則庫的此規則和其他規則添加到模型中:
Model model = new ModelImpl().addRule( rule );
一旦有了這個完全獨立于Drools算法和資料結構的模型,您就可以使用第二個項目 ,這次既依賴于Drools,也依賴于模型本身,以此來建立KieBase。
KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );
該建構器在内部所做的是從模型中重新建立KiePackages,然後使用現有的drools編譯器進行建構。 生成的KieBase與通過編譯相應的drl而獲得的KieBase相同,然後可以以完全相同的方式使用它,從中建立一個KieSession并用您的域事實填充它。
在這裡,您可以找到更多測試用例,以顯示該模型目前支援的Drools功能以及允許使用它們的DSL構造,而在這裡,您可以找到一個更完整的示例。
将可執行模型嵌入到kjar中
目前,一個kjar包含一些實作限制和後果的預生成類。 但是,所有drl檔案都需要從頭開始進行解析和編譯,是以僅從源代碼建構檔案時就節省了有限的錢。 可執行模型也将有助于加快此過程。 将實作規則庫模型的類嵌入到kjar中,可以快速重新建立KiePackages,而不必從drl檔案重新啟動整個編譯過程。 提供了有關如何工作的證明概念
在這裡 。
DRL編譯器到可執行模型
我們正在開發一個新的編譯器,它将使用現有的DRL并直接輸出可執行模型,該模型存儲在kjar中。 這将導緻更快的加載和建構時間。 通過在kjar中預緩存更多資訊,我們也正在尋找其他加快此過程的方法,這些資訊可以在最初的kjar建構期間确定。
Pojo,Polyglot和DRLX規則
可執行模型是低級的,并且由于您必須提供它所需的所有資訊,是以有點冗長。 這是通過設計完成的,以支援語言級别的創新。 盡管從技術上講它仍然是規範規則,但日常使用并不理想。 在不久的将來,我們将在不太冗長的pojo規則層上工作,該層将使用注釋處理器注入諸如index和reactOn之類的東西。 我們還希望它會産生幾種規則語言,而不僅僅是一種-scala規則,閉包規則,mini-dsl規則等。對于一種語言也不必公開所有引擎功能,人們可以編寫mini-dsls公開子集。
最後,我們還緻力于下一代DRL語言(DRLX),它将成為Java的超集。 它仍處于設計階段,并且将在一段時間内不可用,但是一旦準備好早期規範草案,我們将為此釋出一些建議。
翻譯自: https://www.javacodegeeks.com/2017/08/drools-canonical-model-pure-java-rules.html
java drools