1. 程式人生 > >Drools內部功能詳細介紹

Drools內部功能詳細介紹

規則檔案

    在 Drools 當中,一個標準的規則檔案就是一個以“.drl”結尾的文字檔案,由於它是一個標準的文字檔案,所以可以通過一些記事本工具對其進行開啟、檢視和編輯。規則是放在規則檔案當中的,一個規則檔案可以存放多個規則,除此之外,在規則檔案當中還可以存放使用者自定義的函式、資料物件及自定義查詢等相關在規則當中可能會用到的一些物件。

一個標準的規則檔案的結構程式碼清單:


除package之外,其它物件在規則檔案中的順序是任意的,也就是說在規則檔案當中必須要有一個package宣告,同時package 宣告必須要放在規則檔案的第一行,規則檔案當中的package和Java語言當中的package有相似之處,但不完全相同。在Java當中package的作用是用來對功能相似或相關的檔案放在同一個package下進行管理,這種package管理既有物理上Java檔案位置的管理也有邏輯上的檔案位置的管理,在Java當中這種通過package管理檔案要求在檔案位置在邏輯上與物理上要保持一致;但在Drools 的規則檔案當中package 對於規則檔案中規則的管理只限於邏輯上的管理,而不管其在物理上的位置如何,這點是規則與Java檔案的package的區別。 

    對於同一package下的使用者自定義函式、自定義的查詢等,不管這些函式與查詢是否在同一個規則檔案裡面,在規則裡面是可以直接使用的,這點和 Java 的同一package裡的 Java 類呼叫是一樣的。

 

規則語言


一個規則可以包含三個部分:唯有attributes部分是可選的,其他都是必填資訊

    定義當前規則執行的一些屬性等,比如是否可被重複執行、過期時間、生效時間等

條件部分:

    即LHS,定義當前規則的條件,如when Message(); 判斷當前workingMemory中是否存在Message物件。

結果部分:

    即RHS,這裡可以寫普通java程式碼,即當前規則條件滿足後執行的操作,可以直接呼叫Fact物件的方法來操作應用
條件部分:

    條件部分又被稱之為 Left Hand Side,簡稱為 LHS,下文當中,如果沒有特別指出,那麼所說的 LHS 均指規則的條件部分,在一個規則當中 when 與 then 中間的部分就是 LHS 部分。在 LHS 當中,可以包含 0~n 個條件,如果 LHS 部分沒空的話,那麼引擎會自動新增一 個 eval(true)的條件,由於該條件總是返回 true,所以 LHS 為空的規則總是返回 true。  


LHS 部分是由一個或多個條件組成,條件又稱之為 pattern(匹配模式),多個 pattern 之間用可以使用 and 或 or 來進行連線,同時還可以使用小括號來確定 pattern 的優先順序


對於一個 pattern 來說“繫結變數名”是可選的,如果在當前規則的 LHS 部分的其它的 pattern 要用到這個物件,那麼可以通過為該物件設定一個繫結變數名來實現對其引用,對於繫結變數的命名,通常的作法是為其新增一個“$”符號作為字首,這樣可以很好的與 Fact的屬性區別開來;繫結變數不僅可以用在物件上,也可以用在物件的屬性上面,命名方法與物件的命名方法相同;“field 約束”是指當前物件裡相關欄位的條件限制,


規則中 LHS 部分單個pattern (模式) 的情形。 

規則中“$customer”是就是一個繫結到 Customer 物件的“繫結變數名”,該規則的 LHS 部分表示,要求 Fact 物件必須是 Customer 型別,該條件滿足了那麼它的 LHS 會返回 true。

下面這種寫法就是包含兩種pattern(模式) :

rule "rule1" 
     when
     $customer:Customer(age>20,gender=='male') 
     Order(customer==$customer,price>1000) 
    then
        ....
end

簡單說明一下上面的程式碼

第一個:pattern(模式) 有三個約束

1、 物件 型別必須是 Cutomer;

2、Cutomer 的 age 要大於 20

3、Cutomer 的 gender 要是 male

第二個:pattern(模式) 有三個約束

1、 物件型別必須是 Order;

2、 Order 對應的 Cutomer 必須是前面的那個 Customer

3、 當前這個 Order 的price 要大於 1000

這兩個 pattern 沒有符號連線,在 Drools 當中在 pattern 中沒有連線符號,那麼就用 and 來作為預設連線,所以在該規則的 LHS 部分 中兩個pattern(模式)只有都滿足了才會返回 true。預設情況下,每行可以用“;”來作為結束符(和 Java 的結束一樣),當然行尾也可以不加“;”結尾。

約束連線

對於物件內部的多個約束的連線,可以採用“&&”(and)、“||”(or)和“,”(and)來實現

這三個連線符號如果沒有用小括號來顯示的定義優先順序的話,那麼它們的執行順序是:“&&”(and)、“||”(or)

表面上看“,”與“&&”具有相同的含義,但是有一點需要注意,“,”與“&&”和“||”不能混合使用,也就是說在有“&&”或“||”出現的 LHS 當中,是不可以有“,”連線符出現的,反之亦然

Drools提供了十二中型別比較操作符:如果進行常量比較,必須通過eval(條件)或者物件引用比較物件屬性,不能單獨使用,這語法與java是一樣的

>|<,>=|<=,==|!=  這幾個不多說啦

contains| not contains 

memberOf | not memberOf

matches | not matches

下面說明一下後面6種的含意

contains:比較操作符 contains 是用來檢查一個 Fact 物件的某個欄位(該欄位要是一個 Collection 或是一個 Array 型別的物件)是否包含一個指定的物件

語法格式:

Object( field[Collection/Array] contains value)

Contains.drl寫法

package rules.testwrod
import com.drools.test.Person
import com.drools.test.School
rule test001
    when
        $s:School();
        $p:Person(name  contains $s.name);
    then
      System.out.println("恭喜你,成功的使用了 contains");
end

JavaAPI寫法

package com.drools.test;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
public class TestWrod{
    public static void main(String[] args){
        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks =kc.newKieSession("session");
        School school=new School();
        school.setCount(50);
        school.setName("一班");
        Person person=new Person("一班",30);
        FactHandle insert = ks.insert(person);
        ks.insert(school);
        int count = ks.fireAllRules();
        System.out.println("總執行了"+count+"條規則"); 
        ks.dispose();                  
    }
}

contains只能用於物件的某個 Collection/Array型別的欄位與另外一個值進行比較,作為比較的值可以是一個靜態的值,也可以是一個變數(繫結變數或者是一個global物件),說的可能有點麻煩,小編在這裡給大家再通俗的說一下,其實contains就是用來比較屬性值是否與被比較值相同,但是這兩個屬性名是相同的。

not containsnot contains作用與 contains作用相反,not contains是用來判斷一個Fact物件的某個欄位(Collection/Array型別)是不是包含一個指定的物件,和 contains比較符相同,它也只能用在物件的 field當中,舉例說明

Contains.drl寫法

package rules.testwrod
import com.drools.test.Person
import com.drools.test.School
rule test001
    when
        $s:School();
        $p:Person(age not contains $s.count);
    then
      System.out.println("恭喜你,成功的使用了not contains");
end

JavaAPI寫法

package com.drools.test;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
public class TestWrod{
    public static void main(String[] args){
        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks =kc.newKieSession("session");
        School school=new School();
        school.setCount(50);
        school.setName("一班");
        Person person=new Person("一班",30);
        FactHandle insert = ks.insert(person);
        ks.insert(school);
        int count = ks.fireAllRules();
        System.out.println("總執行了"+count+"條規則");
        ks.dispose();
    }
}

結果一定是我們想要的,是因為Person中的屬性是ageSchool的屬性是count,就算值相同,屬性名不同 在not contains下是成立的。

memberOfmemberOf是用來判斷某個Fact物件的某個欄位是否在一個集合(Collection/Array)當中,用法與 contains有些類似,但也有不同

memberOf的語法如下:

Object(fieldName memberOf value[Collection/Array])

可以看到 memberOf中集合型別的資料是作為被比較項的,集合型別的資料物件位於memberOf操作符後面,同時在用 memberOf比較操作符時被比較項一定要是一個變數(繫結變數或者是一個 global物件),而不能是一個靜態值。如何給全域性變數賦值:ksession.setGlobal("list",list);舉例說明

memberOf.drl檔案

package rules.testwrod

import com.drools.test.Person

global java.util.List list;
rule test001
    when
        $p:Person(name memberOf list);
    then
      System.out.println("恭喜你,成功的使用了  memberOf");
end

JavaAPI寫法

package com.drools.test;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
public class TestWrod{
    public static void main(String[] args){
        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks =kc.newKieSession("session");
        List list=new ArrayList();
        list.add("張三");
        list.add("李四");
        list.add("王五");
        list.add("趙六");
        Person person=new Person("張三",50);
        ks.setGlobal("list",list);        
        FactHandle insert = ks.insert(person);
        ks.insert(school);
        int count = ks.fireAllRules();
        System.out.println("總執行了"+count+"條規則");
        ks.dispose();
    }
}

結果肯定是我們想要的了



not memberOf:該操作符與 memberOf作用洽洽相反,是用來判斷Fact物件當中某個欄位值是不是中某個集合(Collection/Array)當中。小編這裡就不給讀者舉例說明,有興趣的讀者可以自己嘗試一下。

 

matchesmatches是用來對某個 Fact 的欄位與標準的 Java 正則表示式進行相似匹配,被比較的字串可以是一個標準的 Java 正則表示式,有一點小編要提醒讀者注意,那就是正則表示式字串當中不用考慮“\”的轉義問題。

語法如下:

Object(fieldName matches “正則表示式”)

舉例說明 

Matches.drl

package rules.testwrod

import com.drools.test.Person

rule test001
    when
        $p:Person(name matches  "張.*");
    then
      System.out.println("恭喜你,成功的使用了  matches");
end

JavaAPI寫法

package com.drools.test;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
public class TestWrod{
    public static void main(String[] args){
        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks =kc.newKieSession("session");       
        Person person=new Person("張三",30);
        FactHandle insert = ks.insert(person);
        ks.insert(school);
        int count = ks.fireAllRules();
        System.out.println("總執行了"+count+"條規則");
        ks.dispose();
    }
}

結果如下:


小編這裡補充幾點:簡單來說就是模糊查詢,語法是不能是“*.這樣的語法是錯誤的。

該規則是用來查詢所有Person物件的 name屬性是不是以字開頭,如果滿足這一條件那麼就將該Person物件的 name 屬性打印出來

not matches:matches作用相反,是用來將某個Fact的欄位與一個Java標準正則表示式進行匹配,看是不是能與正則表示式匹配。 小編這裡就不多寫做例子了,建議讀者要自己試一下,體驗一下結果 

語法擴充套件部分

訪問List資料結構   

 $customer.accounts[3]等同於$customer.getAccounts(3) 

訪問Map資料結構

  $customerMap["123"]等同於$customerMap.get["123"] 


下面是小編的微信轉帳二維碼,小編再次謝謝讀者的支援,小編會更努力的

----請看下方↓↓↓↓↓↓↓

百度搜索 Drools從入門到精通:可下載開源全套Drools教程

深度Drools教程不段更新中:


更多Drools實戰陸續釋出中………

掃描下方二維碼關注公眾號 ↓↓↓↓↓↓↓↓↓↓