规则引擎-drools-4-动态生成drl文档

news2025/1/11 18:42:30

文章目录

  • drools 引擎工作原理
  • 动态生成drl文件示例
    • 步骤
      • 模板文件 decision_rule_template.drt
      • 生成规则文件service
      • DecisionNodeFact实体对象
      • 生成的drl字符串如下
      • KieHealper 执行
  • 动态生成drl文件的原理

实际应用过程中,很多时候,规则不是一成不变的,而且对于业务运营人员,去写drl文件也不太现实,因此,动态生成drl文档,可能是更加常用的操作。

drools 引擎工作原理

这部分内容在官网文档第4章。
4. Drools Engine
官网链接:https://docs.drools.org/7.73.0.Final/drools-docs/html_single/index.html#_droolslanguagereferencechapter

Drools引擎是Drools中的规则引擎。Drools引擎存储、处理和评估数据,以执行您定义的业务规则或决策模型。Drools引擎的基本功能是将传入的数据或事实与规则的条件相匹配,并确定是否以及如何执行规则。

Drools引擎主要有以下几部分:

Rules-规则:您定义的业务规则或DMN决策。所有规则必须至少包含触发规则的条件和规则规定的操作。
Facts-事实:在Drools引擎中输入或更改的数据,Drols引擎匹配规则条件以执行适用规则。
Production memory-生产内存:Drools引擎中存储规则的位置。
Working memory-工作内存:Drools引擎中存储事实的位置。
Agenda-议程:注册和排序激活规则(如果适用)以准备执行的位置。

drools引擎工作原理图:
在这里插入图片描述

当业务用户或自动化系统在Drools中添加或更新规则相关信息时,该信息将以一个或多个事实的形式插入Drools引擎的工作存储器中。

Drools引擎将这些事实与存储在生产内存中的规则条件相匹配,以确定符合条件的规则执行。(将事实与规则相匹配的过程通常称为模式匹配。)

当满足规则条件时,Drools引擎会激活规则并将其注册到议程中,然后Drools会对优先或冲突规则进行排序,以备执行。

动态生成drl文件示例

动态生成drl有多种方式,给一个参考链接:https://www.jianshu.com/p/650ecc341417
读者可根据自身使用场景选择。
本文只写一个示例,
需求大致描述:业务方要在页面配置生成一系列的规则,且配置较为灵活,每个规则的属性、返回值等都不固定,且属性和结果处理是动态可配置的。
避免涉密,再具体的不描述了。以上描述,是想说明我们定义规则时候的Facts不能是确定的对象,因此采用Map来实现Facts的灵活使用。

步骤

1、定义事实对象,本例采用Map,因此不需要定义特定的Fact对象。
2、定义数据存储结构及方式。本例采用mysql存储。因为有页面交互,因此需要将页面的数据进行存储。
3、定义模板文件drt,本例采用模板drt方式,减少拼接drl字符串的麻烦。
4、从数据库中读取数据,转换成模板对应的map。
5、使用ObjectDataCompiler.compile api完成模板drt转为drl字符串的过程。
6、使用KieHealper加载drl字符串,生成kiesession,完成执行动态加载的规则文件(drl字符串)。

模板文件 decision_rule_template.drt

template header

rule_name_id
nodeId
ruleCondition
ruleResult

package rules
import java.util.Map
global java.util.Map globalMap

template "decision_rule_template"

rule "decision_rule_@{rule_name_id}_@{nodeId}"
lock-on-active
when
    $map:Map()
    @{ruleCondition}
then
    @{ruleResult}
    System.out.println("触发规则:decision_rule_@{rule_name_id}_@{nodeId}");
end
end template

生成规则文件service

package com.dcy.drools.service;

import com.dcy.drools.fact.decision.DecisionNodeFact;
import lombok.extern.slf4j.Slf4j;
import org.drools.template.ObjectDataCompiler;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ding cheng yun
 * @description
 * @date 2022/11/15
 **/
@Slf4j
@Service
public class DecisionLoadRuleService {

    public String buildRuleStr(Long decisionId) {
        List<DecisionNodeFact> nodeFacts = getRuleNodeDB(decisionId);

        List<Map<String, Object>> conditionMapList = new ArrayList<>();
        for (int i = 0; i < nodeFacts.size(); i++) {
            DecisionNodeFact n = nodeFacts.get(i);

            Map<String, Object> conditionMap = new HashMap<>();

            conditionMap.put("rule_name_id", decisionId);
            conditionMap.put("nodeId", n.getNodeId());

            conditionMap.put("ruleCondition", n.getRuleConditionStr());
            conditionMap.put("ruleResult", n.getRuleResultStr());

            conditionMapList.add(conditionMap);
        }

        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/decision_rule_template.drt");
        ObjectDataCompiler objectDataCompiler = new ObjectDataCompiler();
        String drlStr = objectDataCompiler.compile(conditionMapList, inputStream);
        log.info(" 规则id:{}, 规则code:{}", "or.getRuleId()", "or.getRuleCode()");
        log.info(drlStr);

        return drlStr;
    }

    private List<DecisionNodeFact> getRuleNodeDB(Long decisionId) {
        // 根节点
        DecisionNodeFact n = new DecisionNodeFact();
        n.setDecisionId(decisionId);
        n.setNodeId(10L);
        n.setNodeName("客户性别分组");
        n.setParentNodeId(0L);
        n.setRuleConditionStr("");
        n.setRuleResultStr("");


        // 子节点-1:规则1,父节点=根节点
        DecisionNodeFact n1 = new DecisionNodeFact();
        n1.setDecisionId(decisionId);
        n1.setNodeId(11L);
        n1.setNodeName("无姓名规则");
        n1.setParentNodeId(10L);
        n1.setRuleConditionStr("Object($map[\"sex\"] == \"女\")  Object($map[\"userAge\"] >\"20\",$map[\"userName\"] ==\"张三\")");
        n1.setRuleResultStr("globalMap.put(\"userScore\",\"100\");globalMap.put(\"validVip\",\"不是vip\");modify($map){put(\"userScore\", \"100\"),put(\"validVip\", \"不是vip\")};");

        // 子节点-2:规则2,父节点=根节点
        DecisionNodeFact n2 = new DecisionNodeFact();
        n2.setDecisionId(decisionId);
        n2.setNodeId(12L);
        n2.setNodeName("张三规则");
        n2.setParentNodeId(10L);
        n2.setRuleConditionStr("Object($map[\"sex\"] == \"男\")  Object($map[\"userAge\"] <=\"20\")");
        n2.setRuleResultStr("globalMap.put(\"userScore\",\"500\");globalMap.put(\"validResult\",\"通过\");modify($map){put(\"userScore\", \"500\"),put(\"validResult\", \"通过\")};");

        // 子节点-3:规则3 父节点=规则2
        DecisionNodeFact n3 = new DecisionNodeFact();
        n3.setDecisionId(decisionId);
        n3.setNodeId(13L);
        n3.setNodeName("李四规则");
        n3.setParentNodeId(12L);
        n3.setRuleConditionStr("Object(!($map[\"sex\"] == \"男\" && $map[\"userAge\"] <=\"20\"))  Object($map[\"userName\"] ==\"李四\")");
        n3.setRuleResultStr("globalMap.put(\"userScore\",\"300\");modify($map){put(\"userScore\", \"300\")};");

        List<DecisionNodeFact> nodeFacts = new ArrayList<>();
        nodeFacts.add(n);
        nodeFacts.add(n1);
        nodeFacts.add(n2);
        nodeFacts.add(n3);
        return nodeFacts;
    }

}

DecisionNodeFact实体对象

package com.dcy.drools.fact.decision;

import lombok.Data;

/**
 * @author ding cheng yun
 * @description
 * @date 2022/11/15
 **/
@Data
public class DecisionNodeFact {
    /**
     * 主键
     */
    private Long nodeId;

    /**
     * 父节点id
     */
    private Long parentNodeId;

    /**
     * 决策流id
     */
    private Long decisionId;

    /**
     * 节点名称
     */
    private String nodeName;

    /**
     * 节点规则条件
     */
    private String ruleConditionStr;

    /**
     * 节点规则结果
     */
    private String ruleResultStr;
}

生成的drl字符串如下

package rules
import java.util.Map
global java.util.Map globalMap

rule "decision_rule_1_10"
lock-on-active
when
    $map:Map()

then

    System.out.println("触发规则:decision_rule_1_10");
end

rule "decision_rule_1_11"
lock-on-active
when
    $map:Map()
    Object($map["sex"] == "女")  Object($map["userAge"] >"20",$map["userName"] =="张三")
then
    globalMap.put("userScore","100");globalMap.put("validVip","不是vip");modify($map){put("userScore", "100"),put("validVip", "不是vip")};
    System.out.println("触发规则:decision_rule_1_11");
end

rule "decision_rule_1_12"
lock-on-active
when
    $map:Map()
    Object($map["sex"] == "男")  Object($map["userAge"] <="20")
then
    globalMap.put("userScore","500");globalMap.put("validResult","通过");modify($map){put("userScore", "500"),put("validResult", "通过")};
    System.out.println("触发规则:decision_rule_1_12");
end

rule "decision_rule_1_13"
lock-on-active
when
    $map:Map()
    Object(!($map["sex"] == "男" && $map["userAge"] <="20"))  Object($map["userName"] =="李四")
then
    globalMap.put("userScore","300");modify($map){put("userScore", "300")};
    System.out.println("触发规则:decision_rule_1_13");
end

KieHealper 执行

 /**
     * 执行drl字符串规则
     * @param drlStr 规则字符串
     * @param packag 规则包
     * @param drlFineName 规则文件名
     * @param params 规则执行的入参
     * @return 规则执行结果map
     * packag 对应该示例,为模板中的pakage ,即rules,drlFineName=decision_rule_1.drl,入参则是调用接口方提供
     */
    public Map<String, Object> executeDrlStr(String drlStr,String packag, String drlFineName, Map<String, Object> params) {
        // 复制参数到另一个map,防止传递方的param发生变化
        Map<String,Object> drlParams = CollectionUtils.isEmpty(params) ? new HashMap<>() : params.entrySet()
                .stream()
                .collect(Collectors.toMap(p->p.getKey(),p->p.getValue()));
        log.info("KieExecuteService.executeDrlStr paramMap:{}", drlParams);
        KieSession kieSession = newKieBase.ruleKieBase(drlStr, packag +"/" +drlFineName);
        Map<String, Object> globalMap = new HashMap<>();
        // 注意这个globalMap必须指定
        kieSession.setGlobal("globalMap", globalMap);
        kieSession.insert(drlParams);
		// 对应该示例, drlFineName.substring(0, drlFineName.lastIndexOf(".drl")) 结果是:decision_rule_1 
		// 根据模板,一个规则文件中的所有规则都是以文件名开头的
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter(drlFineName.substring(0, drlFineName.lastIndexOf(".drl"))));
        kieSession.dispose();
        return globalMap;
    }

动态生成drl文件的原理

动态的将rules修改到生产内存中,且通知drools引擎。
由于时间关系,源码解读等暂时不写了。若以后有机会再来补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

54.Isaac教程--RealSense相机

RealSense相机 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录RealSense相机RealsenseCamera Codelet示例应用程序故障排除固件注意事项通过 USB 3.0 电缆使用 USB 3.0 端口x86_64 Linux 主机设置设置电源模型英特尔RealSense 435 摄像头…

分享159个ASP源码,总有一款适合您

ASP源码 分享159个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 159个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1EaQuRA6mxyylrNWLq8iKVA?pwdaljz 提取码&#x…

springmvc知识巩固

文章目录回顾spring知识前言什么是SpringMVCSpringMVC的优点SpringMVC的常用注解Controller注解的作用ResponseBody注解的作用SpringMVC重定向和转发SpringMVC主要组件SpringMVC的执行流程回顾spring知识 上篇整理了“spring知识巩固”常见面试题&#xff0c;有需要的伙伴请点…

Java基础:源码讲解Collection及相关实现List、Set、Queue

1 缘起 说到Java第一问&#xff0c;很多人的第一反应是三大特性&#xff0c;那么接下来&#xff0c;可能就是集合了。 Collection是Java必知必会&#xff0c;即使没有系统学习&#xff0c;在实际的开发过程中&#xff0c;Collection也是应用最广泛的。 当然&#xff0c;一般的…

ESP-IDF:归并排序测试

ESP-IDF:归并排序测试 /归并排序测试/ void printarry18 (int arr[],int length) { for(int i0;i<length;i) { cout<<arr[i]<<" "; } cout<<endl; } void merge(int arr[],int start, int end, int mid,int * temp) { int length 0;//记录te…

进程间通信之管道(匿名管道与命名管道)

进程间通信之管道进程间通信管道什么是管道管道分类——1.匿名管道匿名管道举例管道的特点管道分类——2.命名管道创建一个命名管道举例命名管道的打开规则匿名管道与命名管道的区别具体使用举例&#xff1a;例子1-用命名管道实现文件拷贝例子2-用命名管道实现server&clien…

POI介绍简介

2.1 POI介绍 Apache POI是用Java编写的免费开源的跨平台的Java API&#xff0c;Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能&#xff0c;其中使用最多的就是使用POI操作Excel文件。 jxl&#xff1a;专门操作Excel maven坐标&#xff1a; <depend…

Linux中安装MySQL及常见问题汇总

一、安装前工作 1、卸载之前的数据库 在安装前需要确定现在这个系统有没有 mysql&#xff0c;如果有那么必须卸载 &#xff08;在 centos7 自带的是 mariaDb 数据库&#xff0c;所以第一步是卸载数据库&#xff09;。 #查看mariadb数据库&#xff1a; rpm -qa | grep maria…

moment.js根据时间戳计算与当前时间相差多少天

Moment旨在在浏览器和Node.js中工作。 所有代码都应该在这两种环境中都有效&#xff0c;并且所有单元测试都在这两种环境中运行。 目前&#xff0c;以下浏览器用于ci系统&#xff1a;Windows XP上的Chrome&#xff0c;Windows 7上的IE 8,9和10&#xff0c;Windows 10上的IE 1…

小车程序、安装vs2019和必要的相关软件

环境 sqlserver2019 vs2019企业版本 安装vs2019步骤 小车程序 C# .net vs2019 sqlserver2019 小车程序地址 小车运行的几种轨迹 一&#xff0c;自动运行到指定节点 找到manual按钮&#xff0c;找到目的节点&#xff0c;search move。 二&#xff0…

[数学] 三次样条

三次样条 已知有一组点x0,x1,x2,⋯,xnx_0, x_1, x_2, \cdots, x_nx0​,x1​,x2​,⋯,xn​, 其中, xt<xt1x_t<x_{t1}xt​<xt1​, y(xt)yty(x_t)y_ty(xt​)yt​, 及该点处的切线y′(xt)yt′y(x_t)y_ty′(xt​)yt′​ 每两个相邻的点之间可以作一个三次曲线 在所有相邻…

let/const相关内容(二)

let/const作用域提升 1&#xff09;根据前面所学的内容知道&#xff0c;var定义的变量是可以作用域提升的。 console.log(foo); // undefined var foo "foo"虽然在第一行中foo还没有被定义&#xff0c;但是在执行代码前&#xff0c;会预编译&#xff0c;先定义f…

ModStartBlog v6.6.0 多语言增强,缓存后台优化

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场&#xff0c;后台一键快速安装会…

【完美解决】Github action报错remote: Write access to repository not granted.

报错及效果图报错代码效果图解决方案必要步骤可能有效的步骤报错及效果图 本解决方案是笔者通过Github action运行项目时报错的解决方案&#xff0c;如果是本地运行报此错&#xff0c;未必有效果。 报错代码 remote: Write access to repository not granted. fatal: unable t…

密评FAQ:如何确定网络和通信安全层面的测评对象?

信息系统一般通过网络技术来实现与外界的互联互通&#xff0c;GB/T 39786-2021《信息安全技术信息系统密码应用基本要求》规定了信息系统在网络和通信安全层面的密码应用技术要求&#xff0c;这些要求涉及到通信的主体&#xff08;通信双方&#xff09;、信息系统与网络边界外建…

(1)深入理解Java虚拟机-内存模型

深入理解Java虚拟机 Java虚拟机运行时数据区 程序计数器 ​ 程序计数器&#xff08;Program Counter Register&#xff09;是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的 字节码的行号指示器。在Java虚拟机的概念模型里 [1] &#xff0c;字节码解释器工作时…

大学开学必备清单、大学生必备的五件电子产品

转眼间就到了新一年的春季开学&#xff0c;在校生进入了新的一个年级学习。电子产品早就成为每个人的必备&#xff0c;尤其是大学生在校时期&#xff0c;更是上网课、日常查询资料的必备&#xff0c;当然还有一些社交、娱乐的因素也都是通过各式各样的电子产品来满足和实现。接…

android12 rockchip预置APK流程

方法一&#xff1a; 根据RK文档&#xff0c; 预制APK很简单, 首先source 环境之后执行命令&#xff1a;get _build_var TARGET_DEVICE_DIR 查看目标文件夹&#xff0c; 例如: device/rockchip/rk3568s/ 这个目录有三个文件夹&#xff1a; preinstall 不可卸载 preinstall_del_f…

基于text2vec进行文本向量化、聚类

基于text2vec进行文本向量化、聚类基于text2vec进行文本向量化、聚类介绍安装安装text2vec库安装transformers库模型下载文本向量化使用text2vec使用transformers文本聚类训练流程&#xff1a;训练代码推理流程推理代码基于text2vec进行文本向量化、聚类 介绍 文本向量表征工…

21_ncwireshark

nc&wireshark 一、nc介绍 网上百度就有一堆介绍,平常主要用于监听和连接 二、nc判断端口是否开放 实验环境: win10虚拟机和kali虚拟机 win10虚拟机ip: 192.168.11.142 kali虚拟机ip: 192.168.11.131 此时win10虚拟机,开放了80端口,21端口,3306端口 在kali虚拟机使用…