Drools规则引擎初体验

news2025/4/24 21:41:09

前言

假设有这样一个场景,订单管理系统需要根据用户的消费情况,来为每个用户发放不同程度的优惠券,这个发放规则复杂且多变,我们该怎么办?在代码中写死显然是不可取的,规则一变就要修改代码,频繁重启服务不说,还极易出错,用户体验就很差了。

那么有没有办法改善这一现状呢?当然是有的,把规则判定逻辑和具体业务分离,规则可以随意编辑替换,应用无需重启。Drools规则引擎就是专门为了解决上述应用场景的问题而开发出来的,下面笔者将详细介绍其基本概念规则。


一、Drools简介

‌Drools‌是一个开源的业务规则管理系统(BRMS),它使用RETE算法实现,特别适用于Java环境。Drools由JBoss开发,并作为JBoss Rules发布,其前身是Codehaus的一个开源项目。Drools支持XML和多种编程语言(如Java、Groovy等),使得业务规则能够以自然的方式表达和执行‌。

官网地址
中文教程地址


二、Drools的应用场景

  1. 动态业务规则管理‌:在需要频繁调整业务规则的场景中,Drools可以将业务规则与系统代码分离,使得规则的调整无需重新编译和部署应用程序,提高了系统的响应速度和灵活性‌

  2. 复杂决策逻辑‌:在涉及复杂决策逻辑的业务场景中,Drools可以帮助将决策逻辑抽象化,使得业务人员可以参与规则的定义和管理,降低了技术门槛‌

  3. 实时决策支持‌:在需要实时决策支持的应用中,Drools可以快速解释和执行业务规则,提供实时的决策支持。


三、Drools规则解析

常用规则

Drools规则是基于Java的业务规则管理系统的核心组成部分。

主要元素

  • 规则名称(rule):每个规则都有一个唯一的名称,用于标识该规则。
  • 命名空间(namespace):规则文件中的package声明定义了规则的命名空间。
  • 导入语句(import):用于导入Java类或模型对象,以便在规则中使用。
  • 全局变量(global):允许规则访问全局变量,这些变量通常由应用程序设置。
  • 条件部分(when):也称为Left Hand Side (LHS),定义了规则触发的条件。可以包含多个条件,使用逻辑运算符连接。
  • 动作部分(then):也称为Right Hand Side (RHS),定义了当条件满足时执行的动作。
  • 规则属性(attributes):如salience(优先级)、no-loop(防止循环触发)、enabled(是否启用规则)等,用于控制规则的行为。

高级特性

  • 查询(query):用于查询工作内存中的数据。
  • 函数(function):可以在规则中定义和调用自定义函数。
  • 事件处理(event processing):支持复杂的事件处理场景。
  • 规则流(ruleflow):用于定义规则的执行顺序和流程。

规则基本示例

  1. 规则名称(rule)
rule "Check Customer Discount"
when
    // 条件部分
then
    // 动作部分
end
  1. 命名空间(namespace)
package com.example.rules;
  1. 导入语句(import)
package com.drools.project.ruleService;

import com.example.model.Customer;
import com.example.model.Order;

rule "Check Customer Discount"
when
    $customer : Customer()
then
    // 动作部分
end

  1. 全局变量(global)
package com.example.rules

import com.example.model.Customer;
global java.util.List discountList;

rule "Check Customer Discount"
when
    $customer : Customer(discount > 0)
then
    discountList.add($customer);
end

  1. 条件部分(when)
rule "Check Customer Discount"
when
    $customer : Customer(discount > 0)
    $order : Order(customer == $customer, totalAmount > 1000)
then
    // 动作部分
end

  1. 动作部分(then)
rule "Check Customer Discount"
when
    $customer : Customer(discount > 0)
then
    System.out.println("Customer " + $customer.getName() + " has a discount.");
end

  1. 规则属性(attributes)
rule "High Priority Rule"
    salience 100
    no-loop true
when
    $customer : Customer(discount > 0)
then
    System.out.println("High priority rule triggered for customer: " + $customer.getName());
end

  1. 查询(query)
query "findCustomersWithDiscount"
    $customer : Customer(discount > 0)
end

rule "Print Customers With Discount"
when
    $customers : List() from query "findCustomersWithDiscount"
then
    for (Customer customer : $customers) {
        System.out.println("Customer with discount: " + customer.getName());
    }
end

  1. 函数(function)
package com.example.rules

import com.example.model.Customer;

function boolean isEligibleForDiscount(Customer customer) {
    return customer.getDiscount() > 0 && customer.getTotalSpent() > 1000;
}

rule "Check Customer Eligibility"
when
    $customer : Customer(isEligibleForDiscount($customer))
then
    System.out.println("Customer " + $customer.getName() + " is eligible for discount.");
end

  1. 事件处理(event processing)
declare Event
    @role(event)
    type : String
    timestamp : long
end

rule "Process Login Event"
when
    $event : Event(type == "LOGIN", timestamp > now - 60000)
then
    System.out.println("Login event detected within the last minute.");
end

  1. 规则流(ruleflow)
package com.example.rules

import com.example.model.Customer;

ruleflow-group "Order Processing"

rule "Step 1: Validate Customer"
ruleflow-group "Order Processing"
salience 10
when
    $customer : Customer()
then
    System.out.println("Validating customer...");
end

rule "Step 2: Process Order"
ruleflow-group "Order Processing"
salience 5
when
    $order : Order()
then
    System.out.println("Processing order...");
end

咱说啊,上面这些规则,真到实际开发里头,未必都能派上用场。平时也就用那最基础的几样,您说是不是这个理儿?咱用规则引擎,图的就是个方便、能简化开发流程。要是把规则弄得太复杂,还不如直接写代码来得痛快呢!您几位觉得呢?(哈哈哈哈……),下面笔者通过一个实战案例来向各位逐一展示下基础用法


四、drools-project规则实战

gitee地址下载git clone https://gitee.com/buxingzhe/drools-project.git

笔者新建了一个Drools-Project的SpringBoot应用,用来测试这个drools的规则是如何使用的

在这里插入图片描述

环境准备:JDK17、Maven3.9.8、IDEA2024.1

这里是笔者的开发环境,读者朋友可以根据自己的环境自行修改依赖版本适配

pom.xml内容如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.drools</groupId>
    <artifactId>Drools-Project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Drools-Project</name>
    <description>Drools-Project</description>
    <properties>
        <java.version>17</java.version>
        <kie.version>7.59.0.Final</kie.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--drools相关依赖-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>${kie.version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>${kie.version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-decisiontables</artifactId>
            <version>${kie.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

可以看到drools相关依赖的版本是 7.59.0.Final


application.yml

server:
  port: 8099
spring:
  application:
    name: Drools-Project

# drools 配置文件读取路径
drools:
  store:
    path: D:/drools

这个是配置文件内容,核心是这个drools 配置文件读取路径,因为笔者的电脑是windows操作系统,笔者把规则文件都放在了D盘下的一个drools文件夹中了,规则配置要求外部化,可以随时加载修改,当然读者也可以把配置路径放在Nacos等配置中心统一管理更方便修改。实际应用中我们的服务一般部署在linux操作系统中,自行新建一个文件路径,比如 /opt/drools,那就在Nacos配置文件里配置即可。


DroolsFilePathConfig 规则文件路径配置

package com.drools.project.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * drools规则文件存放路径
 */
@Component
@ConfigurationProperties(prefix = "drools.store")
public class DroolsFilePathConfig {
    /**
     * drools规则文件存放路径,默认从D盘根目录读取(linux服务器,则自行决定规则文件存放路径)
     */
    @Value("${drools.store.path:D:/drools}")
    private String path;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

这段代码定义了一个配置类 DroolsFilePathConfig,用于管理Drools规则文件的存放路径。通过 @Component 注解使其成为Spring容器中的一个组件,并使用 @ConfigurationProperties 和 @Value 注解从配置文件中读取路径,默认路径为 D:/drools。

注意这里没有使用 @RefreshScope 支持配置动态刷新的注解,如果规则路径有变更,即使是在Nacos中配置的,也还是需要重启应用服务,重新加载配置才能生效,想要使用这个注解,必须引入如下依赖,一般微服务分布式应用可以直接使用这个注解进行配置的动态刷新功能,因为已经引入spring cloud相关依赖了

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

DroolsConfig规则文件加载配置类

package com.drools.project.config;

import jakarta.annotation.Resource;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * @author hulei
 * 规则文件的配置类
 */
@Configuration
public class DroolsConfig {

    /**
     * 外部规则文件路径配置类
     */
    @Resource
    private DroolsFilePathConfig droolsFilePathConfig;

    /**
     * classpath路径下的规则文件根路径
     */
    private static final String CLASSPATH_RULES_PATH = "src/main/resources/";

    /**
     * 创建KieServices对象
     */
    private static final KieServices kieServices = KieServices.Factory.get();

//===========================================内部classPath下drools文件加载方式,不推荐此种方式==================================

    /**
     * 本方法规则为写死的,实际开发中不灵活,当规则文件需要动态变换时,则不适用
     */
    @Bean
    public KieContainer kieContainer() throws IOException {
        KieFileSystem kfs = kieServices.newKieFileSystem();
        Files.walkFileTree(Paths.get(CLASSPATH_RULES_PATH), new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (file.toString().endsWith(".drl")) {
                    kfs.write(ResourceFactory.newFileResource(file.toFile()));
                }
                return FileVisitResult.CONTINUE;
            }
        });

        KieBuilder kb = kieServices.newKieBuilder(kfs);
        kb.buildAll();
        KieModule kieModule = kb.getKieModule();
        return kieServices.newKieContainer(kieModule.getReleaseId());
    }


//===========================================外部drools文件加载方式,推荐此种方式==============================================
//    /**
//     * 动态获取外部规则文件,可以获取多个规则文件,解析加载
//     * kfs.write("src/main/resources/rules/" + ruleFile.getName(),
//     * kieServices.getResources().newFileSystemResource(ruleFile));
//     * 这里的规则文件从ruleFile读取后写入到classpath路径下src/main/resources/rules/
//     * 是虚拟的,实际并不生成文件,需要注意的是虚拟路径的前缀必须是src/main/resources,否则报错
//     * 至于resources后面的路径可以随意写,也可以不写
//     */
//    @Bean
//    public KieContainer getKieContainer() {
//        KieFileSystem kfs = kieServices.newKieFileSystem();
//        // 获取指定目录下的所有规则文件
//        File directory = new File(droolsFilePathConfig.getPath());
//        if (directory.isDirectory()) {
//           processDirectory(directory, kfs, kieServices);
//        }
//        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs);
//        kieBuilder.buildAll();
//        KieModule kieModule = kieBuilder.getKieModule();
//        return kieServices.newKieContainer(kieModule.getReleaseId());
//    }
//
//    /**
//     * 多级目录递归处理
//     */
//    private void processDirectory(File directory, KieFileSystem kfs, KieServices kieServices) {
//        File[] files = directory.listFiles();
//        if (files != null) {
//            for (File file : files) {
//                if (file.isDirectory()) {
//                    // 递归处理子目录
//                    processDirectory(file, kfs, kieServices);
//                } else if (file.getName().endsWith(".drl")) {
//                    kfs.write("src/main/resources/" + file.getName(),
//                            kieServices.getResources().newFileSystemResource(file));
//                }
//            }
//        }
//    }
}

DroolsConfig 是核心类了,主要是加载各种规则配置文件的,此类文件是以.drl为后缀,IDEA中可以下载一个插件Drools用以加载显示此类文件格式
在这里插入图片描述


上面的类中,笔者提供了两种方式加载.drl后缀的规则文件

第一种是 classpath路径下的规则文件路径

在这里插入图片描述
可以看到几个测试的规则文件是放在src/main/resources/rules下的,代码中是使用了递归遍历src/main/resources/路径下的所有.drl后缀的文件,所以不管有多少层都可以遍历到

在这里插入图片描述
这种一般是我们开发后测试规则文件是否生效时使用,一般就放在resources文件目录下,对于线上随时更改替换规则文件不方便,不建议使用。


第二种是外部drools文件加载方式

这是自己定义加载文件路径,方便随时替换的,推荐使用

在这里插入图片描述

不过笔者又发现可以直接按照第一种方式写,之不过换了下加载路径Paths.get(droolsFilePathConfig.getPath())。。。。java自己提供了遍历文件树的方法,笔者看了下,用的还不是递归,是自定义栈队列的方式,这样可以避免深层次递归造成的栈溢出问题,这种方式更好。递归是代码简单易于理解,但是树的层次比较深时,会发生栈溢出报错情况。

    /**
     * 动态获取外部规则文件,可以获取多个规则文件,解析加载
     * kfs.write("src/main/resources/rules/" + ruleFile.getName(),
     * kieServices.getResources().newFileSystemResource(ruleFile));
     * 这里的规则文件从ruleFile读取后写入到classpath路径下src/main/resources/rules/
     * 是虚拟的,实际并不生成文件,需要注意的是虚拟路径的前缀必须是src/main/resources,否则报错
     * 至于resources后面的路径可以随意写,也可以不写
     */
    @Bean
    public KieContainer kieContainer() throws IOException {
        KieFileSystem kfs = kieServices.newKieFileSystem();
        // 获取指定目录下的所有规则文件,其实可以用后面的//======之间的内容替换,
//        File directory = new File(droolsFilePathConfig.getPath());
//        if (directory.isDirectory()) {
//           processDirectory(directory, kfs, kieServices);
//        }
//=================================================================================
        Files.walkFileTree(Paths.get(droolsFilePathConfig.getPath()), new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (file.toString().endsWith(".drl")) {
                    kfs.write(ResourceFactory.newFileResource(file.toFile()));
                }
                return FileVisitResult.CONTINUE;
            }
        });
//=================================================================================
        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs);
        kieBuilder.buildAll();
        KieModule kieModule = kieBuilder.getKieModule();
        return kieServices.newKieContainer(kieModule.getReleaseId());
    }

    /**
     * 多级目录递归处理
     */
    private void processDirectory(File directory, KieFileSystem kfs, KieServices kieServices) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    // 递归处理子目录
                    processDirectory(file, kfs, kieServices);
                } else if (file.getName().endsWith(".drl")) {
                    kfs.write("src/main/resources/" + file.getName(),
                            kieServices.getResources().newFileSystemResource(file));
                }
            }
        }
    }

DroolsProjectApplication规则测试

至于各个规则关键词的测试呢,笔者是放在启动类里了,实现了CommandLineRunner,重写了其中的run方法

package com.drools.project;

import com.drools.project.model.complex.Event;
import com.drools.project.model.complex.Student;
import com.drools.project.model.coupon.Order;
import com.drools.project.model.discount.OrderDiscount;
import com.drools.project.model.discount.OrderRequest;
import com.drools.project.model.coupon.User;
import com.drools.project.ruleService.ComplexService;
import com.drools.project.ruleService.CouponService;
import com.drools.project.ruleService.OrderDiscountService;
import jakarta.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@SpringBootApplication
public class DroolsProjectApplication implements CommandLineRunner {

    @Resource
    private CouponService couponService;

    @Resource
    private OrderDiscountService orderDiscountService;

    @Resource
    private ComplexService complexService;


    public static void main(String[] args) {
        SpringApplication.run(DroolsProjectApplication.class, args);
    }

    @Override
    public void run(String... args) {
        System.out.println("=======================规则案例一--基本用法规则==============================");
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, -1);
        Date oneYearAgo = calendar.getTime();

        Order order1 = new Order();
        order1.setCategory("Electronics");
        order1.setAmount(300);
        order1.setOrderDate(oneYearAgo);

        Order order2 = new Order();
        order2.setCategory("Books");
        order2.setAmount(200);
        order2.setOrderDate(oneYearAgo);

        Order order3 = new Order();
        order3.setCategory("Electronics");
        order3.setAmount(600);
        order3.setOrderDate(new Date());

        List<Order> orders = new ArrayList<>();
        orders.add(order1);
        orders.add(order2);
        orders.add(order3);

        User user = new User();
        user.setName("John Doe");
        user.setVip(true);
        user.setPurchaseCount(15);
        user.setTotalPurchaseAmount(2000);
        user.setOrders(orders);
        user.setCouponAmount(0);
        user.setLocation("Shanghai");
        user.setPoints(1500);
        couponService.applyCoupons(user);

        System.out.println("当前用户总优惠券金额为: " + user.getCouponAmount());

        System.out.println("=======================规则案例二--global规则==============================");

        OrderRequest orderRequest = new OrderRequest();
        orderRequest.setCustomerNumber("123456");
        orderRequest.setAge(55);
        orderRequest.setAmount(2000);
        orderRequest.setCustomerType(com.drools.project.enums.CustomerType.LOYAL);

        OrderDiscount orderDiscount = orderDiscountService.getDiscount(orderRequest);
        System.out.println("获得的折扣:" + orderDiscount.getDiscount());

        //===========================================================================================
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("John",  20, 90,"Shanghai"));
        studentList.add(new Student("Jane",  25, 85,"Beijing"));
        studentList.add(new Student("Jim",   17, 95,"Shanghai"));
        studentList.add(new Student("Judy",  35, 80,"Beijing"));
        studentList.add(new Student("Jason", 15, 90,"Shanghai"));
        studentList.add(new Student("Julia", 45, 85,"Beijing"));
        studentList.add(new Student("James", 19, 76,"Shanghai"));
        studentList.add(new Student("Julie", 16, 80,"Beijing"));

        System.out.println("=======================规则案例三--query函数==============================");
        complexService.complexQuery(studentList);
        System.out.println("=======================规则案例四--function函数==============================");
        complexService.complexFunction(studentList);
        System.out.println("=======================规则案例五--priority规则==============================");
        complexService.complexPriority(studentList);
        System.out.println("=======================规则案例六--role,flow,group规则==============================");
        complexService.complexRoleFlowGroup();
        System.out.println("=======================规则案例七--event规则==============================");
        List<Event> eventList = new ArrayList<>();
        long timestamp = System.currentTimeMillis();
        eventList.add(new Event("LOGIN", timestamp-50000));
        eventList.add(new Event("LOGIN", timestamp-40000));
        eventList.add(new Event("LOGIN", timestamp-80000));
        eventList.add(new Event("LOGOUT", timestamp-30000));
        complexService.complexEvent(eventList);
    }
}

各规则测试结果如下

在这里插入图片描述


五、代码结构

在这里插入图片描述
上图展示的是三个测试的service,对应三个不同的drools文件

  • coupon.drl:使用了优惠卷发放规则来展示基本用法,对应规则服务类是CouponService
  • discount.drl:根据用户年龄、购买次数等情况计算打折规则,没什么特别的,注意dialect "mvel"用法,这个具体在规则文件中有解释
  • complex.drl:展示了query、event、ruleflow group等高级规则使用方式

注意:笔者代码中的实体类并没有使用lombok,因为笔者的jdk版本和drools较高,相关drools依赖版本不支持lombok写法了

到这里,关于Drools的介绍就结束了,主要展示了基本用法,笔者写这篇文章也仅仅是探索学习其用法,因为工作中遇到需要使用规则引擎的场景,读者朋友可以把代码拉下来跑一下看看,大部分都有注释,尤其是规则文件中,相信诸位都能看得明白,是在不会的可在评论区找我,我尽可能回答大家。

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

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

相关文章

K8S ReplicaSet 控制器

一、理论介绍 今天我们来实验 ReplicaSet 控制器&#xff08;也叫工作负载&#xff09;。官网描述如下&#xff1a; 1、是什么&#xff1f; ReplicaSet 副本集&#xff0c; 维护一组稳定的副本 Pod 集合。 2、为什么需要&#xff1f; 解决 pod 被删除了&#xff0c;不能自我恢…

基于springboot校园点歌系统

基于Spring Boot的校园点歌系统是一种专为校园场景设计的音乐点播平台&#xff0c;它能够丰富学生的校园生活&#xff0c;提升学生的娱乐体验。以下是对该系统的详细介绍&#xff1a; 一、系统背景与意义 在校园环境中&#xff0c;学生们对于音乐有着浓厚的兴趣&#xff0c;传…

【R语言】数据操作

一、查看和编辑数据 1、查看数据 直接打印到控制台 x <- data.frame(a1:20, b21:30) x View()函数 此函数可以将数据以电子表格的形式进行展示。 用reshape2包中的tips进行举例&#xff1a; library("reshape2") View(tips) head()函数 查看前几行数据&…

【C++】2.高并发内存池 -- 如何设计一个定长内存池

博客主题&#xff1a;如何设计一个定长内存池 个人主页&#xff1a;https://blog.csdn.net/sobercq CSDN专栏&#xff1a;https://blog.csdn.net/sobercq/category_12884309.html Gitee链接&#xff1a;https://gitee.com/yunshan-ruo/high-concurrency-memory-pool 文章目录 前…

Redis --- 使用Feed流实现社交平台的新闻流

要实现一个 Feed 流&#xff08;类似于社交媒体中的新闻流&#xff09;&#xff0c;通常涉及以下几个要素&#xff1a; 内容发布&#xff1a;用户发布内容&#xff08;例如文章、状态更新、图片等&#xff09;。内容订阅&#xff1a;用户可以订阅其他用户的内容&#xff0c;获…

游戏引擎学习第88天

仓库:https://gitee.com/mrxiao_com/2d_game_2 调查碰撞检测器中的可能错误 在今天的目标是解决一个可能存在的碰撞检测器中的错误。之前有人提到在检测器中可能有一个拼写错误&#xff0c;具体来说是在测试某个变量时&#xff0c;由于引入了一个新的变量而没有正确地使用它&…

c++中priority_queue的应用及模拟实现

1.介绍 priority_queue 是一种数据结构&#xff0c;它允许你以特定的顺序存储和访问元素。在 C 标准模板库&#xff08;STL&#xff09;中&#xff0c;priority_queue 是一个基于容器适配器的类模板&#xff0c;它默认使用 std::vector 作为底层容器&#xff0c;并且默认使用最…

游戏引擎 Unity - Unity 设置为简体中文、Unity 创建项目

Unity Unity 首次发布于 2005 年&#xff0c;属于 Unity Technologies Unity 使用的开发技术有&#xff1a;C# Unity 的适用平台&#xff1a;PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域&#xff1a;开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…

【Elasticsearch】geohex grid聚合

在 Elasticsearch 中&#xff0c;地理边界过滤是一种用于筛选地理数据的技术&#xff0c;它可以根据指定的地理边界形状&#xff08;如矩形、多边形等&#xff09;来过滤符合条件的文档。这种方法在地理空间数据分析中非常有用&#xff0c;尤其是在需要将数据限制在特定地理区域…

crewai框架第三方API使用官方RAG工具(pdf,csv,json)

最近在研究调用官方的工具&#xff0c;但官方文档的说明是在是太少了&#xff0c;后来在一个视频里看到了如何配置&#xff0c;记录一下 以PDF RAG Search工具举例&#xff0c;官方文档对于自定义模型的说明如下&#xff1a; 默认情况下&#xff0c;该工具使用 OpenAI 进行嵌…

算法 哈夫曼树和哈夫曼编码

目录 前言 一&#xff0c;二进制转码 二&#xff0c;哈夫曼编码和哈夫曼树 三&#xff0c;蓝桥杯 16 哈夫曼树 总结 前言 这个文章需要有一定的树的基础&#xff0c;没学过树的伙伴可以去看我博客树的文章 当我们要编码一个字符串转成二进制的时候&#xff0c;我们要怎么…

Sumatra PDF:小巧免费,满足多样阅读需求

Sumatra PDF是一款完全免费的本地阅读器软件&#xff0c;以小巧的体积和全面的功能受到用户青睐。如今&#xff0c;它已经更新到3.3版本&#xff0c;带来了更多实用功能&#xff0c;尤其是新增的注释功能&#xff0c;值得我们再次关注。 软件特色 轻量级体积&#xff1a;压缩…

TiDB 分布式数据库多业务资源隔离应用实践

导读 随着 TiDB 在各行业客户中的广泛应用 &#xff0c;特别是在多个业务融合到一套 TiDB 集群中的场景&#xff0c;各企业对集群内多业务隔离的需求日益增加。与此同时&#xff0c;TiDB 在多业务融合场景下的资源隔离方案日趋完善&#xff0c;详情可参考文章 《你需要什么样的…

105,【5】buuctf web [BJDCTF2020]Easy MD5

进入靶场 先输入试试回显 输入的值成了password的内容 查看源码&#xff0c;尝试得到信息 什么也没得到 抓包&#xff0c;看看请求与响应里有什么信息 响应里得到信息 hint: select * from admin where passwordmd5($pass,true) 此时需要绕过MD5&#xff08;&#xff09;函…

BFS(广度优先搜索)——搜索算法

BFS&#xff0c;也就是广度&#xff08;宽度&#xff09;优先搜索&#xff0c;二叉树的层序遍历就是一个BFS的过程。而前、中、后序遍历则是DFS&#xff08;深度优先搜索&#xff09;。从字面意思也很好理解&#xff0c;DFS就是一条路走到黑&#xff0c;BFS则是一层一层地展开。…

33.Word:国家中长期人才发展规划纲要【33】

目录 NO1.2样式​ NO3​ 图表 ​ NO4.5.6​ 开始→段落标记视图→导航窗格→检查有无遗漏 NO1.2样式 F12/另存为&#xff1a;Word.docx&#xff1a;考生文件夹样式的复制样式的修改 样式的应用&#xff08;没有相似/超级多的情况下&#xff09;——替换 [ ]通配符&#x…

gym-anytrading

参考&#xff1a;https://github.com/upb-lea/gym-electric-motor AnyTrading 是一组基于 reinforcement learning (RL) 的 trading algorithms&#xff08;交易算法&#xff09;的 OpenAI Gym 环境集合。 该项目主要用于foreign exchange (FOREX) 和 stock markets (股票市场)…

如何自定义软件安装路径及Scoop包管理器使用全攻略

如何自定义软件安装路径及Scoop包管理器使用全攻略 一、为什么无法通过WingetUI自定义安装路径&#xff1f; 问题背景&#xff1a; WingetUI是Windows包管理器Winget的图形化工具&#xff0c;但无法直接修改软件的默认安装路径。原因如下&#xff1a; Winget设计限制&#xf…

私有化部署 DeepSeek + Dify,构建你的专属私人 AI 助手

私有化部署 DeepSeek Dify&#xff0c;构建你的专属私人 AI 助手 概述 DeepSeek 是一款开创性的开源大语言模型&#xff0c;凭借其先进的算法架构和反思链能力&#xff0c;为 AI 对话交互带来了革新性的体验。通过私有化部署&#xff0c;你可以充分掌控数据安全和使用安全。…

Java 进阶 01 —— 5 分钟回顾一下 Java 基础知识

Java 进阶 01 —— 5 分钟回顾一下 Java 基础知识 Java 生态圈Java 跨平台的语言 Java 虚拟机规范JVM 跨语言的平台多语言混合编程两种架构 举例 JVM 的生命周期 虚拟机的启动虚拟机的执行虚拟机的退出 JVM 发展历程 Sun Classic VMExact VMHotSpotBEA 的 JRockitIBM 的 J9 …