隨筆 - 19, 文章 - 93, 評論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          (七): Drools規(guī)則語言詳解(下)

          Drools規(guī)則語言詳解(下)

          5. Rule

          Figure?5.1.?rule

          Rule 結(jié)構(gòu)是最重要的結(jié)構(gòu)。 Rule 使用了形如“ IF something THEN action (當(dāng)然,我們的關(guān)鍵字是“ when ”和“ then ”)的形式。

          一個規(guī)則在一個 package 中必須要有唯一的名字。如果一個名字中含有空格,那就需要將名字放在雙引號中(最好總是使用雙引號)。

          Attribute 是可選的(最好是每行只有一個 Attribute )。

          規(guī)則的 LHS 跟在“ when ”關(guān)鍵字的后面(最好是另起一行),同樣 RHS 要跟在“ then ”關(guān)鍵字后面(最好也另起一行)。規(guī)則以關(guān)鍵字“ end ”結(jié)束。規(guī)則不能嵌套。

          5.1 Left Hand Side

          Left Hand Side 其實(shí)就是規(guī)則的條件部分。 LHS 對應(yīng)的 rail-road 圖如下,我們在后面會做進(jìn)一步解釋:


          Figure?5.2.?Left Hand Side


          Figure?5.3.?pattern

          5.2 Right Hand Side

          Right Hand Side RHS )就是規(guī)則的結(jié)果( consequence )或者動作( action )部分。 RHS 的目的是 retract add facts WorkingMemory 中,還有針對你的 application 的動作。實(shí)際上, RHS 是當(dāng)規(guī)則激發(fā)( fire )時執(zhí)行的代碼塊。

          RHS 中,你可以使用幾個方便的 method 來改變 WorkingMemory

          modify(obj) ”:告訴引擎一個對象已經(jīng)發(fā)生變化,規(guī)則必須重新匹配( obj 對象必須是出現(xiàn)在 LHS 中的對象);

          assert(new Something()) ”:將一個新的 Something 對象加入 WorkingMemory

          assertLogical(new Something()) ”:與 assert 方法類似。但是,當(dāng)沒有 fact 支持當(dāng)前激發(fā)規(guī)則的真實(shí)性的時候,這個新對象會自動被 retract

          retract(obj) ”:從 WorkingMemory 中移除一個對象。

          這些方法都是宏指令,提供了到 KnowledgeHelper 實(shí)例的快捷方式(參考 KnowledgeHelper 接口)。 KnowledgeHelper 接口可以在 RHS 代碼塊中調(diào)用,通過變量“ drools ”。如果你在 assert 進(jìn)引擎的 JavaBean 中加入“ Property Change Listener ”,在對象發(fā)生變化的時候,你就不用調(diào)用“ modify ”方法。

          5.3 Rule Attributes


          Figure?5.4.?rule attributes

          5.3.1 no-loop

          默認(rèn)值: false

          類型: boolean

          當(dāng)在 rule RHS 中修改了一個 fact ,這可能引起這個 rule 再次被 activate ,引起遞歸。將 no-loop 設(shè)為 true ,就可以防止這個 rule Activation 的再次被創(chuàng)建。

          5.3.2 salience

          默認(rèn)值: 0

          類型: int

          每個 rule 都可以設(shè)置一個 salience 整數(shù)值,默認(rèn)為 0 ,可以設(shè)為正整數(shù)或負(fù)整數(shù)。 Salience 是優(yōu)先級的一種形式。當(dāng)處于 Activation 隊(duì)列中時,擁有高 salience 值的 rule 將具有更高的優(yōu)先級。

          5.3.3 agenda-group

          默認(rèn)值: MAIN

          類型: String

          Agenda group 允許用戶對 Agenda 進(jìn)行分組,以提供更多的執(zhí)行控制。只有具有焦點(diǎn)的組中的 Activation 才會被激發(fā)( fire )。

          5.3.4 auto-focus

          默認(rèn)值: false

          類型: boolean

          當(dāng)一個規(guī)則被 activate (即 Activation 被創(chuàng)建了),如果這個 rule auto-focus 值為 true 并且這個 rule agenda-group 沒有焦點(diǎn),此時這個 Activation 會被給予焦點(diǎn),允許這個 Activation fire 的潛在可能。

          5.3.5 activation-group

          默認(rèn)值: N/A

          類型: String

          當(dāng)處于同一個 activation-group 中的第一個 Activation fire 后,這個 activation-group 中其余剩下的 Activation 都不會被 fire 。

          5.3.6 duration

          默認(rèn)值:沒有默認(rèn)值

          類型: long

          5.4 Column


          Figure?5.5.?Column

          Example?5.1.?Column

          Cheese(?)
          Cheese(?type?
          == ? " stilton " ,?price? < ? 10 ?)

          一個 Column 由一個類的一個或多個域約束構(gòu)成。第一個例子沒有約束,它將匹配 WorkingMemory 中所有的 Cheese 實(shí)例。第二個例子對于一個 Cheese 對象有兩個字面約束( Literal Constraints ),它們被用“,”號隔開,意味著“ and ”。


          Figure?5.6.?Bound Column

          Example?5.2.?Bound Column

          cheapStilton?:?Cheese(?type? == ? " stilton " ,?price? < ? 10 ?)
          <!--[if !supportEmptyParas]--> <!--[endif]-->

          這個例子同前一個例子有點(diǎn)類似。但是在這個例子中,我們將一個變量綁定到匹配規(guī)則引擎的 Cheese 實(shí)例上。這意味著,你可以在另一個條件中使用 cheapStilton ,或者在 rule RHS 中。

          5.4.1 Field Constraints

          Field Constraints 使規(guī)則引擎可以從 WorkingMemory 中挑選出合適的 Fact 對象。一個 Fact 的“ Field ”必須符合 JavaBean 規(guī)范,提供了訪問 field getter 方法。你可以使用 field 的名字直接訪問 field ,或者使用完整的方法名(省略括號)。

          例如,以我們的 Chess 類為例,下面是等價的: Cheese(type = = …) Cheese(getType = = …) 。這意味著,你可以使用不太嚴(yán)格遵守 JavaBean 規(guī)范對象。盡管如此,你要保證 accessor 方法是不帶參數(shù)的,以保證它不會改變對象的狀態(tài)。

          注意:如果一個 field 使用原始類型( primitive type ), Drools 將會把它們自動裝箱成相應(yīng)的對象(即使你使用 java 1.4 ),但是在 java 1.4 下卻不能自動拆箱。總的來說,盡量在 rule 所使用的類中,使用非原始類型的域。如果是使用 java 5 ,就可以比較隨意了,因?yàn)榫幾g器會幫你執(zhí)行自動裝拆箱。

          5.4.1.1 Operators


          Figure?5.7.?Operators

          有效的操作符是同域類型相關(guān)的。例如,對于日期域,“ < ”意味著“之前”。“ matches ”只適用于 String 域,“ contains ”和“ excludes ”只適用于 Collection 類型域。

          5.4.1.2 字面值約束( Literal Constraints

          最簡單的域約束就是字面值約束,允許用戶將一個 field 約束于一個已知值。

          注意:你可以檢查域是否為 null ,使用 = = != 操作符和字面值‘ null ’關(guān)鍵字。如, Cheese(type != null) 。字面值約束,特別是“ = = ”操作符,提供了非??斓膱?zhí)行速度,因?yàn)榭梢允褂蒙⒘蟹▉硖岣咝阅堋?/span>


          Figure?5.8.?Literal Constraints

          Numeric

          所有標(biāo)準(zhǔn)的 Java 數(shù)字基本類型都可以用。

          有效操作符:

          <!--[if !supportLists]--> ·???????? <!--[endif]--> ==

          <!--[if !supportLists]--> ·???????? <!--[endif]--> !=

          <!--[if !supportLists]--> ·???????? <!--[endif]--> >

          <!--[if !supportLists]--> ·???????? <!--[endif]--> <

          <!--[if !supportLists]--> ·???????? <!--[endif]--> >=

          <!--[if !supportLists]--> ·???????? <!--[endif]--> <=

          Example?5.3 .?Numeric Literal Constraint
          Cheese(?quantity? == ? 5 ?)

          Date

          當(dāng)前只對“ dd-mm-yyyy ”的日期格式提供默認(rèn)支持。你可以通過指定 drools.dateformat 系統(tǒng)屬性,來改變默認(rèn)的日期格式。如果需要更多的控制,要用謂詞約束( Predicate Constraint )。

          有效操作符:

          <!--[if !supportLists]--> ·???????? <!--[endif]--> ==

          <!--[if !supportLists]--> ·???????? <!--[endif]--> !=

          <!--[if !supportLists]--> ·???????? <!--[endif]--> >

          <!--[if !supportLists]--> ·???????? <!--[endif]--> <

          <!--[if !supportLists]--> ·???????? <!--[endif]--> >=

          <!--[if !supportLists]--> ·???????? <!--[endif]--> <=

          Example?5.4.?Date Literal Constraint
          Cheese(?bestBefore? < ? " 27-Oct-2007 " ?)

          String

          可以使用任何有效的 Java String

          有效操作符:

          <!--[if !supportLists]--> ·???????? <!--[endif]--> ==

          <!--[if !supportLists]--> ·???????? <!--[endif]--> !=

          Example?5.5.?String Literal Constraint
          Cheese(?type? == ? " stilton " ?)

          Boolean

          只能用 true ”或“ false ”。 0 1 不能被識別,而且 Cheese(smelly) 也是不被允許的。

          有效操作符:

          <!--[if !supportLists]--> ·???????? <!--[endif]--> ==

          <!--[if !supportLists]--> ·???????? <!--[endif]--> !=

          Example?5.6?Boolean Literal Constraint
          Cheese(?smelly? = ? = ? true ?)

          Matches Operator

          Matches 操作符后面可以跟任何有效的 Java 正則表達(dá)式。

          Example?5.7.?Regular Expression Constraint
          Cheese(?type?matches? " (Buffulo)?\\S*Mozerella " ?)

          Contains Operator and Excludes Operator

          contains ”和“ excludes ”可以用來檢查一個 Collection 域是否含有一個對象。

          Example?5.8.?Literal Cosntraints with Collections
          CheeseCounter(?cheeses?contains? " stilton " ?)
          CheeseCounter(?cheeses?excludes?
          " chedder " ?)

          5.4.1.3 Bound Variable Constraint

          可以將 Facts 和它們的 Fields 附給一個 Bound Variable ,然后在后續(xù)的 Field Constraints 中使用這些 Bound Variable 。一個 Bound Variable 被稱為聲明( Declaration )。 Declaration 并不能和“ matches ”操作符合用,但卻可以和“ contains ”操作符合用。

          Example?5.9.?Bound Field using '==' operator
          Person(?likes?:?favouriteCheese?)
          Cheese(?type?
          == ?likes?)

          在上面的例子中,“ likes ”就是我們的 Bound Variable ,即 Declaration 。它被綁定到了任何正在匹配的 Person 實(shí)例的 favouriteCheese 域上,并且用來在下一個 Column 中約束 Cheese type 域??梢允褂盟杏行У?/span> Java 變量名,包括字符“ $ ”。“ $ ”經(jīng)??梢詭椭銋^(qū)分 Declaration field 。下面的例子將一個 Declaration 綁定到匹配的實(shí)例上,并且使用了“ contains ”操作符。注意: Declaratino 的第一個字符用了“ $ ”:

          Example?5.10?Bound Fact using 'contains' operator

          $stilton?:?Cheese(?type? == ? " stilton " ?)
          Cheesery(?cheeses?contains?$stilton?)

          5.4.1.4 Predicate Constraints



          Figure?5.9.?Predicate expression

          Predicate 表達(dá)式可以使用任何有效的 Java 邏輯表達(dá)式。先前的 Bound Declaration 可以用在表達(dá)式中。

          下面的例子將會找出所有男性比女性大 2 歲的 pairs of male/femal people

          Example?5.11. Predicate Constraints

          Person(?girlAge?:?age,?sex? = ? = ? " F " ?)
          Person(?boyAge?:?age?
          -> ?(?girlAge.intValue()? + ? 2 ? == ?boyAge.intValue()?),?sex? = ? = ? " M " ?)

          5.4.1.5 Return Value Constraints



          Figure?5.10.?Return Value expression

          一個 Retrurn Value 表達(dá)式可以使用任何有效的 Java 表達(dá)式,只要它返回一個對象,不能返回原始數(shù)據(jù)類型。如果返回值是原始數(shù)據(jù)類型,要先進(jìn)行裝箱。先前的 Bound Declaration 也可以使用在表達(dá)式中。

          下面的例子跟上一節(jié)的例子一樣,也將會找出所有男性比女性大 2 歲的 pairs of male/femal people 。注意:這里我們不用綁定 boyAge ,增加了可讀性:

          Example?5.12.?Return Value Constraints
          Person(?girlAge?:?age,?sex? = ? = ? " F " ?)
          Person(?age?
          = ? = ?(? new ?Integer(girlAge.intValue()? + ? 2 )?),?sex? = ? = ? " M " ?)

          5.5 Conditional Elements

          Conditional Elements 用來連接一個或多個 Columns 。

          5.5.1 and

          Figure?5.11.?and

          Example?5.13. ?And
          Cheese(?cheeseType?:?type?)? && ?Person(?favouriteCheese? == ?cheeseType?)
          Cheese(?cheeseType?:?type?)?and?Person(?favouriteCheese?
          == ?cheeseType?)

          5.5.2 or


          Figure?5.12.?or
          Example?5.14.?or
          Person(?sex? == ? " f " ,?age? > ? 60 ?)? || ?Person(?sex? == ? " m " ,?age? > ? 65 ?)
          Person(?sex?
          == ? " f " ,?age? > ? 60 ?)?or?Person(?sex? == ? " m " ,?age? > ? 65 ?)



          Figure?5.13.?or with binding

          Example?5.15.?or with binding
          pensioner?:?Person(?sex? == ? " f " ,?age? > ? 60 ?)? || ?pensioner?:?Person(?sex? == ? " m " ,?age? > ? 65 ?)?
          pensioner?:?(?Person(?sex?
          == ? " f " ,?age? > ? 60 ?)?or?Person(?sex? == ? " m " ,?age? > ? 65 ?)?)

          or Conditional Element 的使用會導(dǎo)致多條 rule 的產(chǎn)生,稱為 sub rules 。上面的例子將在內(nèi)部產(chǎn)生兩條規(guī)則。這兩條規(guī)則會在 WorkingMemory 中各自獨(dú)立的工作,也就是它們都能進(jìn)行 match , activate fire 。當(dāng)對一個“ or Conditional Element 使用變量綁定時,要特別小心,錯誤的使用將產(chǎn)生完全不可預(yù)期的結(jié)果。

          可以將“ OR Conditional Element 理解成產(chǎn)生兩條規(guī)則的快捷方式。因此可以很容易理解,當(dāng)“ OR Conditional Element 兩邊都為真時,這樣的一條規(guī)則將可能產(chǎn)生多個 activation 。

          5.5.3 eval


          Figure?5.14 .?eval

          Eval is essentially a catch all which allows any semantic code (that returns a primitive boolean) to be executed. 在表達(dá)式中可以引用在 LHS 中出現(xiàn)的變量,和在 rule package 中的 Functions 。一個 Eval 應(yīng)該是 LHS 中的最后一個 Conditional Element 。在一個 rule 中,你可以有多個 eval

          Eval 不能被索引,因此不能像 Field Constraints 那樣被優(yōu)化。盡管如此,當(dāng) Functions 的返回值一直在變化時,應(yīng)該使用 Eval ,因?yàn)檫@在 Field Constraints 中時不允許的。如果規(guī)則中的其他條件都匹配,一個 eval 每次都要被檢查。(現(xiàn)在還不理解到底 eval 要怎么用?)

          Example?5.16.?eval

          p1?:?Parameter()?
          p2?:?Parameter()
          eval(?p1.getList().containsKey(p2.getItem())?)
          eval(?isValid(p1,?p2)?)?
          // this?is?how?you?call?a?function?in?the?LHS?-?a?function?called? // "isValid"

          5.5.4 not


          Figure?5.15.?not

          not ”是一階邏輯的存在量詞( first order logic’s Existential Quantifier , 用來檢查 WorkingMemory 中某對象的非存在性?,F(xiàn)在,只有 Columns 可以放在 not 中,但是將來的版本會支持“ and ”和“ or ”。

          Example?5.17.?No Buses

          not?Bus()

          Example?5.18.?No red Buses

          not?Bus(color? == ? " red " )
          not?(?Bus(color?
          == ? " red " ,?number? = ? = ? 42 )?)? // brackets?are?optional

          5.5.5 exists


          Figure?5.16.?exists

          exists 是一階邏輯的存在量詞( first order logic’s Existential Quantifier ),用來檢查 WorkingMemory 中某對象的存在性。可以將“ exists ”理解為“至少有一個”( at least one… )。它的意義不同于只有 Column 本身,“ Column ”本身可以理解為“對于每一個 ”( for each of … )。如果你對一個 Column 使用了“ exists ”,那么規(guī)則將只 activate 一次,而不管 WorkingMeomry 中有多少個數(shù)據(jù)匹配了那個條件。

          現(xiàn)在,只有 Columns 可以放在“ exists ”中,但是將來的版本會支持“ and ”和“ or ”。

          Example?5.19.?At least one Bus

          exists?Bus()

          Example?5.20.?At least one red Bus

          exists?Bus(color? == ? " red " )

          5.5.6 group


          Figure?5.17.?group

          Group 的作用相當(dāng)于代數(shù)學(xué)中的“()”,顯式的指明操作的順序。

          5.6 再談自動裝箱和原始類型

          Java 5 支持在原始類型與其對應(yīng)包裝類之間的裝拆箱。盡管如此,因?yàn)橐?/span> drools 能夠在 J2SE 1.4 下運(yùn)行,我們不能依靠 J2SE 。因此, drools 自己實(shí)現(xiàn)了自動裝箱。被引用(即被 Bound Variable 綁定)的 Field 將被自動進(jìn)行裝箱(如果它們本身就是 object ,就不會有任何變化)。盡管如此,必須要注意的是,他們并不會被自動拆箱。

          還有一點(diǎn)要注意的,就是對于 ReturnValue Constraints ,返回值的代碼必須返回一個對象,而不能是一個原始類型。

          6 Query


          Figure?6.1 .?query

          一個 query 只包含了一個 rule LHS 結(jié)構(gòu)(你不用指定“ when ”或“ then ”)。這是查詢 WorkingMemory 中匹配條件的 Facts 的簡單的方法。

          要得到結(jié)果,要使用 WorkingMemory.getQueryResults(“name”) 方法,其中“ name ”就是 query 的名字。 Query 的名字在 RuleBase 中是全局的,所以, do not add queries of the same name to different packages for the same RuleBase

          下面的例子創(chuàng)建了一個簡單的 query 來查詢所有年齡大于 30 的人:

          Example?6.1.?Query People over the age of 30
          ?
          query?"people?over?the?age?of?30"?
          ????person?:?Person(?age?
          >?30?)
          end

          我們通過一個標(biāo)準(zhǔn)的循環(huán)來迭代一個返回的QueryResults對象。每一次的iterate將返回一個QueryResult對象。我們可以用QueryResult對象的get()方法來訪問每個Column,通過傳入Bound Declarationindex position。

          Example?6.2.?Query People over the age of 30

          QueryResults?results?=?workingMemory.getQueryResults(?"people?over?the?age?of?30"?);
          System.out.println(?
          "we?have?"?+?results.size()?+?"?people?over?the?age??of?30"?);

          System.out.println(?
          "These?people?are?are?over?30:"?);

          for?(?Iterator?it?=?results.iterator;?it.hasNext();?)?{
          ????QueryResult?result?
          =?(?QueryResult?)?it.next();
          ????Person?person?
          =?(?Person?)?result.get(?"person"?);
          ????System.out.println(?person.getName()?
          +?"\n"?);
          }

          posted on 2006-12-03 09:56 BPM 閱讀(1515) 評論(0)  編輯  收藏 所屬分類: 規(guī)則引擎

          主站蜘蛛池模板: 保德县| 若羌县| 静宁县| 嘉义县| 繁峙县| 盐城市| 普兰店市| 乐都县| 竹北市| 南投市| 凉山| 田阳县| 华亭县| 大姚县| 商都县| 乌鲁木齐市| 华容县| 来凤县| 吕梁市| 云阳县| 山阴县| 那坡县| 米泉市| 长乐市| 宁明县| 墨江| 棋牌| 建湖县| 平阳县| 武宁县| 错那县| 延长县| 尉犁县| 陕西省| 渭源县| 田林县| 三明市| 奈曼旗| 牟定县| 常熟市| 张北县|