Drools

1.2爲什麼使用規則引擎
一些經常會問到的問題有:
。爲什麼我要用一個規則引擎?
。相比"if ...then"這樣的硬編碼規則的方法,規則引擎有什麼優點?
。爲什麼我要規則引擎,而不是像Beanshell之類的腳本框架?
我們將在下面解答這些
1.2.1 規則引擎的優點總結
。聲明式編程
規則引擎可以允許你只需要說“要做什麼”,而不是說“如何去做”。
這樣做的很重要的優點是很容易的表達困難問題的解答,從而對結果進行驗證(閱讀規則比閱讀代碼容易的多)
規則系統能夠解決非常非常困難的問題,同時提供的這種解決還能夠解釋爲什麼會有這樣的決策(別的AI系統就很不容易,像神經網絡,或者說我的大腦-我不知道我爲什麼能畫出汽車)
。邏輯和數據的分離
你的數據在你的域對象中,邏輯在規則中。這將根本上打破OO中數據和邏輯的綁定(依賴於你的觀點,這是個優點或許是個缺點)。結果是邏輯能更加容易的維護,更容易在未來進行改變,因爲邏輯是建立在規則之上的。
。速度和可擴展性
Rete算法,Leaps算法和它的派生算法,例如Drools的Reteoo(和leaps),提供了非常有效的方法去匹配規則模式和數據對象數據。特別是當你數據集不會完全改變的適合就更加有效(規則引擎能夠記住過去的匹配)。這些算法經歷了實戰的檢驗。
。以知識爲中心
通過運用規則,你能夠建立可執行的知識庫。This means its a single point of truth, for business policy (for instance),理想的,規則是如此的具有可讀性,除了執行它們也可以作爲文檔。
。工具集成
像eclipse(以後會是基於web的UI)這樣的工具提供了方法來編輯和管理規則,得到即時反饋,驗證,content assitance,審計和調試工具。
。explanation facility
規則系統能夠通過記錄規則引擎的決策,有效的提供“explanation facility”
。可理解規則(能夠由領域專家閱讀)
通過創建對象模型(可選的,域特定的語言),建模你的問題域,規則看起來非常貼近自然語言。這使得那些不是技術人員的領域專家能夠理解。
1.2.2 什麼時候你應該採用規則引擎
對於這個問題最簡單的回答是“當傳統的編程方法沒有可以令人滿意的方法解決問題的時候”。對這個簡單的回答需要我們做出詳細的解釋。
沒有傳統辦法的原因可能是以下原因:
對於傳統的編碼方式,問題的要求可能過於精細,問題可能並不複雜,但是去找不到不那麼脆弱的方法。
問題沒有任何容易理解的算法去解決。
要解決的問題是一個複雜問題,沒有傳統的方法,或者問題完全無法理解。
邏輯經常改變
邏輯本身可能是簡單的(但是也不是一定會簡單),但是規則經常改變,在許多組種種,軟件的發佈期間隔很久,而規則能夠幫助在期望的時間內提供所需要的靈活性。
領域專家(或者是業務分析師)很容易可以找到,但是他們卻不是技術人員。
非技術的領域專家通常對於業務邏輯有非常豐富的知識,他們通常不是關注技術而是卻非常有邏輯性,規則能夠提供讓領域專家用他們自己的語言表達邏輯。當然他們仍然不得不思考,精密而且邏輯性的思考。(許多在非技術職位上的人並不擅長這樣的思考,所以要小心,當用規則編碼業務知識,還還會經常像目前業務規則一樣碰見缺陷)
當然,如果,你的項目組對於規則完全是沒經驗的。在熟悉中的開支也必須要考慮到。這並不是一項簡單的技術,但是我們試圖是它更簡單。
典型的,在現代的OO應用中,你可以用一個規則引擎來容納業務邏輯的關鍵部分()-特別是,也就是完全一團糟的部分。這和OO的把邏輯封裝到對象中的概念是相反的。這並不是說你你要完全拋棄OO概念,相反的,在任何實際的應用中,業務規則都只是應用的一部分。如果你注意到你的代碼中有大量的"if""else""switch"和其他凌亂的邏輯,而且爲之發愁(要麼因爲你錯了,或者邏輯改變了,你講不停的返回來修改)-那麼就考慮用規則。如果你正面對困難的問題,而且沒有算法或模式去解決,也考慮規則。
規則能夠嵌入在你的應用中,或者作爲一個服務。通常規則作爲有狀態的組件會工作的最好,因此,通常是集成在應用中,然而,把規則作爲無狀態的可重用的服務,也有成功的例子。
在你的組織中,重要的是要考慮一下你在使用的系統中可能或者不得不更新規則的過程。(這個過程可選的,但是不同的組織有不同的需求,而且通常不受應用提供者/項目開發者的控制)
1.2.3什麼時候不使用規則引擎
引用Drools郵件列表中的話(Dave Hamu):在我來看來在使用的規則引擎的興奮中,人們忘記 規則引擎僅僅是複雜應用或解決方案的一個部分。實際上規則引擎並不是打算去解決工作流或者過程的執行,工作流引擎或者過程管理工具也沒有設計的要使用規則。使用對工作合適的工具。當然,緊急中一把鉗子也能作爲榔頭使用,但是那並不是設計它的目的。
規則引擎是動態的(動態是從規則能存儲,管理,更新上說的),它們通常能看做是配置軟件這個問題的解決辦法。(most IT departments seem to exist for the purpose of preventing software being rolled out),如果這是你使用規則引擎的原因,要清楚的知道規則引擎在你能夠寫出聲明式的規則時才能提供最佳的工作效果。可選擇的,你也可以考慮數據驅動的設計(查找表),或者腳本/過程引擎,其中腳本可以由數據庫管理,能夠動態的更新。
1.2.4 腳本或者過程引擎
希望上面的章節已經解釋了什麼時候你可能會用規則引擎。
可選的,基於腳本的引擎也能爲不確定的改變提供動態性(有很多解辦法)。
像jBPM過程引擎(也能工作流)能讓你圖形化(或者程序化)的描述一個過程中的步驟-這些步驟也能涉及到決策點,決策點中本身也是一個簡單的規則。過程引擎和規則能夠很好的一起工作,所以它們並不是非此即彼的關係。
規則引擎中要注意的一個關鍵是,一些規則引擎實際上是腳本引擎。腳本引擎的不利是你的應用緊緊的和腳本結合在一起,這樣可能會給未來的維護造成困難,它們也會隨時間變的更復雜。有利的它們能快速的實現,然後你很快的得到結果。
很多人在過去也成功的實現了數據驅動的系統(其中,有控制表來存儲能改變你應用行爲的元數據),當控制有限時,它們工作的很好。然而,如果需要很多的控制時,這種方法就不行了。或者它會因爲不靈活是你的應用不能改變。
1.2.5 緊耦合和鬆耦合

毫無疑問,在系統設計中你已經聽說過緊耦合和鬆耦合。一般的,在設計上,由於能夠增進靈活性,人們認爲鬆耦合或者弱耦合是更好的。對規則也一樣,你可能有緊耦合或者鬆耦合的規則。緊耦合意味着一個規則被觸發會清楚的導致另一個規則的觸發,換句話,存在清楚的邏輯鏈。如果你的規則都是緊耦合的,可能的情況就是將會變的不靈活。或者更嚴重的,可能是過度使用規則引擎了(因爲,如果邏輯是很清楚的規則鏈,那麼可以寫入代碼中)。並不是說緊耦合或者鬆耦合必定是壞的,當考慮到一個規則引擎的時候,它是你要始終考慮住的一點,同樣也是在你如何捕獲規則的時候。鬆耦合將產生的系統中規則能夠改變,去處,添加而不用考慮其他不相關的規則。

1.3 知識表達
1.3.1 產生式
一個產生式歸,或者規則,在Drools中是一個包括兩部分的結構,有左部(left hand side LHS )和右部(right hand side RHS)。附加的,一個規則可能有下面屬性:
      salience
      agenda-group
      auto-focus
      activation-group
      no-loop
      duration
rule “”   
       
    when       
           
    then       
       
end
規則的LHS包括條件元素(conditional elements CE)和Columns,可以編碼命題和一階邏輯。
column用來指出一個事實(Fact)上的域限制。
Drools當前支持下面CE:
'and'  'or' 'not' 'exists'
'forall' and 'accumulat' 很快就會添加進來。
有下面這些域限制:
  
      Literal Constraint
      Bound Variable Constraint
      Return Value
      Predicate
語言指南那章會提供更詳細的信息。
當在工作存儲中聲明或修改一個事實時,它會匹配LHS條件,當所有的條件都符合,並且值爲‘真’規則加上那些符合的事實就會被激活。當一個規則被激活後,它會放入議程中,由議程決定它的執行當RHS執行,LHS和RHS的效果就類似於:
if ( ) {
   
}
然而,'if'這個詞是過程式的,它只一個可能執行流(如if this.... else if.... else .....)的一部分。規則用‘when’語義上更加清楚的表示當且僅當LHS匹配的時候,規則激活。
用package關鍵字規則和一個命名空間關聯,別的規則引擎能夠把這個包叫做規則集。一個包聲明import,全局變量,函數和規則
package com.sample
import java.util.List
import com.sample.Cheese
global List cheeses
function void exampleFunction(Cheese cheese) {
    System.out.println( cheese );
}
rule “A Cheesey Rule”
    when
        cheese : Cheese( type == "stilton" )
    then
        exampleFunction( cheese );
        cheeses.add( cheese );
end
下面這個例子表明一個有單個Column的LHS,這個Column有一個用在Chess事實中的Literal Field Constraint。
rule "Cheddar Cheese"
    when
        Cheese( type == "cheddar" )
    then
        System.out.println( "cheddar" );
end
這個例子效果類似於:
public void cheddarCheese(Cheese cheese) {
    if ( cheese.getType().equals("cheddar") {
        System.out.println( "cheddar" );
    }
}
規則完全的分離了邏輯和數據。規則不能直接的調用,它們並不是方法或函數,規則由工作存儲中的數據的改變而觸發。
1.3.2 一階邏輯
規則用一階邏輯或叫謂詞邏輯(命題邏輯的擴展)書寫,Emil Leon Post 是第一個開發基於推理的系統,用符合來表達邏輯,結論是,他能證明,任何邏輯系統(包括數學)能用這樣的一個系統來表達。
一個命題是有真假值的陳述句。如果僅從這句子本身就能確定真值,那麼它是一個‘closed statement’,在程序中,這就等於是不參考任何變量的表達式。
10==2*5
需要計算一個或多個變量的表達式,事實,是‘open statement’,也就是,除非變量被計算出來,否則我們不能確定陳述句的真假值。
Person.sex-"male"
如果我們結論動作是返回符合的事實,用SQL
select * from People where People.sex == "male"

對任何代表我們事實的行,我們推斷出這些事實是male peopele。下面這個圖可顯示,用推理引擎的觀點,sql語句和people表是如何表示的。

Drools第一章 <wbr>1.2 <wbr>1.3所以,在java中,我們能看見簡單的命題,它們有variable' 'operator' 'value' 這樣的形式,'value'通常是字面量(literal value)-這樣就是一個可以看做是域限制的s命題。更甚,這個命題可以用‘與’‘或’連接。例如下面的代碼採用'&&' '||'形式的邏輯連接。

person.getEyeColor().equals("blue") || person.getEyeColor().equals("green")
它也能用析取條件元素連接,會產生兩條規則
Person( eyeColour == "blue" ) || Person( eyeColor == "green" )
也可以析取的域限制連接,儘管現在在Drools3.0中還不支持。這樣不會產生多條規則。
Person( eyeColour == "blue"||"green" )
然而命題邏輯並不是圖靈完全的,這樣,它就會限制你所能表達的問題,因爲它不能表達數據的結構。一階邏輯通過兩個量詞概念擴展了命題邏輯,允許表達式定義結構。(存在量詞,全稱量詞)。全稱量詞允許你檢查對所有的某些事情是正確的。但是當前的Drools3.0中還不支持。存在量詞檢查存在某些事情。也就說至少一次。它通過‘not’和‘exists’條件元素來支持。
設想我們有兩個類-student 和Module。Module代表學生這個學期參加的每一個課程,通過List表示。在學期結束。每個Module有一個成績。如果學生有一個成績低於40分,那麼這個學期就不及格。-存在量詞能用在這樣的情況中。
public class Student {
    private String name;
    private List modules;
    ...
}
public Class Module {
    private String name;
    private String studentName;
    private int score;
Java是圖靈完全的, 你能寫代碼循環數據結構來檢查存在性。
List failedStudents = new ArrayList();
for ( Iterator studentIter = students.iterator(); studentIter.hasNext() {
    Student student = ( Student ) studentIter.next();
    for ( Iterator it = student.getModules.iterator(); it.hasNext(); ) {
        Module module = ( Module ) it.next();
        if ( module.getScore() < 40  ) {
            failedStudents.add( student ) ;
            break;
        }
    }
}

早期的SQL實現不是圖靈完全的,因爲它們並沒有提供量詞來計算數據的結構。然而現在的SQL引擎允許嵌套SQL,能夠組合關鍵詞如‘exists’或‘in’:下面的查詢返回不及格的student集合:
select
    *
from
    Students s
where exists ( 
    select
        *
    from
        Modules m
    where
        m.student_name = s.name and
        m.score < 40
)
rule
    when
        exists( $student : Student() && Module( student == $student, score < 40 ) )
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章