日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Drools规则引擎

發(fā)布時(shí)間:2023/12/10 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Drools规则引擎 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

借鑒:基于JAVA的功能強(qiáng)大的開源規(guī)則引擎-Drools業(yè)務(wù)管理系統(tǒng)實(shí)戰(zhàn)視頻教程_嗶哩嗶哩_bilibili

?1、什么是規(guī)則引擎?

規(guī)則引擎,全稱為業(yè)務(wù)規(guī)則管理系統(tǒng),英文名為BRMS(即Business Rule Management System)。規(guī)則引擎的主要思想是將應(yīng)用程序中的業(yè)務(wù)決策部分分離出來,并使用預(yù)定義的語義模板編寫業(yè)務(wù)決策(業(yè)務(wù)規(guī)則),由用戶或開發(fā)者在需要時(shí)進(jìn)行配置、管理。

需要注意的的規(guī)則引擎并不是一個(gè)具體的技術(shù)框架,而是指的一類系統(tǒng),即業(yè)務(wù)規(guī)則管理系統(tǒng)。目前市面上具體的規(guī)則引擎產(chǎn)品有:drools、VisualRules、iLog等。

規(guī)則引擎實(shí)現(xiàn)了將業(yè)務(wù)決策從應(yīng)用程序代碼中分離出來,接收數(shù)據(jù)輸入,解釋業(yè)務(wù)規(guī)則,并根據(jù)業(yè)務(wù)規(guī)則做出業(yè)務(wù)決策。規(guī)則引擎其實(shí)就是一個(gè)輸入輸出平臺(tái)。

2、Drools介紹

drools是一款由JBoss組織提供的基于java語言開發(fā)的開源規(guī)則引擎,可以將復(fù)雜且多變的業(yè)務(wù)規(guī)則從硬編碼中解放出來,以規(guī)則腳本的形式存放在文件或特定的存儲(chǔ)介質(zhì)中(如存放在數(shù)據(jù)庫中),使得業(yè)務(wù)規(guī)則的變更不需要修改項(xiàng)目代碼、重啟服務(wù)器就可以在線上環(huán)境立即生效。

drools官網(wǎng):https://www.drools.org/

drools中文網(wǎng):Drools中文網(wǎng) | 基于java的功能強(qiáng)大的開源規(guī)則引擎

drools源碼下載地址:https://github.com/kiegroup/drools

在項(xiàng)目中使用drools時(shí),既可以單獨(dú)使用也可以整合spring使用。如果單獨(dú)使用只需導(dǎo)入如下maven坐標(biāo)即可:

<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.6.0.Final</version> </dependency>

?3、Drools入門案例

1、業(yè)務(wù)場景說明

業(yè)務(wù)場景:消費(fèi)者在圖書商城購買圖書,下單后需要在支付頁面顯示訂單優(yōu)惠后的價(jià)格。具體優(yōu)惠規(guī)則如下:

?現(xiàn)在需要根據(jù)上面的規(guī)則計(jì)算優(yōu)惠后的價(jià)格。

?2、開發(fā)實(shí)現(xiàn)

第一步:創(chuàng)建maven工程并導(dǎo)入drools相關(guān)maven坐標(biāo)

<!-- drools規(guī)則引擎 --><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.6.0.Final</version></dependency><!-- junit單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>

第二部:根據(jù)drools要求創(chuàng)建resources/META-INF/kmodule.xml

<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"><!--name:指定kbase的名稱,可以任意,但是需要唯一packages:指定規(guī)則文件的目錄,需要根據(jù)實(shí)際情況填寫,否則無法加載到規(guī)則文件default:指定當(dāng)前kbase是否為默認(rèn)--><kbase name="myKbase1" packages="rules" default="true"><!--name:指定ksession的名稱,可以任意,但需要唯一default:指定當(dāng)前session是否為默認(rèn)--><ksession name="ksession-rule" default="true"/></kbase> </kmodule>

注意:上面配置文件的名字和位置都是固定寫法,不能更改。

第三步:創(chuàng)建實(shí)體類Order

package com.ws.soon.entity;import lombok.Data;/*** 訂單*/ @Data public class Order {private Double originalPrice; // 訂單原始價(jià)格,即優(yōu)惠前的價(jià)格private Double realPrice; // 訂單真實(shí)價(jià)格,即優(yōu)惠后的價(jià)格 }

第四步:創(chuàng)建規(guī)則文件resources/rules/bookDiscount.drl

// 圖書優(yōu)惠規(guī)則 package book.discount import com.ws.soon.entity.Order// 規(guī)則一:所購圖書總價(jià)在100元以下的沒有優(yōu)惠 rule "book_discount_1"when$order: Order(originalPrice < 100) // 匹配模式,到規(guī)則引擎中(工作內(nèi)存)查找Order對象,命名為$orderthen$order.setRealPrice($order.getOriginalPrice());System.out.println("成功匹配到規(guī)則一,所購圖書總價(jià)在100元以下無優(yōu)惠"); end// 規(guī)則二:所購圖書總價(jià)在100~200的優(yōu)惠20元 rule "book_discount_2"when$order: Order(originalPrice >= 100 && originalPrice < 200)then$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規(guī)則二,所購圖書總價(jià)在100~200元之間"); end// 規(guī)則三:所購圖書總價(jià)在200~300元的優(yōu)惠50元 rule "book_discount_3"when$order: Order(originalPrice >= 200 && originalPrice < 300)then$order.setRealPrice($order.getOriginalPrice() - 50);System.out.println("成功匹配到規(guī)則三,所購圖書總價(jià)在200~300元之間"); end// 規(guī)則四:所購圖書總價(jià)在300元及以上的優(yōu)惠100元 rule "book_discount_4"when$order: Order(originalPrice >= 300)then$order.setRealPrice($order.getOriginalPrice() - 100);System.out.println("成功匹配到規(guī)則四,所購圖書總價(jià)在300元及以上"); end

第五步:編寫單元測試

package com.ws.soon.test;import com.ws.soon.entity.Order; import org.junit.Test; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession;public class DroolsTest {@Testpublic void test() {KieServices kieServices = KieServices.Factory.get();// 獲取Kie容器對象(默認(rèn)容器對象KieContainer kieContainer = kieServices.newKieClasspathContainer();// 從Kie容器對象中獲取會(huì)話對象(默認(rèn)session對象KieSession kieSession = kieContainer.newKieSession();Order order = new Order();order.setOriginalPrice(160d);// 將order對象插入工作內(nèi)存kieSession.insert(order);System.out.println("匹配規(guī)則前優(yōu)惠后價(jià)格:" + order.getRealPrice());// 匹配對象// 激活規(guī)則,由drools框架自動(dòng)進(jìn)行規(guī)則匹配。若匹配成功,則執(zhí)行kieSession.fireAllRules();// 關(guān)閉會(huì)話kieSession.dispose();System.out.println("優(yōu)惠前價(jià)格:" + order.getOriginalPrice() + "\n優(yōu)惠后價(jià)格:" + order.getRealPrice());} }

控制臺(tái)輸出如下:

通過上面的入門案例可以發(fā)現(xiàn),使用drools引擎規(guī)則主要工作就是編寫規(guī)則文件,在規(guī)則文件中定義和業(yè)務(wù)相關(guān)的業(yè)務(wù)規(guī)則,例如本案例定義的就是圖書的優(yōu)惠規(guī)則。規(guī)則定義好后就需要調(diào)用drools提供的api將數(shù)據(jù)提供給規(guī)則引擎進(jìn)行規(guī)則模式匹配,規(guī)則引擎會(huì)執(zhí)行匹配成功的規(guī)則,并將計(jì)算的結(jié)果返回。

可能大家會(huì)有疑問,雖然沒有在代碼中編寫規(guī)則的判斷邏輯,但是還是在規(guī)則文件中編寫了業(yè)務(wù)規(guī)則,這跟在代碼中編寫規(guī)則有什么本質(zhì)的區(qū)別?

前面已經(jīng)提到,使用規(guī)則引擎時(shí),規(guī)則可以做到動(dòng)態(tài)管理。業(yè)務(wù)人員可以像管理數(shù)據(jù)一樣對業(yè)務(wù)規(guī)則進(jìn)行管理,比如查詢、添加、更新、統(tǒng)計(jì)、提交業(yè)務(wù)規(guī)則等。這樣就可以做到在不重啟服務(wù)的情況下調(diào)整業(yè)務(wù)規(guī)則。

4、小結(jié)

1、規(guī)則引擎構(gòu)成

drools規(guī)則引擎由以下三部分構(gòu)成:

  • Working Memory(工作內(nèi)存)
  • Rule Base(規(guī)則庫)
  • Inference Engine(推理引擎)

其中Inference Engine(推理引擎)又包括:

  • Pattern Matcher(匹配器)
  • Agenda(議程)
  • Execution Engine(執(zhí)行引擎)?

?如下圖所示:

2、相關(guān)概念說明

Working Memory:工作內(nèi)存,drools規(guī)則引擎會(huì)從Working Memory中獲取數(shù)據(jù)并和規(guī)則文件中定義的規(guī)則進(jìn)行模式匹配,所以我們開發(fā)的應(yīng)用程序只需要將我們的數(shù)據(jù)插入到Working Memory中即可,例如本案例中我們調(diào)用kieSession.insert(order);就是將order對象插入到工作內(nèi)存中。

Fact:事實(shí),是指在drools規(guī)則應(yīng)用當(dāng)中,將一個(gè)普通的javaBean插入到Working Memory后的對象就是Fact對象,例如本案例中的Order對象就屬于Fact對象。Fact對象是我們的應(yīng)用和規(guī)則引擎進(jìn)行交互的橋梁或通道。

Rule Base:規(guī)則庫,我們在規(guī)則文件中定義的規(guī)則都會(huì)被加載到規(guī)則庫中。

Pattern Matcher:匹配器,將Rule Base中的所有規(guī)則與Working Memory中的Fact對象進(jìn)行模式匹配,匹配成功則被激活并放入Agenda中。

Agenda:議程,用于存放通過匹配器進(jìn)行模式匹配后被激活的規(guī)則。

Execution Engine:執(zhí)行引擎,執(zhí)行Agenda中被激活的規(guī)則。

3、KIE介紹

我們在操作Drools時(shí)經(jīng)常使用的API以及他們之間的關(guān)系如下圖:

?通過上面的API可以發(fā)現(xiàn),大部分類都是以Kie開頭。Kie全稱為Knowledge is Everything,即“只是就是一切”的縮寫,是Jboss一系列項(xiàng)目的總稱。如下圖所示,Kie的主要模塊有OptaPlanner、Drools、UberFire、jBPM。

通過上圖可以看到,Drools是整個(gè)KIE項(xiàng)目中的一個(gè)組件,Drools中還包括一個(gè)Drools-WB的模塊,他是一個(gè)可視化的規(guī)則編輯器。

?5、Drools基礎(chǔ)語法

1、規(guī)則文件構(gòu)成

在使用Drools時(shí)非常重要的一個(gè)工作就是編寫規(guī)則文件,通常規(guī)則文件的后綴為.drl。

drl是Drools Rule Language的縮寫。在規(guī)則文件中編寫具體的規(guī)則內(nèi)容。

一套完整的規(guī)則文件內(nèi)容構(gòu)成如下:

關(guān)鍵字描述
package包名,只限于邏輯上的管理,同一個(gè)包名下的查詢或者函數(shù)可以直接調(diào)用
import用于導(dǎo)入類或靜態(tài)方法
global全景變量
function自定義函數(shù)
query查詢
rule...end規(guī)則體

Drools支持的規(guī)則文件,除了drl形式,還有Excel文件類型的。

2、規(guī)則體語法結(jié)構(gòu)

規(guī)則體是規(guī)則文件中的重要組成部分,是進(jìn)行業(yè)務(wù)規(guī)則判斷、處理業(yè)務(wù)結(jié)果的部分。

規(guī)則語法結(jié)構(gòu)如下:

rule "ruleName" attributes when LHSthen RHS end

?rule:關(guān)鍵字,表示規(guī)則開始,參數(shù)為規(guī)則的唯一名稱。

attribute:規(guī)則屬性,是rule與when之間的參數(shù),為可選項(xiàng)。

when:關(guān)鍵字,后面跟規(guī)則的條件部分。

LHS(Left Hand Side):是規(guī)則的條件部分的通用名稱。它由零個(gè)或多個(gè)條件元素組成。如果LHS為空,則它將被視為始終為true的條件元素。

then:關(guān)鍵字,后面跟規(guī)則的結(jié)果部分。

RHS(Right Hand Side):是規(guī)則的后果或行動(dòng)部分的通用名稱。

end:關(guān)鍵字,表示一個(gè)規(guī)則的結(jié)束。

3、注釋

在drl形式的規(guī)則文件中使用注釋和Java類中使用注釋一致, 分為單行注釋和多行注釋。

單行注釋用”//"進(jìn)行標(biāo)記,多行注釋以"/*"開始,以"*/"結(jié)束。

4、Pattern匹配規(guī)則

前面我們已經(jīng)知道了Drools中的匹配器可以將Rule Base中的所有規(guī)則與Working Memory中的Fact對象進(jìn)行模式匹配,那么我們就需要在規(guī)則體的LHS部分定義規(guī)則并進(jìn)行模式匹配。LHS部分由一個(gè)或者多個(gè)條件組成,條件又稱為pattern。

pattern的語法結(jié)構(gòu)為:綁定變量名:Object(Field約束)

其中綁定變量名可以省略,通常綁定變量名的命名一般建議以$開始。如果定義了綁定變量名,就可以在規(guī)則體的RHS部分使用此綁定變量名來操作相應(yīng)的Fact對象。Field約束部分是需要返回true或者false的0個(gè)或多個(gè)表達(dá)式。

例如我們的入門案例中:

// 規(guī)則二:所購圖書總價(jià)在100~200的優(yōu)惠20元 rule "book_discount_2"when// Order為類型約束,originalPrice為屬性約束$order: Order(originalPrice >= 100 && originalPrice < 200)then$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規(guī)則二,所購圖書總價(jià)在100~200元之間"); end

通過上面的例子我們可以知道,匹配的條件為:

  • 工作內(nèi)存中必須存在Order這種類型的Fact對象---類型約束
  • Fact對象的originalPrice屬性值必須小于200----屬性約束
  • Fact對象的originalPrice屬性值必須大于等 于1-0----屬性約束?
  • ?以上條件必須同時(shí)滿足當(dāng)前規(guī)則才有可能被激活。

    綁定變量既可以用在對象上,也可以用在對象的屬性上。例如上面的例子可以改為:

    // 規(guī)則二:所購圖書總價(jià)在100~200的優(yōu)惠20元 rule "book_discount_2"when$order: Order($op:originalPrice >= 100 && originalPrice < 200)thenSystem.out.println("$op=" + $op);$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規(guī)則二,所購圖書總價(jià)在100~200元之間"); end

    ?LHS部分還可以定義多個(gè)pattern,多個(gè)pattern之間可以使用and或者or進(jìn)行連接,也可以寫,默認(rèn)連接為and。

    5、比較操作符

    符號(hào)說明
    >大于
    <小于
    >=大于等于
    <=小于等于
    ==等于
    !=不等于
    contains檢查一個(gè)Fact對象的某個(gè)屬性值是否包含一個(gè)指定的對象值
    not contains檢查一個(gè)Fact對象的某個(gè)屬性值是否不包含一個(gè)指定的對象值
    memberOf判斷一個(gè)Fact對象的某個(gè)屬性是否在一個(gè)或多個(gè)集合中
    not memberOf判斷一個(gè)Fact對象的某個(gè)屬性是否不在一個(gè)或多個(gè)集合中
    matches判斷一個(gè)Fact對象的屬性是否與提供的標(biāo)準(zhǔn)的Java正則表達(dá)式進(jìn)行匹配
    not matches判斷一個(gè)Fact對象的屬性是否不與提供的標(biāo)準(zhǔn)的Java正則表達(dá)式進(jìn)行匹配

    前6個(gè)比較操作符和Java中的完全相同,下面我們重點(diǎn)學(xué)習(xí)后6個(gè)比較操作符。?

    1、語法

    ●contains | not contains語法結(jié)構(gòu) // 包含與不包含,是模糊匹配,類似于sql的like Object(Field[Collection/Array] contains value) Object(Field[Collection/Array] npt contains value)●memberOf | not memberOf語法結(jié)構(gòu) Object(field memberOf value[Collection/Array]) Object(field not memberOf value[Collection/Array1)●matches | not matches語法結(jié)構(gòu) Object(field matches "正則表達(dá)式") Object(field not matches "正則表達(dá)式")

    2、操作步驟

    第一步:創(chuàng)建實(shí)體類,用于測試比較運(yùn)算符

    package com.ws.soon.entity;import lombok.Data;import java.util.List;/*** @author wangsaisoon* @Description 實(shí)體類 用戶測試比較運(yùn)算符* @date 2021/10/27 21:23* @Version 1.0*/ @Data public class ComparisonOperatorEntity {private String names;private List<String> list; }

    第二步:創(chuàng)建規(guī)則文件resources/rules/comparisonOperator.drl

    package comparisonOperatorimport com.ws.soon.entity.ComparisonOperatorEntity/*** 當(dāng)前規(guī)則用于測試drools提供的操作運(yùn)算符*/// 測試比較操作符contains rule "rule_comparison_contains"whenComparisonOperatorEntity(names contains "王小白") orComparisonOperatorEntity(list contains names)thenSystem.out.println("規(guī)則:rule_comparison_contains觸發(fā)了..."); end// 測試比較操作符contains rule "rule_comparison_not_contains"whenComparisonOperatorEntity(names not contains "王小白") andComparisonOperatorEntity(list not contains names)thenSystem.out.println("規(guī)則:rule_comparison_not_contains觸發(fā)了..."); end// 測試比較操作符memberOf rule "rule_comparison_memberOf"whenComparisonOperatorEntity(names memberOf list)thenSystem.out.println("規(guī)則:rule_comparison_memberOf觸發(fā)了..."); end// 測試比較操作符not memberOf rule "rule_comparison_not_memberOf"whenComparisonOperatorEntity(names not memberOf list)thenSystem.out.println("規(guī)則:rule_comparison_not_memberOf觸發(fā)了..."); end// 測試比較操作符matches rule "rule_comparison_matches"whenComparisonOperatorEntity(names matches "王.*") // 正則表達(dá)式thenSystem.out.println("規(guī)則:rule_comparison_matches觸發(fā)了..."); end// 測試比較操作符not matches rule "rule_comparison_not_matches"whenComparisonOperatorEntity(names not matches "王.*") // 正則表達(dá)式thenSystem.out.println("規(guī)則:rule_comparison_not_matches觸發(fā)了..."); end

    第三步:編寫單元測試

    package com.ws.soon.test;import com.ws.soon.entity.ComparisonOperatorEntity; import org.junit.Test; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class ComparisonOperatorEntityTest {@Testpublic void test() {KieServices kieServices = KieServices.Factory.get();// 獲取Kie容器對象(默認(rèn)容器對象KieContainer kieContainer = kieServices.newKieClasspathContainer();// 從Kie容器對象中獲取會(huì)話對象(默認(rèn)session對象KieSession kieSession = kieContainer.newKieSession();ComparisonOperatorEntity fact = new ComparisonOperatorEntity();String names = "1王2小白";fact.setNames(names);List<String> list = new ArrayList<String>();list.add("小黑");list.add("小白"); // list.add(names);fact.setList(list);// 將order對象插入工作內(nèi)存kieSession.insert(fact);// 匹配對象// 激活規(guī)則,由drools框架自動(dòng)進(jìn)行規(guī)則匹配。若匹配成功,則執(zhí)行kieSession.fireAllRules();// 關(guān)閉會(huì)話kieSession.dispose();} }

    6、執(zhí)行執(zhí)行規(guī)則

    6、關(guān)鍵字

    7、Drools內(nèi)置方法

    總結(jié)

    以上是生活随笔為你收集整理的Drools规则引擎的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。