轉:java 規則引擎

最近剛剛接觸JAVA的規則引擎,一般的系統而言,業務不是非常複雜,而且變化少,因此很少採用什麼規則引擎,最近接觸了一個規則引擎的系統,是使用BlazeSoft公司的Blaze來實現的,自己對它正在瞭解中,把具體的實現相關的知識,寫下來,以待進一步的整理。

本系列文章主要先人云亦云地介紹一下規則引擎的背景知識(本人瞭解規則引擎不多),接着介紹JSR94的 API和具體的實現,以及blaze自己提供的java api的簡單介紹和實現,然後介紹一下BlazeSoft公司的blaze的搭建、開發和部署,以及在java環境中的集成,簡單介紹一下Blaze使用 的規則語言,srl的語法。

規則引擎的簡介

規則引擎

規則引擎是推理引擎的一種,它起源於基於規則的專家系統。規則引擎好像不是新鮮的話題了,但在java應用中,好像以前討論得不多,不久熱起來的。

規則引擎也就是基於規則的專家系統中的推理引擎發展而來。下面簡要介紹一下基於規則的專家系統。

引用一段相關文章的介紹 :

RBES的推理(規則)引擎

和人類的思維相對應,規則引擎存在兩者推理方式:演繹法(Forward-Chaining)和歸納法(Backward-Chaining)。演繹法從 一個初始的事實出發,不斷地應用規則得出結論(或執行指定的動作)。而歸納法則是從假設出發,不斷地尋找符合假設的事實。

Rete算法是目前效率最高的一個Forward-Chaining推理算法,Drools項目是Rete算法的一個面向對象的Java實現。

規則引擎的推理步驟如下:

1. 將初始數據(fact)輸入Working Memory。
2. 使用Pattern Matcher比較規則(rule)和數據(fact)。
3. 如果執行規則存在衝突(conflict),即同時激活了多個規則,將衝突的規則放入衝突集合。
4. 解決衝突,將激活的規則按順序放入Agenda。
5. 使用規則引擎執行Agenda中的規則。重複步驟2至5,直到執行完畢所有Agenda中的規則。

具體請參考其他相關文章的介紹。

規則引擎是一種嵌入在應用程序中的組件,實現了將業務決策從應用程序代碼中分離出來,並使用預定義的語義模塊編寫業務決策。接受數據輸入,解釋業務規則,並根據規則做出業務決策。

“Java規則引擎將業務決策從應用程序代碼中分離出來,並使用預定義的語義模塊編寫業務決策。Java規則引擎接受數據輸入,解釋業務規則,並根據規則 作出業務決策。從這個意義上來說,它是軟件方法學在”關注點分離”上的一個重要的進展。”,有人說,soa的發展成熟,將給規則引擎提供良好的切入。

但是究竟什麼是規則引擎,在業界中還沒有統一的說法,至今仍然是個爭議性的問題,因此也就缺少標準,如今比較流行的,作爲規則引擎實現標準化的JSR 94(Java規則引擎API)也對此幾乎沒有任何定義,因此,暫且不深究吧。

爲什麼要使用規則引擎,它所適合的場所?

在保險業和金融服務業都廣泛地使用了基於規則的編程技術,當需要在大量的數據上應用複雜的規則時,規則引擎技術特別有用。

以前參與過一個系統,是一個物流的調度系統,當時遇到一個問題,就是在實施的最後一個月中,客戶的業務產生了多次變化,而且一直都有可能變化 。該系統業務比較複雜,變化大,這是在需求開發中是沒有料到的,客戶他們也一樣,他們也不能預測以後的業務會發生怎樣的變化。後來經過打了一系列的補丁才 解決了問題,有些不可解決的問題,還是最後通過雙方的讓步,最終通過妥協解決的。後來想想,應該在需求研發中加大比重,挖掘隱性需求,另外應該利用工作流 引擎結合簡單的規則引擎,應該可以相應的降低或者避免後來出現的問題,以適應客戶的不斷變化的業務發展。

我們其實在今天一直都在討論在什麼時候以及什麼場所中,該使用規則引擎,這個疑問對於大多數人都存在,就像連規則引擎是什麼,如何使用,這兩個問題都沒有 統一的答案一樣,一切好像都存在很大的爭議性,我們暫且不深究吧。像以前作的系統,有人提倡使用什麼什麼引擎,後來覺得我們水平不夠,使用的學習成本也不 低,不是很複雜的系統的業務邏輯,直接嵌入coding一樣沒問題,並且一些常變的規則,我們把它做成可配置(當然如果變化的規則變得越來越龐大的話,那 是災難性的)。總之還是可以滿足需求。 看過相關的介紹,一般是指兩方面的需求:

一、業務模式不成熟,跟着業務的發展,和行業的成熟,業務規則或者模式會經常變換,另外就是根據市場的需求,業務規則也經常變化。我們適用這些規則的變化,可以讓業務人員直接變更這些系統中的規則,不需要開發人員的參與。

二、我們開發的系統,很多業務規則在需求研發階段並不明朗,規則的變化可能一直貫穿到設計和編碼,甚至在維護和運營之中。因此,我們需要一個相關的框架來 對這些業務規則,進行統一的管理。像EJB和Spring只能在高端實現商務邏輯構建,但並不能提供具體的code的管理。用在配置性,可讀性和重用性方 面,帶給我們極大利益的框架,來代替那些嵌入到系統代碼中的if-else等邏輯(這些邏輯往往可讀性差),看過一篇文章,是做這方面探討的,有一些啓 發,請看http://lizwjiang.blog.hexun.com/3475785_d.html

其實在實踐中,帶來的利益是上述兩者兼而有之的,就像一般的規則引擎語言,都是比較簡單明瞭的語言,像balze公司的STRUTURED RULE LANGUAGE,它追求的目標是,它的語法“as English-like as possible”,是比較容易懂,也易學,他的維護界面,也停供可視化的操作界面,因此在管理這些規則,某些簡單的規則,業務人員是可以操作的,其實, 在某些系統中,很多具體的業務變化,改變的都是這些規則。另外,它作爲一個規則代碼統一管理的框架,或者叫它嵌入式的組件,對這些規則的統一管理是非常方 便的,而且不用重啓應用系統。

當然,至於說完全不用開發人員的參與,讓業務人員去維護規則,就今天的發展現狀而言,有點癡人說夢矣。

總的來說,“複雜企業級項目的開發以及其中隨外部條件不斷變化的業務規則(business logic),迫切需要分離商業決策者的商業決策邏輯和應用開發者的技術決策,並把這些商業決策放在中心數據庫或其他統一的地方,讓它們能在運行時(即商 務時間)可以動態地管理和修改從而提供軟件系統的柔性和適應性。規則引擎正是應用於上述動態環境中的一種解決方法。”

下面轉述一下相關的產品的介紹

目前主流的規則引擎組件多是基於Java和C++程序語言環境,已經有多種Java規則引擎商業產品與開源項目的實現,其中有的已經支持JSR94,有的正朝這個方向做出努力,列出如下:

Java規則引擎商業產品有:

l. ILOG公司的JRules(見 http://www.ilog.com/produts/jrules/)
2. BlazeSoft公司的Blaze(見 http://www.fairisaac.com)
3. Rules4J
4. Java Expert System Shell (JESS)(見http://herzberg.ca.sandia.com/jess)

Jess不是開源項目,它可以免費用於學術研究,但用於商業用途則要收費

開源項目的實現包括:

l. Drools項目(見 http://drools.org/
Drools規則引擎應用Rete算法的改進形式Rete-II算法。從內部機制上講,它使用了和Forgy的算法相同的概念和方法,但是增加了可與面嚮對象語言無縫連接的節點類型。

最近Drools被納入JBoss門下,更名爲JBoss Rules,成爲了JBoss應用服務器的規則引擎。

有一篇入門的介紹文章,見:http://www.blogjava.net/guangnian0412/archive/2006/06/04/50251.aspx

2. JLisa項目(見 http://jlisa.sourceforge.net/
JLisa是用來構建業務規則的強大框架,它有着擴展了LISP優秀特色的優點,比Clips還要強大.這些特色對於多範例軟件的開發是至關重要的。它實現了JSR94 Rule Engine API。

3. OFBiz Rule Engine(不支持JSR 94)

4. Mandarax(見 http://mandarax.sourceforge.net/
Mandarax是一個規則引擎的純Java實現。基於反向推理(歸納法)。能夠較容易地實現多個數據源的集成。例如,數據庫記錄能方便地集成爲事實集 (facts sets),reflection用來集成對象模型中的功能。支持XML標準(RuleML 0.8)。它提供了一個兼容J2EE的使用反向鏈接的接口引擎。目前不支持JSR 94。

還有其他,在我們社區也有相關的介紹,例如:http://www.javaeye.com/topic/7803?page=7

5、OFBiz Rule Engine - 支持歸納法(Backward chaining).最初代碼基於Steven John Metsker的”Building Parsers in Java”,不支持JSR 94

其它的開源項目實現有諸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler,  Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2等等。

目前規則引擎比較流行的算法是都來自於Dr. Charles Forgy在1979年提出的RETE算法及其變體,Rete算法是目前效率最高的一個Forward-Chaining推理算法。詳情請見 CIS587:The RETE Algorithm,The Rete Algorithm,RETE演算法,《專家系統原理與編程》中第11章等。

規則語言

是規則引擎應用程序的重要組成部分,所有的業務規則都必須用某種語言定義並且存儲於規則執行集中,從而規則引擎可以裝載和處理他們。

Java Specification Request (JSR) 94沒有爲任何類型的業務規則(如,基於XML的、基於統一數據的或基於對象模型的)指定描述語言。由於沒有關於規則如何定義的公用規範,市場上大多數流 行的規則引擎都有其自己的規則語言,目前便有許多種規則語言正在應用。流行的規則語言:

STRUTURED RULE LANGUAGE(srl)          http://www.fairisaac.com
Rule Markup language (RuleML)                        http://www.ruleml.org/
Simple Rule Markup Language (SRML)                    http://xml.coverpages.org/srml.html
Business Rules Markup Language (BRML)                    http://xml.coverpages.org/brml.html
SWRL: A Semantic Web Rule Language Combining OWL and RuleML   http://www.daml.org/2003/11/swrl/

對於規則語法錯誤可以靠IDE工具來識別,當然,一般的IDE還沒有Eclips和JBuilder等 IDE那麼方便,JBoss已經有提供Eclipse plugin了。如果要在上述的規則框架中移植這些規則的具體實現,變換規則定義,一般要使用XSLT轉換器。當然公用規則語言的缺乏將阻礙不同規則引擎 之間的互操作性,業界現在比較流行的公用操作語言都仍然沒有達到各家提供商的一致認可,因此,公用標準的路還很長。

上面說到,目前在市場上留下多種規則引擎的產品,同樣有多種的規則引擎語言,存在兼容性的問題。因此,我們 必須提供一個統一的,標準的接口,來實現規則引擎的具體實現與業務應用系統之間的解耦,就像JDBC能夠適應多種數據庫一樣,JSR 94也就順勢而生。當然,由於在語言級的標準路還很長,因此JSR 94只是在java中接口級別的標準。它的出現可以避免在更換實現產品時,必須重寫應用程序邏輯和API調用的噩夢。JSR 94的官方網站爲:http://jcp.org/en/procedures/jcp2

SR94 的規則引擎API介紹

我們先來看看包內主要的類,如圖jsr94.bmp。

我們可以看到,包主要有javax.rules.admin和javax.rules兩個目錄,前一個目錄,顧名思義,就是規則管理API(the rules administration API),後者是其他用途的API,我們稱之爲運行時API(the Runtime client API)。

規則管理API,我們從上圖可以看到主要包括以下幾個類:

RuleExecutionSetProvider類:
裏面主要重載三個方法createRuleExecutionSet,從名稱中可以看出,這個方法負責創建規則執行集。

LocalRuleExecutionSetProvider類:
與之對應的是 RuleExecutionSetProvider類,一個是遠程的,一個是本地的(Local)。

規則執行集可以從如XML streams, input streams等來源中創建。在J2EE環境中,Java規則引擎的管理活動是應用服務器的一部分。因此一般規則庫跟服務器不在同一臺機器上,RuleExecutionSetProvider類可以從遠程的經過彙集和系列化的數據來源中獲取。

但一般情況而言,使用遠程規則引擎或遠程規則數據來源的情況並不多見,RuleExecutionSetProvider創建規則執行集會耗費較大的網絡開銷,所以一般使用的都是LocalRuleExecutionSetProvider類。

RuleAdministrator類:

四個方法:

java 代碼

  1. deregisterRuleExecutionSet(String, Map)   
  2. registerRuleExecutionSet(String, RuleExecutionSet, Map)   
  3. getRuleExecutionSetProvider(Map)   
  4. getLocalRuleExecutionSetProvider(Map)   

前面兩個方法是註冊執行集的,第一個參數是URI,作爲唯一標識。後面兩個是獲取遠程和本地的RuleExecutionSetProvider。

javax.rules.admin.Rule類

RuleExecutionSet類

這個類就是封裝了規則執行集,實例由RuleExecutionSetProvider的createRuleExecutionSet方法創建。

運行時API中比較常用的類有:

RuleServiceProviderManager類:這個類負責註冊RuleServiceProvider和獲取註冊的 RuleServiceProvider。分別見方法registerRuleServiceProvider(String, Class)/registerRuleServiceProvider(String, Class, ClassLoader)和getRuleServiceProvider(String)
註冊和獲取的方法,第一個參數都是RuleServiceProvider的唯一標識。

RuleServiceProvider類:主要的兩個方法getRuleAdministrator()和getRuleRuntime(),負責獲取RuleRuntime和RuleRuntime的實例。

RuleRuntime類:提供一個createRuleSession(String, Map, int)方法創建rule執行會話。第一個參數就是上面註冊RuleServiceProvider和RuleExecutionSet時候的uri,唯 一標識。擁有一個唯一標識的RuleServiceProvider和RuleExecutionSet,可以創建多個rule session。第三個參數是一個整數,它用於標示創建有狀態的還是無狀態的session。

StatefulRuleSession類和StatelessRuleSession類,這兩個類都繼承了RuleSession類,規則執行會 話主要維護規則的執行調用。無狀態會話的工作方式就像一個無狀態會話bean.客戶可以發送單個輸入對象或一列對象來獲得輸出對象.當客戶需要一個與規則 引擎間的專用會話時,有狀態會話就很有用.輸入的對象通過addObject() 方法可以加入到會話當中.同一個會話當中可以加入多個對象.對話中已有對象可以通過使用updateObject()方法得到更新。只要客戶與規則引擎間 的會話依然存在,會話中的對象就不會丟失。

RuleExecutionSetMetadata類:接口提供給客戶讓其查找規則執行集的元數據(metadata)。元數據通過規則會話接口(RuleSession Interface)提供給用戶。

總之,規則管理API主要提供裝載規則以及與規則對應的動作(執行集 execution sets)以及實例化規則引擎以及對執行集進行維護。規則可以從外部資源中裝載,比如說URI,Input streams, XML streams和readers等等。同時,規則引擎API提供了這樣一個機制,就是訪問RuleServiceProvider和 RuleExecutionSet的實例,兩者都必須先在服務器上註冊,然後才能根據註冊中使用的uri來獲取。這樣,有助於對客戶訪問運行規則進行控制 管理,它通過在執行集上定義許可權使得未經授權的用戶無法訪問受控規則。而運行時API是提供了一個對規則執行集訪問的機制,類似於JDBC的訪問方法。 類RuleServiceProvider提供了對具體規則引擎實現的運行時和管理API的訪問,將其規則引擎實現提供給客戶,並獲得 RuleServiceProvider唯一標識規則引擎的URI。

我們且看,一個規則實現的註冊,然後到客戶訪問和執行規則的步驟。

第一步:先實例化ruleServiceProvider,這個ruleServiceProvider,就是提供具體的規則引擎實現,不同的規則 引擎提供商有不同的provider。它的格式標準用法一般是例 如:com.mycompany.myrulesengine.rules.RuleServiceProvider,我使用blaze,因此代碼片斷如下:

java 代碼

  1. Class ruleServiceProviderClass = Class.forName(”com.blazesoft.server.deploy.javax.rules.base.NdRuleServiceProvider”);  

第二步:註冊ruleServiceProvider。上面說到,使用RuleServiceProviderManager,如下:

java 代碼

  1. RuleServiceProviderManager.registerRuleServiceProvider(uri,ruleServiceProviderClass);   

第三步:獲取剛纔註冊的ruleServiceProvider實例(上面說過,要使用ruleServiceProvider的實例,必須先註冊)

java 代碼

  1. RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(uri);  

第四步:獲取RuleAdministrator的實例,因爲註冊和管理規則執行集,都是在RuleAdministrator中進行的。

java 代碼

  1. RuleAdministrator ruleAdministrator = ruleServiceProvider.getRuleAdministrator();   

第五步:在Administrator實例中獲取rule execution set provider

java 代碼

  1. HashMap properties = new HashMap();   
  2.     properties.put(”name”, ”My Rules”);   
  3.     properties.put(”description”, ”A trivial rulebase”);   
  4.     FileReader reader = new FileReader(”rules.xml”);   
  5. RuleExecutionSetProvider ruleExecutionSetProvider ruleAdministrator.getRuleExecutionSetProvider(properties);   

第六步:通過rule execution set provider的實例創建RuleExecutionSet

java 代碼

  1. RuleExecutionSet res = resp.createRuleExecutionSet(reader, properties);   

第七步:註冊RuleExecutionSet。

java 代碼

  1. admin.registerRuleExecutionSet(uri, ruleSet, properties);   

下面是創建會話,然後執行規則集。
第八步:獲取RuleRuntime 的實例,然後根據RuleRuntime 的實例創建執行會話。

java 代碼

  1. RuleRuntime runtime = rsp.getRuleRuntime();   
  2. StatelessRuleSession session = (StatelessRuleSession)runtime.createRuleSession(uri, properties,RuleRuntime.STATELESS_SESSION_TYPE);   

最後:執行規則集,釋放會話資源。

java 代碼

  1. LinkedList list = new LinkedList();   
  2. list.add(oneObject);   
  3. list.add(anotherObject);   
  4. session.executeRules();   
  5.  List results = session.getObjects();   
  6. session.release();   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章