Drools 规则语言详解(上)
?http://www.blogjava.net/guangnian0412/archive/2006/06/09/51574.html
?
http://www.blogjava.net/guangnian0412/archive/2006/06/09/51756.html
Drools 規(guī)則語言詳解(上)<!--[if !supportLists]--> 1.? <!--[endif]--> 概述:
Drools 3 采用了原生的規(guī)則語言,那是一種非 XML 文本格式。在符號(hào)方面,這種格式是非常輕量的,并且通過“ expanders ”支持符合你問題域的 Domain Specific Language ( DSL )。這一章把焦點(diǎn)放在了 Drools 原生的規(guī)則格式。如果你想從技術(shù)上了解規(guī)則語言的機(jī)制,可以參考“ drl.g ”源文件,這是用 Antlr3 語法來描述規(guī)則語言。如果你使用 Rule Workbench ,內(nèi)容助手將會(huì)為你完成大量的規(guī)則結(jié)構(gòu),例如輸入“ ru ”,然后按 ctrl + space ,會(huì)為你建立規(guī)則結(jié)構(gòu)。<!--[if !supportLists]--> 1.1??? <!--[endif]--> 規(guī)則文件
一個(gè)規(guī)則文件通常是一個(gè)以 .drl 擴(kuò)展名結(jié)尾的文件。在一個(gè) drl 文件中,你可以有多條 rules , functions 等等。盡管如此,你也可以將你的規(guī)則分布在多個(gè)文件中,這有利于管理大量的規(guī)則。一個(gè) DRL 文件是一個(gè)簡(jiǎn)單的文本文件。
1.2 規(guī)則的結(jié)構(gòu)
一個(gè)規(guī)則結(jié)構(gòu)大致如下:
rule? " name "????ATTRIBUTES
????when
????????LHS
????then
????????RHS
end
可以看到,這是非常簡(jiǎn)單的。通常的標(biāo)點(diǎn)符號(hào)都是不需要的,甚至連“ name ”的雙引號(hào)都是不需要的。 ATTRIBUTES 是簡(jiǎn)單的,也是可選的,來提示規(guī)則的行為方式。 LHS 是規(guī)則的條件部分,需要按照一定的語法來寫。 RHS 基本上是一個(gè)允許執(zhí)行 Java 語法的代碼的塊(以后將會(huì)支持 groovy 和 C #)。任何在 LHS 中使用的變量都可以在 RHS 中使用。
注意:每行開始的空格是不重要的,除非在 DSL ( Domain Specific Language )語言中有特別的指明。
<!--[if !supportLists]--> 1.3?? <!--[endif]--> Domain Specific Language
Domain Specific Language 是對(duì)原生規(guī)則語言的加強(qiáng)。它們使用“ expander ”機(jī)制。 Expander 機(jī)制是一種可擴(kuò)展的 API 。你可以使用 .dsl 文件,來提供從域或自然語言到規(guī)則語言和你的域?qū)ο蟮挠成洹D憧梢詫?.dsl 文件看成是對(duì)你的域模型的映射。 DSL 提供了更高的規(guī)則可讀性,你可以選擇使用你自己創(chuàng)建的 DSL ,或者是原生的規(guī)則語言。
1.4 保留字
在規(guī)則語言中存在一些保留字。你應(yīng)該避免使用這些保留字,來命名規(guī)則文本中的域?qū)ο?#xff0c;屬性,方法,功能。保留字如下: when , then , rule , end , contains , matches , and , or , modify , retract , assert , salience , function , query , exists , eval , agenda-group , no-loop , duration , -> , not , auto-focus 。<!--[if !supportLists]--> 2. ? <!--[endif]--> 注釋
2.1 單行注釋:Figure?2.1.?Single line comment
2.2 多行注釋:
Figure?2.2.?Multi line comment
<!--[if !supportLists]-->
3. ??? <!--[endif]--> Package
一個(gè)包是 rule 和其他相關(guān)結(jié)構(gòu),像 import 和 global 的集合。 Package 的成員之間通常都是相關(guān)聯(lián)的。一個(gè) Package 代表了一個(gè)命名空間( namespace ),用來使給定的規(guī)則組之間保持唯一性。 Package 的名字本身就是命名空間,并且與文件或文件夾并無關(guān)聯(lián)。
<!--[if !supportEmptyParas]-->
可以將來自不同規(guī)則源的規(guī)則裝配在一起,前提是這些規(guī)則必須處在同一個(gè)命名空間中。盡管如此,一個(gè)通常的結(jié)構(gòu)是將處于同一個(gè)命名空間中的所有規(guī)則都放在同一個(gè)相同的文件中。
下面的 rail-road 圖顯示了組成一個(gè) Package 的所有組件。注意:一個(gè) package 必須有一個(gè)命名空間,并且采用 Java 包名的約定。在一個(gè)規(guī)則文件中,各組件出現(xiàn)的位置是任意的,除了“ package ”和“ expander ”語句必須出現(xiàn)在任何一個(gè)規(guī)則之前,放在文件的頂部。在任何情況下,分號(hào)都是可選的。
Figure?3.1.?package
3.1 import
Figure?3.2.?import
Import 語句的使用很像 Java 中的 import 語句。你需要為你要在規(guī)則中使用的對(duì)象,指定完整的路徑和類名。 Drools 自動(dòng)從相同命名的 java 包中引入所需的類。
3.2 expander
Figure?3.3.?expander
expander 語句是可選的,是用來指定 Domain Specific Language 的配置(通常是一個(gè) .dsl 文件)。這使得解析器可以理解用你自己的 DSL 語言所寫的規(guī)則。
3.3 globalFigure?3.4.?global
Global 就是全局變量。如果多個(gè) package 聲明了具有相同標(biāo)識(shí)符的 global ,那么它們必需是相同的類型,并且所有的引用都是相同的。它們通常用來返回?cái)?shù)據(jù),比如 actions 的日志,或者為 rules 提供所需的數(shù)據(jù)或服務(wù)。 global 并不是通過 assert 動(dòng)作放入 WorkingMemory 的,所有當(dāng) global 發(fā)生改變時(shí),引擎將不會(huì)知道。所以, global 不能作為約束條件,除非它們的值是 final 的。將 global 錯(cuò)誤的使用在約束條件中,會(huì)產(chǎn)生令人驚訝的錯(cuò)誤結(jié)果。
<!--[if !supportEmptyParas]-->
注意: global 只是從你的 application 中傳入 WorkingMemory 的對(duì)象的命名實(shí)例。這意味著你可以傳入任何你想要的對(duì)象。你可以傳入一個(gè) service locator ,或者是一個(gè) service 本身。
<!--[if !supportEmptyParas]-->
下面的例子中,有一個(gè) EmailService 的實(shí)例。在你調(diào)用規(guī)則引擎的代碼中,你有一個(gè) EmailService 對(duì)象,然后把它放入 WorkingMemory 。在 DRL 文件中,你聲明了一個(gè)類型為 EmailService 的 global ,然后將它命名為“ email ”,像這樣: global EmailService email ;。然后在你的規(guī)則的 RHS 中,你可以使用它,像這樣: email.sendSMS(number,message) 等等。
4. Function
Figure?4.1.?function
Function 是將代碼放到你的規(guī)則源中的一種方法。它們只能做類似 Helper 類做的事(實(shí)際上編譯器在背后幫你生成了 Helper 類)。在一個(gè) rule 中使用 function 的主要優(yōu)勢(shì)是,你可以保持所有的邏輯都在一個(gè)地方,并且你可以根據(jù)需要來改變 function (這可能是好事也可能是壞事)。 Function 最有用的就是在規(guī)則的 RHS 調(diào)用 actions ,特別是當(dāng)那個(gè) action 需要反復(fù)調(diào)用的時(shí)候。
<!--[if !supportEmptyParas]-->
一個(gè)典型的 function 聲明如下:
function?String?calcSomething(String?arg)?{return ? " hola?! " ;
}
<!--[if !supportEmptyParas]-->
注意:“ function ”關(guān)鍵字的使用,它并不真正是 Java 的一部分。而 function 的參數(shù)就像是一個(gè)普通的 method (如果不需要參數(shù)就不用寫)。返回類型也跟普通的 method 一樣。在一條規(guī)則(在它的 RHS 中,或可能是一個(gè) eval )中調(diào)用 function ,就像調(diào)用一個(gè) method 一樣,只需要 function 的名字,并傳給它參數(shù)。
<!--[if !supportEmptyParas]-->
function 的替代品,可以使用一個(gè) Helper 類中的靜態(tài)方法: Foo.doSomething() ,或者以 global 的方式傳入一個(gè) Helper 類或服務(wù)的實(shí)例: foo.doSomething() ( foo 是一個(gè)命名的 global 變量)。
<!--[if !supportEmptyParas]-->
?
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 ”)的形式。
一個(gè)規(guī)則在一個(gè) package 中必須要有唯一的名字。如果一個(gè)名字中含有空格,那就需要將名字放在雙引號(hào)中(最好總是使用雙引號(hào))。
Attribute 是可選的(最好是每行只有一個(gè) 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 對(duì)應(yīng)的 rail-road 圖如下,我們?cè)诤竺鏁?huì)做進(jìn)一步解釋:
Figure?5.3.?pattern
5.2 Right Hand Side
Right Hand Side ( RHS )就是規(guī)則的結(jié)果( consequence )或者動(dòng)作( action )部分。 RHS 的目的是 retract 或 add facts 到 WorkingMemory 中,還有針對(duì)你的 application 的動(dòng)作。實(shí)際上, RHS 是當(dāng)規(guī)則激發(fā)( fire )時(shí)執(zhí)行的代碼塊。在 RHS 中,你可以使用幾個(gè)方便的 method 來改變 WorkingMemory :
“ modify(obj) ”:告訴引擎一個(gè)對(duì)象已經(jīng)發(fā)生變化,規(guī)則必須重新匹配( obj 對(duì)象必須是出現(xiàn)在 LHS 中的對(duì)象);
“ assert(new Something()) ”:將一個(gè)新的 Something 對(duì)象加入 WorkingMemory ;
“ assertLogical(new Something()) ”:與 assert 方法類似。但是,當(dāng)沒有 fact 支持當(dāng)前激發(fā)規(guī)則的真實(shí)性的時(shí)候,這個(gè)新對(duì)象會(huì)自動(dòng)被 retract ,
“ retract(obj) ”:從 WorkingMemory 中移除一個(gè)對(duì)象。
這些方法都是宏指令,提供了到 KnowledgeHelper 實(shí)例的快捷方式(參考 KnowledgeHelper 接口)。 KnowledgeHelper 接口可以在 RHS 代碼塊中調(diào)用,通過變量“ drools ”。如果你在 assert 進(jìn)引擎的 JavaBean 中加入“ Property Change Listener ”,在對(duì)象發(fā)生變化的時(shí)候,你就不用調(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 中修改了一個(gè) fact ,這可能引起這個(gè) rule 再次被 activate ,引起遞歸。將 no-loop 設(shè)為 true ,就可以防止這個(gè) rule 的 Activation 的再次被創(chuàng)建。
5.3.2 salience默認(rèn)值: 0
類型: int
每個(gè) rule 都可以設(shè)置一個(gè) salience 整數(shù)值,默認(rèn)為 0 ,可以設(shè)為正整數(shù)或負(fù)整數(shù)。 Salience 是優(yōu)先級(jí)的一種形式。當(dāng)處于 Activation 隊(duì)列中時(shí),擁有高 salience 值的 rule 將具有更高的優(yōu)先級(jí)。
5.3.3 agenda-group默認(rèn)值: MAIN
類型: String
Agenda group 允許用戶對(duì) Agenda 進(jìn)行分組,以提供更多的執(zhí)行控制。只有具有焦點(diǎn)的組中的 Activation 才會(huì)被激發(fā)( fire )。
5.3.4 auto-focus默認(rèn)值: false
類型: boolean
當(dāng)一個(gè)規(guī)則被 activate (即 Activation 被創(chuàng)建了),如果這個(gè) rule 的 auto-focus 值為 true 并且這個(gè) rule 的 agenda-group 沒有焦點(diǎn),此時(shí)這個(gè) Activation 會(huì)被給予焦點(diǎn),允許這個(gè) Activation 有 fire 的潛在可能。
5.3.5 activation-group默認(rèn)值: N/A
類型: String
當(dāng)處于同一個(gè) activation-group 中的第一個(gè) Activation fire 后,這個(gè) activation-group 中其余剩下的 Activation 都不會(huì)被 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 ?)
一個(gè) Column 由一個(gè)類的一個(gè)或多個(gè)域約束構(gòu)成。第一個(gè)例子沒有約束,它將匹配 WorkingMemory 中所有的 Cheese 實(shí)例。第二個(gè)例子對(duì)于一個(gè) Cheese 對(duì)象有兩個(gè)字面約束( Literal Constraints ),它們被用“,”號(hào)隔開,意味著“ and ”。
Example?5.2.?Bound Column
cheapStilton?:?Cheese(?type? == ? " stilton " ,?price? < ? 10 ?) <!--[if !supportEmptyParas]--> <!--[endif]-->
這個(gè)例子同前一個(gè)例子有點(diǎn)類似。但是在這個(gè)例子中,我們將一個(gè)變量綁定到匹配規(guī)則引擎的 Cheese 實(shí)例上。這意味著,你可以在另一個(gè)條件中使用 cheapStilton ,或者在 rule 的 RHS 中。
5.4.1 Field Constraints
Field Constraints 使規(guī)則引擎可以從 WorkingMemory 中挑選出合適的 Fact 對(duì)象。一個(gè) Fact 的“ Field ”必須符合 JavaBean 規(guī)范,提供了訪問 field 的 getter 方法。你可以使用 field 的名字直接訪問 field ,或者使用完整的方法名(省略括號(hào))。
例如,以我們的 Chess 類為例,下面是等價(jià)的: Cheese(type = = …) 和 Cheese(getType = = …) 。這意味著,你可以使用不太嚴(yán)格遵守 JavaBean 規(guī)范對(duì)象。盡管如此,你要保證 accessor 方法是不帶參數(shù)的,以保證它不會(huì)改變對(duì)象的狀態(tài)。
注意:如果一個(gè) field 使用原始類型( primitive type ), Drools 將會(huì)把它們自動(dòng)裝箱成相應(yīng)的對(duì)象(即使你使用 java 1.4 ),但是在 java 1.4 下卻不能自動(dòng)拆箱。總的來說,盡量在 rule 所使用的類中,使用非原始類型的域。如果是使用 java 5 ,就可以比較隨意了,因?yàn)榫幾g器會(huì)幫你執(zhí)行自動(dòng)裝拆箱。
5.4.1.1 OperatorsFigure?5.7.?Operators
有效的操作符是同域類型相關(guān)的。例如,對(duì)于日期域,“ < ”意味著“之前”。“ matches ”只適用于 String 域,“ contains ”和“ excludes ”只適用于 Collection 類型域。
5.4.1.2 字面值約束( Literal Constraints )最簡(jiǎn)單的域約束就是字面值約束,允許用戶將一個(gè) field 約束于一個(gè)已知值。
注意:你可以檢查域是否為 null ,使用 = = 或 != 操作符和字面值‘ null ’關(guān)鍵字。如, Cheese(type != null) 。字面值約束,特別是“ = = ”操作符,提供了非常快的執(zhí)行速度,因?yàn)榭梢允褂蒙⒘蟹▉硖岣咝阅堋?
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 ConstraintCheese(?quantity? == ? 5 ?)
Date
當(dāng)前只對(duì)“ 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 ConstraintCheese(?bestBefore? < ? " 27-Oct-2007 " ?)
String
可以使用任何有效的 Java String 。
有效操作符:
<!--[if !supportLists]--> ·???????? <!--[endif]--> ==
<!--[if !supportLists]--> ·???????? <!--[endif]--> !=
Example?5.5.?String Literal ConstraintCheese(?type? == ? " stilton " ?)
Boolean
只能用 “ true ”或“ false ”。 0 和 1 不能被識(shí)別,而且 Cheese(smelly) 也是不被允許的。
有效操作符:
<!--[if !supportLists]--> ·???????? <!--[endif]--> ==
<!--[if !supportLists]--> ·???????? <!--[endif]--> !=
Example?5.6?Boolean Literal ConstraintCheese(?smelly? = ? = ? true ?)
Matches Operator
Matches 操作符后面可以跟任何有效的 Java 正則表達(dá)式。
Example?5.7.?Regular Expression ConstraintCheese(?type?matches? " (Buffulo)?\\S*Mozerella " ?)
Contains Operator and Excludes Operator
“ contains ”和“ excludes ”可以用來檢查一個(gè) Collection 域是否含有一個(gè)對(duì)象。
Example?5.8.?Literal Cosntraints with Collections CheeseCounter(?cheeses?contains? " stilton " ?)CheeseCounter(?cheeses?excludes? " chedder " ?)
5.4.1.3 Bound Variable Constraint
可以將 Facts 和它們的 Fields 附給一個(gè) Bound Variable ,然后在后續(xù)的 Field Constraints 中使用這些 Bound Variable 。一個(gè) Bound Variable 被稱為聲明( Declaration )。 Declaration 并不能和“ matches ”操作符合用,但卻可以和“ contains ”操作符合用。
Example?5.9.?Bound Field using '==' operatorPerson(?likes?:?favouriteCheese?)
Cheese(?type? == ?likes?)
在上面的例子中,“ likes ”就是我們的 Bound Variable ,即 Declaration 。它被綁定到了任何正在匹配的 Person 實(shí)例的 favouriteCheese 域上,并且用來在下一個(gè) Column 中約束 Cheese 的 type 域。可以使用所有有效的 Java 變量名,包括字符“ $ ”。“ $ ”經(jīng)常可以幫助你區(qū)分 Declaration 和 field 。下面的例子將一個(gè) Declaration 綁定到匹配的實(shí)例上,并且使用了“ contains ”操作符。注意: Declaratino 的第一個(gè)字符用了“ $ ”:
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á)式中。
下面的例子將會(huì)找出所有男性比女性大 2 歲的 pairs of male/femal people :
Person(?boyAge?:?age? -> ?(?girlAge.intValue()? + ? 2 ? == ?boyAge.intValue()?),?sex? = ? = ? " M " ?)
5.4.1.5 Return Value Constraints
Figure?5.10.?Return Value expression
一個(gè) Retrurn Value 表達(dá)式可以使用任何有效的 Java 表達(dá)式,只要它返回一個(gè)對(duì)象,不能返回原始數(shù)據(jù)類型。如果返回值是原始數(shù)據(jù)類型,要先進(jìn)行裝箱。先前的 Bound Declaration 也可以使用在表達(dá)式中。
下面的例子跟上一節(jié)的例子一樣,也將會(huì)找出所有男性比女性大 2 歲的 pairs of male/femal people 。注意:這里我們不用綁定 boyAge ,增加了可讀性:
Example?5.12.?Return Value ConstraintsPerson(?girlAge?:?age,?sex? = ? = ? " F " ?)
Person(?age? = ? = ?(? new ?Integer(girlAge.intValue()? + ? 2 )?),?sex? = ? = ? " M " ?)
5.5 Conditional Elements
Conditional Elements 用來連接一個(gè)或多個(gè) 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 的使用會(huì)導(dǎo)致多條 rule 的產(chǎn)生,稱為 sub rules 。上面的例子將在內(nèi)部產(chǎn)生兩條規(guī)則。這兩條規(guī)則會(huì)在 WorkingMemory 中各自獨(dú)立的工作,也就是它們都能進(jìn)行 match , activate 和 fire 。當(dāng)對(duì)一個(gè)“ or ” Conditional Element 使用變量綁定時(shí),要特別小心,錯(cuò)誤的使用將產(chǎn)生完全不可預(yù)期的結(jié)果。
可以將“ OR ” Conditional Element 理解成產(chǎn)生兩條規(guī)則的快捷方式。因此可以很容易理解,當(dāng)“ OR ” Conditional Element 兩邊都為真時(shí),這樣的一條規(guī)則將可能產(chǎn)生多個(gè) 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 。一個(gè) Eval 應(yīng)該是 LHS 中的最后一個(gè) Conditional Element 。在一個(gè) rule 中,你可以有多個(gè) eval 。
Eval 不能被索引,因此不能像 Field Constraints 那樣被優(yōu)化。盡管如此,當(dāng) Functions 的返回值一直在變化時(shí),應(yīng)該使用 Eval ,因?yàn)檫@在 Field Constraints 中時(shí)不允許的。如果規(guī)則中的其他條件都匹配,一個(gè) eval 每次都要被檢查。(現(xiàn)在還不理解到底 eval 要怎么用?)
Example?5.16.?evalp1?:?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 中某對(duì)象的非存在性。現(xiàn)在,只有 Columns 可以放在 not 中,但是將來的版本會(huì)支持“ and ”和“ or ”。
Example?5.17.?No Busesnot?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 中某對(duì)象的存在性。可以將“ exists ”理解為“至少有一個(gè)”( at least one… )。它的意義不同于只有 Column 本身,“ Column ”本身可以理解為“對(duì)于每一個(gè) … ”( for each of … )。如果你對(duì)一個(gè) Column 使用了“ exists ”,那么規(guī)則將只 activate 一次,而不管 WorkingMeomry 中有多少個(gè)數(shù)據(jù)匹配了那個(gè)條件。
現(xiàn)在,只有 Columns 可以放在“ exists ”中,但是將來的版本會(huì)支持“ and ”和“ or ”。
Example?5.19.?At least one Busexists?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 再談自動(dòng)裝箱和原始類型
Java 5 支持在原始類型與其對(duì)應(yīng)包裝類之間的裝拆箱。盡管如此,因?yàn)橐?drools 能夠在 J2SE 1.4 下運(yùn)行,我們不能依靠 J2SE 。因此, drools 自己實(shí)現(xiàn)了自動(dòng)裝箱。被引用(即被 Bound Variable 綁定)的 Field 將被自動(dòng)進(jìn)行裝箱(如果它們本身就是 object ,就不會(huì)有任何變化)。盡管如此,必須要注意的是,他們并不會(huì)被自動(dòng)拆箱。
還有一點(diǎn)要注意的,就是對(duì)于 ReturnValue Constraints ,返回值的代碼必須返回一個(gè)對(duì)象,而不能是一個(gè)原始類型。
6 . Query
Figure?6.1 .?query
一個(gè) query 只包含了一個(gè) rule 的 LHS 結(jié)構(gòu)(你不用指定“ when ”或“ then ”)。這是查詢 WorkingMemory 中匹配條件的 Facts 的簡(jiǎn)單的方法。
要得到結(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)建了一個(gè)簡(jiǎn)單的 query 來查詢所有年齡大于 30 的人:
Example?6.1.?Query People over the age of 30?
query?"people?over?the?age?of?30"?
????person?:?Person(?age?>?30?)
end
我們通過一個(gè)標(biāo)準(zhǔn)的循環(huán)來迭代一個(gè)返回的QueryResults對(duì)象。每一次的iterate將返回一個(gè)QueryResult對(duì)象。我們可以用QueryResult對(duì)象的get()方法來訪問每個(gè)Column,通過傳入Bound Declaration或index position。
Example?6.2.?Query People over the age of 30QueryResults?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"?);
}
總結(jié)
以上是生活随笔為你收集整理的Drools 规则语言详解(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Drools学习 入门实例
- 下一篇: COALESCE()、isnull()、