Drools规则引擎案例

wen java案例 3

本文目录导读:

Drools规则引擎案例

  1. 项目基础搭建
  2. 核心业务场景案例
  3. 决策表(Excel)案例
  4. 复杂事件处理(CEP)案例
  5. 完整项目配置(kmodule.xml)
  6. 性能优化与最佳实践

我为你整理了一份关于Drools规则引擎的完整案例解析,涵盖从基础概念到实际业务场景的完整代码演示。

项目基础搭建

Maven依赖配置

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.73.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.73.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-decisiontables</artifactId>
    <version>7.73.0.Final</version>
</dependency>

基础数据模型

// 订单实体
public class Order {
    private String orderId;
    private Customer customer;
    private double amount;
    private double discount = 0;
    private String discountLevel;
    private boolean vip;
    private List<String> promotions = new ArrayList<>();
    // getters/setters...
}
// 客户实体
public class Customer {
    private String name;
    private int age;
    private int creditScore;
    private double totalAmount;  // 历史累计消费金额
    private String membership;   // 会员等级
    // getters/setters...
}
// 商品实体
public class Product {
    private String productId;
    private String category;
    private String name;
    private double price;
    private int stock;
    private boolean isPromotional;
    // getters/setters...
}

核心业务场景案例

场景1:电商折扣计算系统

业务规则:

  • 会员客户享受额外5%折扣
  • 累计消费超过10000元享受金卡会员折扣
  • 订单金额超过500元且非促销商品,享受10%折扣
  • 同时满足多个条件时,折扣可叠加

规则文件 discount-rules.drl

package com.example.drools.rules
import com.example.drools.model.Order;
import com.example.drools.model.Customer;
// 规则1:普通会员折扣
rule "Member Discount-5%"
    when
        $customer: Customer(membership == "VIP" && totalAmount >= 5000)
        $order: Order(vip == true, discount < 0.15)
    then
        $order.setDiscount($order.getDiscount() + 0.05);
        $order.setDiscountLevel("VIP会员折扣");
        System.out.println("应用VIP会员5%折扣");
        update($order);
end
// 规则2:大额订单折扣
rule "Large Order Discount-10%"
    when
        $order: Order(amount > 500, discount < 0.20)
    then
        $order.setDiscount($order.getDiscount() + 0.10);
        $order.setDiscountLevel("大额订单优惠");
        System.out.println("应用大额订单10%折扣");
        update($order);
end
// 规则3:银联支付优惠
rule "UnionPay Discount-3%"
    when
        $order: Order(promotions contains "UnionPay", discount < 0.25)
    then
        $order.setDiscount($order.getDiscount() + 0.03);
        $order.getPromotions().add("银联支付优惠");
        System.out.println("应用银联支付3%折扣");
        update($order);
end
// 规则4:新客首单优惠
rule "New Customer First Order"
    when
        $customer: Customer(totalAmount == 0)
        $order: Order()
    then
        $order.setDiscount($order.getDiscount() + 0.15);
        $order.setDiscountLevel("新客首单优惠");
        System.out.println("应用新顾客15%折扣");
        update($order);
end

调用代码:

public class DiscountCalculator {
    private static KieContainer kieContainer;
    static {
        KieServices kieServices = KieServices.Factory.get();
        kieContainer = kieServices.newKieClasspathContainer();
    }
    public static Order calculateDiscount(Order order) {
        KieSession kieSession = kieContainer.newKieSession("discount-session");
        kieSession.insert(order);
        kieSession.insert(order.getCustomer());
        kieSession.fireAllRules();
        kieSession.dispose();
        // 计算最终金额
        double finalAmount = order.getAmount() * (1 - order.getDiscount());
        order.setFinalAmount(finalAmount);
        return order;
    }
    public static void main(String[] args) {
        // 测试案例
        Customer customer = new Customer();
        customer.setName("张三");
        customer.setTotalAmount(12000);
        customer.setMembership("VIP");
        Order order = new Order();
        order.setOrderId("ORD001");
        order.setCustomer(customer);
        order.setAmount(800);
        order.setVip(true);
        order.getPromotions().add("UnionPay");
        Order result = calculateDiscount(order);
        System.out.println("订单原价:" + order.getAmount());
        System.out.println("总折扣率:" + (result.getDiscount() * 100) + "%");
        System.out.println("最终金额:" + result.getFinalAmount());
    }
}

场景2:风控可疑交易检测

业务规则:

  • 单笔交易超过50000元且时间在凌晨0-5点,高风险
  • 5分钟内连续多笔交易累计超过30000元,中高风险
  • 新开户3天内大额交易,高风险
  • CEO/高管账户大额交易,允许但需通知

规则文件 risk-rules.drl

package com.example.drools.risk
import java.time.LocalDateTime;
import com.example.drools.model.Transaction;
import com.example.drools.model.User;
// 规则1:凌晨大额交易检测
rule "Detect Late Night Major Transaction"
    when
        $transaction: Transaction(amount > 50000)
        eval(判断交易时间是否在凌晨0-5点)
        $user: User(accountType != "CEO")
    then
        TransactionAlert alert = new TransactionAlert();
        alert.setLevel("HIGH");
        alert.setType("凌晨大额交易");
        alert.setTransactionId($transaction.getTransactionId());
        alert.setDescription("疑似洗钱行为,金额超过5万且时间异常");
        insert(alert);
        drools.halt();
end
// 规则2:高频连续交易检测
rule "Detect Rapid Multiple Transactions"
    when
        $user: User()
        $transactions: List(size > 3) from collect 
            (Transaction(userId == $user.getUserId(), 
                         timestamp > $user.getLastCheckedTime()))
        eval(累计金额超过30000)
    then
        TransactionAlert alert = new TransactionAlert();
        alert.setLevel("MEDIUM_HIGH");
        alert.setType("高频交易");
        alert.setUserId($user.getUserId());
        alert.setTransactionCount($transactions.size());
        insert(alert);
end
// 规则3:新开户交易限制
rule "New Account Transaction Monitoring"
    when
        $user: User(accountAge <= 3)
        $transaction: Transaction(amount > 20000, userId == $user.getUserId())
    then
        TransactionAlert alert = new TransactionAlert();
        alert.setLevel("HIGH");
        alert.setType("新账户异常");
        insert(alert);
end
// 规则4:高管账户通知(非拦截)
rule "CEO Account Notification"
    when
        $user: User(accountType == "CEO", status == "ACTIVE")
        $transaction: Transaction(amount >= 100000, userId == $user.getUserId())
    then
        TransactionNotification notification = new TransactionNotification();
        notification.setType("CEO交易确认");
        notification.setMessage("高管大额交易需人工确认");
        insert(notification);
end

场景3:货物配送路径优化

业务规则:

  • 依据邮编和距离选择最近配送中心
  • 考虑货物重量、体积、紧急程度
  • 如果配送中心库存不足,自动寻找替代方案
  • 包裹丢失时自动触发理赔流程
// 规则1:超出配送范围检测
rule "Out of Delivery Range"
    when
        $package: PackageObject(deliveryCode != null )
        $address: Address(scope == "distance" || $package.getDistance() > 50)
    then
        System.out.println("该地址超出配送范围,请联系客服");
        retract($package);
        // 触发特殊流程
        insert(new DeliveryException($package, "超出配送范围"));
end
// 规则2:紧急包裹优先处理
rule "Priority Emergency Package"
    when
        $package: PackageObject(priority == "EMERGENCY", 
                                 deliveryTime > 8, 
                                 deliveryTime <= 10)
        $carrier: Carrier(freeCapacity > $package.getWeight())
    then
        assignPackageToCarrier($package, $carrier);
        update($carrier);
end

决策表(Excel)案例

Excel决策表结构:

| RuleSet  | package: com.example.drools.rules | |
|----------|----------------------------------|--|
| Import   | com.example.drools.model.Order   | |
| Notes    | 折扣计算规则决策表               | |
|----------------------------------------------------------------|
| RuleTable 折扣计算              |                             |              |
| 触发条件 | 属性                      | 成员属性         | 结果       |
|----------|--------------------------|-----------------|------------|
| 条件     | 会员等级                 | 订单金额        | 折扣率     |
| 条件     | 枚举类型                 | double          | double     |
| VIP      | 金卡会员                 | 金额 > 1000     | 0.15       |
| 普通用户 | 无会员                   | 金额 > 2000     | 0.10       |
| 新用户   | 首单                     | 任意金额        | 0.20       |

复杂事件处理(CEP)案例

实时监控系统

package com.example.drools.cep
import com.example.drools.model.SensorData;
import java.util.Date;
import java.util.concurrent.TimeUnit;
// 定义事件窗口和时序逻辑
declare SensorAlarm
    @role(event)
    @timestamp(timestamp)
    @expires(24h)
end
// 连续高频异常检测
rule "Detect Continuous High Temperature"
    when
        // 在10秒内连续3次高温报警
        $threshold : Number(doubleValue > 85) from accumulate(
            SensorData(time > currentTime - 10s, temperature > 80),
            count($count))
        $count : Number(intValue >= 3)
    then
        System.out.println("设备温度异常!连续高温报警次数:" + $count);
        insert(new SensorAlarm("HIGH_TEMPERATURE", 
                               "设备连续高温,需要停机检查"));
end

完整项目配置(kmodule.xml)

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="rules" packages="com.example.drools.rules">
        <ksession name="discount-session" type="stateful"/>
        <ksession name="stateless-session" type="stateless"/>
    </kbase>
    <kbase name="risk-rules" packages="com.example.drools.risk">
        <ksession name="risk-session" type="stateful"/>
    </kbase>
    <kbase name="cep-rules" packages="com.example.drools.cep">
        <ksession name="cep-session" type="stateful">
            <clock type="realtime"/>
        </ksession>
    </kbase>
</kmodule>

性能优化与最佳实践

规则冲突解决

// 设置规则优先级
rule "High Priority Rule"
    salience 100  // 数值越大优先级越高
    when
        // 条件
    then
        // 执行逻辑
end
// 使用组和议程
rule "Group A Rule"
    agenda-group "main"
    activation-group "critical"
end
rule "Alternating Rule"
    agenda-group "main"  
    activation-group "alternating"
end

动态规则加载

public class DynamicRuleLoader {
    public static KieSession loadRuleFromString(String ruleContent) {
        KieHelper helper = new KieHelper();
        helper.addContent(ruleContent, ResourceType.DRL);
        KieBase kbase = helper.build();
        return kbase.newKieSession();
    }
    public static void updateRuleInRuntime(KieSession session, String newRule) {
        // 重新加载并替换规则
    }
}

大数据量优化

// 使用无状态会话
StatelessKieSession statelessSession = kContainer.newStatelessKieSession("stateless-session");
statelessSession.execute(orderList);
// 启用增量编译
KieServices kieServices = KieServices.Factory.get();
KieRepository kr = kieServices.getRepository();
KieBuilder kieBuilder = kieServices.newKieBuilder(kr);
kieBuilder.setIncremental(true);

抱歉,评论功能暂时关闭!