commit
					eab23f8499
				
				 17 changed files with 889 additions and 0 deletions
			
			
		| @ -0,0 +1,6 @@@@ -0,0 +1,6 @@ | ||||
| /.classpath | ||||
| /.project | ||||
| /.settings | ||||
| /bin/ | ||||
| /logs | ||||
| /target | ||||
| @ -0,0 +1,8 @@@@ -0,0 +1,8 @@ | ||||
| server.port=80 | ||||
| server.servlet.context-path=/ | ||||
| dev=on | ||||
| # 程序自身数据源配置 | ||||
| spring.datasource.url=jdbc:mysql://localhost:3306/admin?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true | ||||
| spring.datasource.username=root | ||||
| spring.datasource.password=51131420 | ||||
| 
 | ||||
| @ -0,0 +1,46 @@@@ -0,0 +1,46 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <configuration debug="false"> | ||||
| 
 | ||||
|     <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> | ||||
|     <property name="LOG_HOME" value="D:/logs/drools" /> | ||||
| 
 | ||||
|     <!--控制台日志, 控制台输出 --> | ||||
|     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||||
|         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | ||||
|             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--> | ||||
|             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> | ||||
|         </encoder> | ||||
|     </appender> | ||||
| 
 | ||||
|     <!--文件日志, 按照每天生成日志文件 --> | ||||
|     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!--日志文件输出的文件名--> | ||||
|             <FileNamePattern>${LOG_HOME}/drools-%d{yyyy-MM-dd}.log</FileNamePattern> | ||||
|             <!--日志文件保留天数--> | ||||
|             <MaxHistory>30</MaxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | ||||
|             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> | ||||
|             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> | ||||
|         </encoder> | ||||
|         <!--日志文件最大的大小--> | ||||
|         <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> | ||||
|             <MaxFileSize>10MB</MaxFileSize> | ||||
|         </triggeringPolicy> | ||||
|     </appender> | ||||
| 
 | ||||
|     <logger name="vip.xumy" level="DEBUG"/> | ||||
|      | ||||
|     <!--myibatis log configure--> | ||||
|     <logger name="com.apache.ibatis" level="TRACE"/> | ||||
|     <logger name="java.sql.Connection" level="DEBUG"/> | ||||
|     <logger name="java.sql.Statement" level="DEBUG"/> | ||||
|     <logger name="java.sql.PreparedStatement" level="DEBUG"/> | ||||
| 
 | ||||
|     <!-- 日志输出级别 --> | ||||
|     <root level="INFO"> | ||||
|         <appender-ref ref="STDOUT" /> | ||||
|         <appender-ref ref="FILE"/> | ||||
|     </root> | ||||
| </configuration> | ||||
| @ -0,0 +1,146 @@@@ -0,0 +1,146 @@ | ||||
| <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 http://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>2.7.1</version> | ||||
| 	</parent> | ||||
| 	<groupId>vip.xumy.drools</groupId> | ||||
| 	<artifactId>xumy_drools</artifactId> | ||||
| 	<version>0.0.0</version> | ||||
| 	<name>drools</name> | ||||
| 	<description>xumy-drools</description> | ||||
| 	<packaging>jar</packaging> | ||||
| 
 | ||||
| 	<properties> | ||||
| 		<java.version>17</java.version> | ||||
| 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
| 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||||
| 
 | ||||
| 		<core.version>1.0.0</core.version> | ||||
| 		<log4j.version>1.2.17</log4j.version> | ||||
| 		<fastjson.version>1.2.46</fastjson.version> | ||||
| 		<druid.version>1.1.9</druid.version> | ||||
| 		<mybatis-plus.version>3.5.1</mybatis-plus.version> | ||||
| 		<mybatis.pagehelper.version>1.4.6</mybatis.pagehelper.version> | ||||
| 		<drools.version>7.74.1.Final</drools.version> | ||||
| 		<kie.spring.version>7.74.1.Final</kie.spring.version> | ||||
| 	</properties> | ||||
| 
 | ||||
| 	<dependencies> | ||||
| 
 | ||||
| 		<dependency> | ||||
| 			<groupId>vip.xumy.core</groupId> | ||||
| 			<artifactId>xumy_core</artifactId> | ||||
| 			<version>${core.version}</version> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!-- 代码修改之后可以实时生效,该模块在完整的打包环境下运行的时候会被禁用 --> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.boot</groupId> | ||||
| 			<artifactId>spring-boot-devtools</artifactId> | ||||
| 			<optional>true</optional> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> | ||||
| 		<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> | ||||
| 			<exclusions> | ||||
| 				<!-- 单元测试不使用Junit4,使用Junit5 --> | ||||
| 				<exclusion> | ||||
| 					<groupId>junit</groupId> | ||||
| 					<artifactId>junit</artifactId> | ||||
| 				</exclusion> | ||||
| 				<exclusion> | ||||
| 					<groupId>org.junit.vintage</groupId> | ||||
| 					<artifactId>junit-vintage-engine</artifactId> | ||||
| 				</exclusion> | ||||
| 			</exclusions> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!--junit 测试包--> | ||||
| 		<dependency> | ||||
| 			<groupId>org.junit.jupiter</groupId> | ||||
| 			<artifactId>junit-jupiter-api</artifactId> | ||||
| 			<scope>test</scope> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!-- mysql驱动 --> | ||||
| 		<dependency> | ||||
| 			<groupId>mysql</groupId> | ||||
| 			<artifactId>mysql-connector-java</artifactId> | ||||
| 			<scope>runtime</scope> | ||||
| 		</dependency> | ||||
| 		<!-- alibaba的druid数据库连接池 --> | ||||
| 		<dependency> | ||||
| 			<groupId>com.alibaba</groupId> | ||||
| 			<artifactId>druid-spring-boot-starter</artifactId> | ||||
| 			<version>${druid.version}</version> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!-- mybatis plus--> | ||||
| 		<dependency> | ||||
| 			<groupId>com.baomidou</groupId> | ||||
| 			<artifactId>mybatis-plus-boot-starter</artifactId> | ||||
| 			<version>${mybatis-plus.version}</version> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 		<!-- mybatis的pagehelper --> | ||||
| 		<dependency> | ||||
| 			<groupId>com.github.pagehelper</groupId> | ||||
| 			<artifactId>pagehelper-spring-boot-starter</artifactId> | ||||
| 			<version>${mybatis.pagehelper.version}</version> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 
 | ||||
| 		<!--drools规则引擎--> | ||||
| 		<dependency> | ||||
| 			<groupId>org.drools</groupId> | ||||
| 			<artifactId>drools-core</artifactId> | ||||
| 			<version>${drools.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.drools</groupId> | ||||
| 			<artifactId>drools-compiler</artifactId> | ||||
| 			<version>${drools.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.drools</groupId> | ||||
| 			<artifactId>drools-templates</artifactId> | ||||
| 			<version>${drools.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.kie</groupId> | ||||
| 			<artifactId>kie-api</artifactId> | ||||
| 			<version>${drools.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.kie</groupId> | ||||
| 			<artifactId>kie-spring</artifactId> | ||||
| 			<version>${drools.version}</version> | ||||
| 		</dependency> | ||||
| 	 | ||||
| 
 | ||||
| 	</dependencies> | ||||
| 
 | ||||
| 	<!-- Package as an executable jar --> | ||||
| 	<build> | ||||
| 		<finalName>drools</finalName> | ||||
| 		<plugins> | ||||
| 			<plugin> | ||||
| 				<groupId>org.springframework.boot</groupId> | ||||
| 				<artifactId>spring-boot-maven-plugin</artifactId> | ||||
| 				<configuration> | ||||
| 					<executable>true</executable> | ||||
| 				</configuration> | ||||
| 			</plugin> | ||||
| 		</plugins> | ||||
| 	</build> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,14 @@@@ -0,0 +1,14 @@ | ||||
| package vip.xumy.drools; | ||||
| 
 | ||||
| import org.springframework.boot.SpringApplication; | ||||
| 
 | ||||
| import vip.xumy.drools.conf.DroolsInitializer; | ||||
| 
 | ||||
| public class DroolsApplocation { | ||||
| 
 | ||||
| 	public static void main(String[] args) { | ||||
| 		Class<?>[] arr = new Class<?>[] { DroolsInitializer.class }; | ||||
| 		SpringApplication.run(arr, args); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,150 @@@@ -0,0 +1,150 @@ | ||||
| package vip.xumy.drools.action; | ||||
| 
 | ||||
| import java.text.MessageFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Random; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| import org.drools.core.time.SessionPseudoClock; | ||||
| import org.kie.api.runtime.KieSession; | ||||
| 
 | ||||
| import lombok.extern.log4j.Log4j2; | ||||
| import vip.xumy.core.utils.DateUtil; | ||||
| import vip.xumy.drools.pojo.CDR; | ||||
| 
 | ||||
| /** | ||||
|  * Ownership belongs to the company | ||||
|  * | ||||
|  * @author:mengyxu | ||||
|  * @date:2023年9月22日 | ||||
|  */ | ||||
| 
 | ||||
| @Log4j2 | ||||
| public class CdrGenerator { | ||||
| 	public static final List<CDR> CDRS = new ArrayList<>(); | ||||
| 	static { | ||||
| 		CDRS.add(new CDR(0, "CN", "CN", "460018765432101", "8618601234567", 2, null)); | ||||
| 		CDRS.add(new CDR(1, "CN", "CN", "460018765432101", "8618601234567", 3, null)); | ||||
| 		CDRS.add(new CDR(2, "CN", "CN", "460018765437788", "8618601237788", 2, null)); | ||||
| 		CDRS.add(new CDR(3, "JP", "CN", "460018765432101", "8618601234567", 2, null)); | ||||
| 		CDRS.add(new CDR(4, "CN", "CN", "460018765437755", "8618601237755", 2, null)); | ||||
| 		CDRS.add(new CDR(5, "JP", "CN", "460018765432101", "8618601234567", 45, null)); | ||||
| 		CDRS.add(new CDR(6, "CN", "CN", "460018765432101", "8618601234567", 3, null)); | ||||
| 		CDRS.add(new CDR(7, "JP", "CN", "460018765432101", "8618601234567", 2, null)); | ||||
| 		CDRS.add(new CDR(8, "CN", "CN", "460018765436633", "8618601236633", 2, null)); | ||||
| 		CDRS.add(new CDR(9, "CN", "CN", "460018765432101", "8618601234567", 3, null)); | ||||
| 		CDRS.add(new CDR(10, "CN", "CN", "460018765437755", "8618601237755", 2, null)); | ||||
| 		CDRS.add(new CDR(11, "CN", "CN", "460018765432101", "8618601234567", 2, null)); | ||||
| 		CDRS.add(new CDR(12, "CN", "CN", "460018765437788", "8618601237788", 2, null)); | ||||
| 		CDRS.add(new CDR(13, "CN", "CN", "460018765437755", "8618601237755", 2, null)); | ||||
| 		CDRS.add(new CDR(14, "CN", "CN", "460018765436633", "8618601236633", 2, null)); | ||||
| 		CDRS.add(new CDR(15, "CN", "CN", "460018765432102", "8618601234568", 2, null)); | ||||
| 		CDRS.add(new CDR(16, "CN", "CN", "460018765432102", "8618601234568", 3, null)); | ||||
| 		CDRS.add(new CDR(17, "CN", "CN", "460018765437789", "8618601237789", 2, null)); | ||||
| 		CDRS.add(new CDR(18, "JP", "CN", "460018765432102", "8618601234568", 2, null)); | ||||
| 		CDRS.add(new CDR(19, "CN", "CN", "460018765437756", "8618601237756", 2, null)); | ||||
| 		CDRS.add(new CDR(20, "JP", "CN", "460018765432102", "8618601234568", 45, null)); | ||||
| 		CDRS.add(new CDR(21, "CN", "CN", "460018765432102", "8618601234568", 3, null)); | ||||
| 		CDRS.add(new CDR(22, "JP", "CN", "460018765432102", "8618601234568", 2, null)); | ||||
| 		CDRS.add(new CDR(23, "CN", "CN", "460018765436634", "8618601236634", 2, null)); | ||||
| 		CDRS.add(new CDR(24, "CN", "CN", "460018765432102", "8618601234568", 3, null)); | ||||
| 		CDRS.add(new CDR(25, "CN", "CN", "460018765437756", "8618601237756", 2, null)); | ||||
| 		CDRS.add(new CDR(26, "CN", "CN", "460018765432102", "8618601234568", 2, null)); | ||||
| 		CDRS.add(new CDR(27, "CN", "CN", "460018765437789", "8618601237789", 2, null)); | ||||
| 		CDRS.add(new CDR(28, "CN", "CN", "460018765437756", "8618601237756", 2, null)); | ||||
| 		CDRS.add(new CDR(29, "CN", "CN", "460018765436634", "8618601236634", 2, null)); | ||||
| 		CDRS.add(new CDR(30, "CN", "HK", "454018765432101", "8521234567", 2, null)); | ||||
| 		CDRS.add(new CDR(31, "CN", "HK", "454018765432101", "8521234567", 3, null)); | ||||
| 		CDRS.add(new CDR(32, "CN", "HK", "454018765437788", "8521237788", 2, null)); | ||||
| 		CDRS.add(new CDR(33, "JP", "HK", "454018765432101", "8521234567", 2, null)); | ||||
| 		CDRS.add(new CDR(34, "CN", "HK", "454018765437755", "8521237755", 2, null)); | ||||
| 		CDRS.add(new CDR(35, "JP", "HK", "454018765432101", "8521234567", 45, null)); | ||||
| 		CDRS.add(new CDR(36, "CN", "HK", "454018765432101", "8521234567", 3, null)); | ||||
| 		CDRS.add(new CDR(37, "JP", "HK", "454018765432101", "8521234567", 2, null)); | ||||
| 		CDRS.add(new CDR(38, "CN", "HK", "454018765436633", "8521236633", 2, null)); | ||||
| 		CDRS.add(new CDR(39, "CN", "HK", "454018765432101", "8521234567", 3, null)); | ||||
| 		CDRS.add(new CDR(40, "CN", "HK", "454018765437755", "8521237755", 2, null)); | ||||
| 		CDRS.add(new CDR(41, "CN", "HK", "454018765432101", "8521234567", 2, null)); | ||||
| 		CDRS.add(new CDR(42, "CN", "HK", "454018765437788", "8521237788", 2, null)); | ||||
| 		CDRS.add(new CDR(43, "CN", "HK", "454018765437755", "8521237755", 2, null)); | ||||
| 		CDRS.add(new CDR(44, "CN", "HK", "454018765436633", "8521236633", 2, null)); | ||||
| 		CDRS.add(new CDR(45, "CN", "HK", "454017765437755", "8522237755", 2, null)); | ||||
| 		CDRS.add(new CDR(46, "CN", "HK", "454017765432101", "8522234567", 2, null)); | ||||
| 		CDRS.add(new CDR(47, "CN", "HK", "454017765437788", "8522237788", 2, null)); | ||||
| 		CDRS.add(new CDR(48, "CN", "HK", "454017765437755", "8522237755", 2, null)); | ||||
| 		CDRS.add(new CDR(49, "CN", "HK", "454017765436633", "8522236633", 2, null)); | ||||
| 	} | ||||
| 
 | ||||
| 	private KieSession ks; | ||||
| 	private SessionPseudoClock clock; | ||||
| 	private long currentTime = System.currentTimeMillis(); | ||||
| 	private long timestamp = System.currentTimeMillis(); | ||||
| 	private int maxNum; | ||||
| 	private int maxTime; | ||||
| 	private int sum; | ||||
| 	private int loop; | ||||
| 	private boolean running = false; | ||||
| 
 | ||||
| 	public CdrGenerator(KieSession ks, int maxNum, int maxTime, int loop) { | ||||
| 		this.ks = ks; | ||||
| 		this.clock = ks.getSessionClock(); | ||||
| 		this.maxNum = maxNum; | ||||
| 		this.maxTime = maxTime; | ||||
| 		this.loop = loop; | ||||
| 	} | ||||
| 
 | ||||
| 	public void start() { | ||||
| 		running = true; | ||||
| 		new Thread(this::run).start(); | ||||
| 		new Thread(this::log).start(); | ||||
| 	} | ||||
| 
 | ||||
| 	private void log() { | ||||
| 		while (running) { | ||||
| 			log.debug(MessageFormat.format("loop:{0},已匹配{1}次规则", loop, sum)); | ||||
| 			try { | ||||
| 				Thread.sleep(1000); | ||||
| 			} catch (InterruptedException e) { | ||||
| 				e.printStackTrace(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private void run() { | ||||
| 		currentTime = System.currentTimeMillis(); | ||||
| 		clock.advanceTime(currentTime, TimeUnit.MILLISECONDS); | ||||
| 		Random rand = new Random(); | ||||
| 		long start = System.currentTimeMillis(); | ||||
| 		log.debug(MessageFormat.format("开始匹配{0}条数据", loop * CDRS.size())); | ||||
| 
 | ||||
| 		CDR cdr; | ||||
| 		long id = 0; | ||||
| 		long count = 0; | ||||
| 		while (loop-- > 0) { | ||||
| 			for (CDR item : CDRS) { | ||||
| 				timestamp += rand.nextInt(1000); | ||||
| 				cdr = new CDR(item); | ||||
| 				cdr.setId(id++); | ||||
| 				cdr.setCreateTime(new Date(timestamp)); | ||||
| 				ks.insert(cdr); | ||||
| 				if (count >= maxNum || timestamp - currentTime > maxTime) { | ||||
| 					clock.advanceTime(timestamp - currentTime, TimeUnit.MILLISECONDS); | ||||
| 					currentTime = timestamp; | ||||
| 					count = 0; | ||||
| 					sum += ks.fireAllRules(); | ||||
| 				} | ||||
| 				count++; | ||||
| 			} | ||||
| 		} | ||||
| 		sum += ks.fireAllRules(); | ||||
| 		ks.dispose(); | ||||
| 		running = false; | ||||
| 		long finish = System.currentTimeMillis(); | ||||
| 		log.debug("数据最后时间:" + DateUtil.format(new Date(timestamp))); | ||||
| 		log.debug(MessageFormat.format("数据匹配完成,{0}开始,{1}结束,耗时{2}秒,匹配到{3}次规则", DateUtil.format(new Date(start)), | ||||
| 				DateUtil.format(new Date(finish)), (finish - start) / 1000, sum)); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,118 @@@@ -0,0 +1,118 @@ | ||||
| package vip.xumy.drools.conf; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.kie.api.KieBase; | ||||
| import org.kie.api.KieBaseConfiguration; | ||||
| import org.kie.api.KieServices; | ||||
| import org.kie.api.builder.KieBuilder; | ||||
| import org.kie.api.builder.KieFileSystem; | ||||
| import org.kie.api.builder.KieRepository; | ||||
| import org.kie.api.conf.EventProcessingOption; | ||||
| import org.kie.api.runtime.KieContainer; | ||||
| import org.kie.api.runtime.KieSession; | ||||
| import org.kie.api.runtime.KieSessionConfiguration; | ||||
| import org.kie.api.runtime.conf.ClockTypeOption; | ||||
| import org.kie.internal.io.ResourceFactory; | ||||
| import org.kie.spring.KModuleBeanFactoryPostProcessor; | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||
| import org.springframework.boot.system.ApplicationHome; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.core.io.Resource; | ||||
| import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | ||||
| import org.springframework.core.io.support.ResourcePatternResolver; | ||||
| 
 | ||||
| @Configuration | ||||
| public class DroolsConfig { | ||||
| 	private static final String RULES_PATH = "rules/"; | ||||
| 	public static final String JAR_ROOT_PATH; | ||||
| 	public static final String CLASSPATH = "classpath:"; | ||||
| //	private static final String JAVA_ROOT = "src/main/java/";
 | ||||
| //	private static final String RESOURCES_ROOT = "src/main/resources/";
 | ||||
| 
 | ||||
| 	static { | ||||
| 		ApplicationHome h = new ApplicationHome(DroolsConfig.class); | ||||
| 		File jarF = h.getSource(); | ||||
| 		JAR_ROOT_PATH = jarF.getParentFile().getAbsolutePath() + '/'; | ||||
| 	} | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@ConditionalOnMissingBean(KieFileSystem.class) | ||||
| 	public KieFileSystem kieFileSystem() throws IOException { | ||||
| 		KieFileSystem kieFileSystem = getKieServices().newKieFileSystem(); | ||||
| 		File dir = new File(JAR_ROOT_PATH + RULES_PATH); | ||||
| 		if (dir.exists()) { | ||||
| 			for (File file : dir.listFiles()) { | ||||
| 				kieFileSystem.write(ResourceFactory.newFileResource(file)); | ||||
| 			} | ||||
| 		} else { | ||||
| 			ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); | ||||
| 			Resource[] resources = resourcePatternResolver.getResources(CLASSPATH + RULES_PATH + "**/*.*"); | ||||
| 			for (Resource resource : resources) { | ||||
| 				kieFileSystem.write(ResourceFactory.newFileResource(resource.getFile())); | ||||
| 			} | ||||
| 		} | ||||
| 		return kieFileSystem; | ||||
| 	} | ||||
| 
 | ||||
| //	private String getPath(org.kie.api.io.Resource resource) {
 | ||||
| //		String target = resource.getTargetPath() != null ? resource.getTargetPath() : resource.getSourcePath();
 | ||||
| //		if (target != null) {
 | ||||
| //			String prefix = resource.getResourceType() == ResourceType.JAVA ? JAVA_ROOT : RESOURCES_ROOT;
 | ||||
| //			int prefixPos = target.indexOf(prefix);
 | ||||
| //			String path = prefixPos >= 0 ? target.substring(prefixPos) : prefix + target;
 | ||||
| //			path = path.replace(java.io.File.separatorChar, '/');
 | ||||
| //			return path;
 | ||||
| //		} else {
 | ||||
| //			throw new RuntimeException(
 | ||||
| //					"Resource does not have neither a source nor a target path. Impossible to add it to the bundle. Please set either the source or target name of the resource before adding it."
 | ||||
| //							+ resource.toString());
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@ConditionalOnMissingBean(KieContainer.class) | ||||
| 	public KieContainer kieContainer() throws IOException { | ||||
| 		KieServices kieServices = getKieServices(); | ||||
| 		final KieRepository kieRepository = kieServices.getRepository(); | ||||
| 		// 设置时间格式
 | ||||
| 		System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss"); | ||||
| 		kieRepository.addKieModule(kieRepository::getDefaultReleaseId); | ||||
| 		build(); | ||||
| 		return kieServices.newKieContainer(kieRepository.getDefaultReleaseId()); | ||||
| 	} | ||||
| 
 | ||||
| 	public KieServices getKieServices() { | ||||
| 		return KieServices.Factory.get(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void build() throws IOException { | ||||
| 		KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem()); | ||||
| 		kieBuilder.buildAll(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@ConditionalOnMissingBean(KieBase.class) | ||||
| 	public KieBase kieBase() throws IOException { | ||||
| 		KieBase kieBase = kieContainer().getKieBase(); | ||||
| 		return kieBase; | ||||
| 	} | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@ConditionalOnMissingBean(KieSession.class) | ||||
| 	public KieSession kieSession() throws IOException { | ||||
| 		KieBaseConfiguration baseConf = KieServices.Factory.get().newKieBaseConfiguration(); | ||||
| 		baseConf.setOption(EventProcessingOption.STREAM); | ||||
| 		KieSessionConfiguration sessConf = KieServices.Factory.get().newKieSessionConfiguration(); | ||||
| 		sessConf.setOption(ClockTypeOption.get("pseudo")); | ||||
| 		return kieContainer().newKieSession(sessConf); | ||||
| 	} | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class) | ||||
| 	public KModuleBeanFactoryPostProcessor kiePostProcessor() { | ||||
| 		return new KModuleBeanFactoryPostProcessor(); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,20 @@@@ -0,0 +1,20 @@ | ||||
| package vip.xumy.drools.conf; | ||||
| 
 | ||||
| import org.mybatis.spring.annotation.MapperScan; | ||||
| import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||||
| import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | ||||
| import org.springframework.boot.builder.SpringApplicationBuilder; | ||||
| import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; | ||||
| import org.springframework.context.annotation.ComponentScan; | ||||
| 
 | ||||
| @EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class) | ||||
| @ComponentScan(value = "vip.xumy.drools, vip.xumy.core") | ||||
| @MapperScan({ "vip.xumy.drools.mapper" }) | ||||
| public class DroolsInitializer extends SpringBootServletInitializer { | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { | ||||
| 		return builder.sources(DroolsInitializer.class); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,24 @@@@ -0,0 +1,24 @@ | ||||
| package vip.xumy.drools.ctrl; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.PathVariable; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
| 
 | ||||
| import vip.xumy.drools.service.CdrRuleService; | ||||
| 
 | ||||
| @RestController | ||||
| @RequestMapping("rule/cdr") | ||||
| public class CdrRuleController { | ||||
| 	@Autowired | ||||
| 	private CdrRuleService cdrRuleService; | ||||
| 
 | ||||
| 	@GetMapping("test/{loop}") | ||||
| 	public void fireAllRules4One(@PathVariable("loop")Integer loop) throws IOException { | ||||
| 		cdrRuleService.test(loop); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,51 @@@@ -0,0 +1,51 @@ | ||||
| package vip.xumy.drools.pojo; | ||||
| 
 | ||||
| import java.util.Date; | ||||
| 
 | ||||
| import lombok.Data; | ||||
| 
 | ||||
| @Data | ||||
| public class CDR { | ||||
| 	private Long id; | ||||
| 	private String callerCN; | ||||
| 	private String calledCN; | ||||
| 	private String imsi; | ||||
| 	private String msisdn; | ||||
| 	private int msgType; | ||||
| 	private Date createTime; | ||||
| 	private long duration; | ||||
| 
 | ||||
| 	public CDR(long id, String callerCN, String calledCN, String imsi, String msisdn, int msgType, Date date) { | ||||
| 		this.id = id; | ||||
| 		this.callerCN = callerCN; | ||||
| 		this.calledCN = calledCN; | ||||
| 		this.imsi = imsi; | ||||
| 		this.msisdn = msisdn; | ||||
| 		this.msgType = msgType; | ||||
| 		if (date == null) | ||||
| 			this.createTime = new Date(); | ||||
| 		else | ||||
| 			this.createTime = date; | ||||
| 		this.duration = 50; | ||||
| 	} | ||||
| 
 | ||||
| 	public CDR() { | ||||
| 	} | ||||
| 
 | ||||
| 	public CDR(CDR cdr) { | ||||
| 		id = cdr.id; | ||||
| 		callerCN = cdr.callerCN; | ||||
| 		calledCN = cdr.calledCN; | ||||
| 		imsi = cdr.imsi; | ||||
| 		msisdn = cdr.msisdn; | ||||
| 		msgType = cdr.msgType; | ||||
| 		createTime = cdr.createTime; | ||||
| 		duration = cdr.duration; | ||||
| 	} | ||||
| 
 | ||||
| //	@Override
 | ||||
| //	protected void finalize() throws Throwable {
 | ||||
| //		System.out.println(this.id + " is deleted");
 | ||||
| //	}
 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,51 @@@@ -0,0 +1,51 @@ | ||||
| package vip.xumy.drools.pojo; | ||||
| 
 | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| import org.drools.core.time.SessionPseudoClock; | ||||
| import org.kie.api.runtime.KieSession; | ||||
| 
 | ||||
| //@Log4j2
 | ||||
| public class DroolsBurster { | ||||
| 	private KieSession ks; | ||||
| 	private SessionPseudoClock clock; | ||||
| 	private long currentTime; | ||||
| 	private int burst; | ||||
| 	private int count; | ||||
| 
 | ||||
| 	public DroolsBurster(KieSession ks, String clockType, int burst) { | ||||
| 		this.ks = ks; | ||||
| 		if (clockType == "pseudo") | ||||
| 			clock = ks.getSessionClock(); | ||||
| 		else | ||||
| 			clock = null; | ||||
| 		currentTime = 0; | ||||
| 		currentTime = System.currentTimeMillis(); | ||||
| 		clock.advanceTime(currentTime, TimeUnit.MILLISECONDS); | ||||
| 		count = 0; | ||||
| 		this.burst = burst; | ||||
| 	} | ||||
| 
 | ||||
| 	// 将事件插入KieSession,并根据时间戳(ms)推进时钟,在一定时间间隔触发规则
 | ||||
| 	public int insert(Object evt, long timestamp) { | ||||
| 		ks.insert(evt); | ||||
| 		if (count >= burst || timestamp - currentTime > 1000) { | ||||
| 			if (clock != null) { | ||||
| 				clock.advanceTime(timestamp - currentTime, TimeUnit.MILLISECONDS); | ||||
| 				currentTime = timestamp; | ||||
| 			} | ||||
| 
 | ||||
| 			count = 0; | ||||
| 			int num = ks.fireAllRules(); | ||||
| 			return num; | ||||
| 		} | ||||
| 		count++; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	public void dispose() { | ||||
| 		if (ks != null) | ||||
| 			ks.dispose(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,23 @@@@ -0,0 +1,23 @@ | ||||
| package vip.xumy.drools.pojo; | ||||
| import java.util.List; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| public class RuleSink { | ||||
| 	String ruleName; | ||||
| 	String ruleInfo; | ||||
| 	Long trapId; | ||||
| 	List<Long> cdrIDs; | ||||
| 	 | ||||
| 	public RuleSink(Long trapId, String ruleName, String ruleInfo, List<Long> cdrIDs) { | ||||
| 		this.ruleName = ruleName; | ||||
| 		this.ruleInfo = ruleInfo; | ||||
| 		this.trapId = trapId; | ||||
| 		this.cdrIDs = cdrIDs; | ||||
| 		//this.cdrIDs.add(0, trapId);
 | ||||
| 	} | ||||
| 	 | ||||
| 	public String toString() { | ||||
| 		return String.format("{\"trapId\" : %d, \"cdrs\": %s, \"rule\" : \"%s\", \"info\" : \"%s\"}\n", trapId, cdrIDs, ruleName, ruleInfo); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,28 @@@@ -0,0 +1,28 @@ | ||||
| package vip.xumy.drools.service; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.kie.api.runtime.KieSession; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
| 
 | ||||
| import vip.xumy.drools.action.CdrGenerator; | ||||
| 
 | ||||
| /** | ||||
|  * Ownership belongs to the company | ||||
|  * | ||||
|  * @author:mengyxu | ||||
|  * @date:2023年9月19日 | ||||
|  */ | ||||
| 
 | ||||
| @Service | ||||
| public class CdrRuleService { | ||||
| 	@Autowired | ||||
| 	private DroolsApiService droolsApiService; | ||||
| 
 | ||||
| 	public void test(Integer loop) throws IOException { | ||||
| 		KieSession ks = droolsApiService.createSession(true); | ||||
| 		new CdrGenerator(ks, 500, 10000, loop).start(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,39 @@@@ -0,0 +1,39 @@ | ||||
| package vip.xumy.drools.service; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.kie.api.KieServices; | ||||
| import org.kie.api.runtime.KieContainer; | ||||
| import org.kie.api.runtime.KieSession; | ||||
| import org.kie.api.runtime.KieSessionConfiguration; | ||||
| import org.kie.api.runtime.conf.ClockTypeOption; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
| 
 | ||||
| import vip.xumy.drools.conf.DroolsConfig; | ||||
| 
 | ||||
| /** | ||||
|  * Ownership belongs to the company | ||||
|  * | ||||
|  * @author:mengyxu | ||||
|  * @date:2023年9月20日 | ||||
|  */ | ||||
| 
 | ||||
| @Service | ||||
| public class DroolsApiService { | ||||
| 	private static final KieSessionConfiguration sessConf; | ||||
| 	static { | ||||
| 		sessConf = KieServices.Factory.get().newKieSessionConfiguration(); | ||||
| 		sessConf.setOption(ClockTypeOption.get("pseudo")); | ||||
| 	} | ||||
| 	@Autowired | ||||
| 	private KieContainer kieContainer; | ||||
| 	private DroolsConfig config = new DroolsConfig(); | ||||
| 
 | ||||
| 	public KieSession createSession(boolean reBuild) throws IOException { | ||||
| 		if(reBuild)  | ||||
| 			config.build(); | ||||
| 		return kieContainer.newKieSession(sessConf); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,28 @@@@ -0,0 +1,28 @@ | ||||
| logging.config:logback.xml | ||||
| 
 | ||||
| spring.main.banner-mode=off | ||||
| 
 | ||||
| spring.datasource.type=com.alibaba.druid.pool.DruidDataSource | ||||
| spring.datasource.driver-class-name=com.mysql.jdbc.Driver | ||||
| spring.datasource.initialSize=1 | ||||
| spring.datasource.minIdle=1 | ||||
| spring.datasource.maxActive=20 | ||||
| spring.datasource.maxWait=60000 | ||||
| spring.datasource.timeBetweenEvictionRunsMillis=60000 | ||||
| spring.datasource.minEvictableIdleTimeMillis=300000 | ||||
| spring.datasource.validationQuery=SELECT 1 FROM DUAL | ||||
| spring.datasource.keepAlive=true | ||||
| spring.datasource.testWhileIdle=true | ||||
| spring.datasource.testOnBorrow=false | ||||
| spring.datasource.testOnReturn=false | ||||
| spring.datasource.poolPreparedStatements=false | ||||
| 
 | ||||
| mybatis.configuration.map-underscore-to-camel-case=true | ||||
| 
 | ||||
| quartz.cron.clean.global=0 */10 * * * ? | ||||
| 
 | ||||
| pagehelper.helperDialect=mysql | ||||
| pagehelper.reasonable=true | ||||
| pagehelper.supportMethodsArguments=true | ||||
| pagehelper.params=count=countSql | ||||
| pagehelper.returnPageInfo=check | ||||
| @ -0,0 +1,134 @@@@ -0,0 +1,134 @@ | ||||
| package rules | ||||
| import vip.xumy.drools.pojo.CDR | ||||
| import vip.xumy.drools.pojo.RuleSink | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.LinkedList; | ||||
| 
 | ||||
| //global java.lang.Integer count; | ||||
| //global java.util.LinkedList<RuleSink> sink; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| declare CDR | ||||
| 	@role(event) | ||||
| 	@timestamp(createTime) | ||||
| 	@expires(15s) | ||||
| 	//@duration(duration) | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| rule "test002" | ||||
| 	enabled false | ||||
| 	when | ||||
| 		accumulate(CDR(msgType == 2) over window:time(1s), $cnt:count()) | ||||
| 	then | ||||
| 		//System.out.println("match rule test002, count = " + $cnt); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| rule "test003" | ||||
| 	enabled true | ||||
| 	when | ||||
| 		$al : ArrayList() from collect(CDR(msgType == 2) over window:time(5s)) | ||||
| 	then | ||||
| 		//count++; | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + " count = " + $al.size()); | ||||
| end | ||||
| 
 | ||||
| rule "test004" | ||||
| 	enabled true | ||||
| 	when | ||||
| 		$b : CDR() over window:time(5s) | ||||
| 		$a : CDR(imsi==$b.imsi, this after $b) | ||||
| 	then | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + "\nevent: " + $a + "\nevent: " + $b); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| rule "test005" | ||||
| 	enabled true | ||||
| 	when | ||||
| 		$b : CDR() | ||||
| 		$a : CDR(imsi==$b.imsi, this after $b) | ||||
| 	then | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + "\nevent: " + $a + "\nevent: " + $b); | ||||
| end | ||||
| 
 | ||||
| rule "test006" | ||||
| 	//no-loop true | ||||
| 	//lock-on-active true | ||||
| 	enabled true | ||||
| 	when | ||||
| 		$b : CDR(msgType==3) | ||||
| 		//$al : ArrayList(size>1) from collect(CDR(imsi==$b.imsi, this before[1ms, 10s] $b)) | ||||
| 		//ArrayList(size>0) from collect(CDR(msgType==45, this before[1ms, 20s] $b)) | ||||
| 		exists CDR(msgType==45, imsi==$b.imsi, this before[1ms, 10s] $b) | ||||
| 	then | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + "\nevent: " + $a + "\nevent: " + $b); | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + " count = " + $al.size() + " event: " + $b); | ||||
| 		//for(int i=0; i<$al.size(); i++) | ||||
| 		//	System.out.println($al.get(i)); | ||||
| end | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| //在10s内,出现不同国家发起的两次位置更新并在此之后有短信行为 | ||||
| rule "test007" | ||||
| 	no-loop true | ||||
| 	lock-on-active true | ||||
| 	when | ||||
| 		$b : CDR(msgType==44||msgType==45||msgType==46) | ||||
| 		//accumulate(CDR(msgType==2, imsi==$b.imsi, this before[0ms, 10s] $b, $this:this, $cn:callerCN), $cnt:count($cn), $al:collectList($this)) | ||||
| 		accumulate(CDR(msgType==2, imsi==$b.imsi, this before[1ms, 15s] $b, $this:this, $cn:callerCN, $id:id), $cnt:count($cn), $al:collectList($this), $ids:collectList($id)) | ||||
| 		eval($cnt > 1) | ||||
| 	then | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + " count = " + $al.size() + " event: " + $b); | ||||
| 		//for(int i=0; i<$al.size(); i++) | ||||
| 		//	System.out.println($al.get(i)); | ||||
| 		//sink.sink(drools.getRule().getName(), "has many updatelocation from other CN before sm in 20s", $ids); | ||||
| 		 | ||||
| 		//RuleSink ri = new RuleSink($b.getId(), drools.getRule().getName(), "has many updatelocation from other CN before sm in 10s", $ids); | ||||
| 		//sink.add(ri); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| //在10s内,出现不同国家发起的两次位置更新并在此之后有短信行为 | ||||
| rule "test008" | ||||
| 	//no-loop true | ||||
| 	//lock-on-active true | ||||
| 	when | ||||
| 		$b : CDR(msgType==2) | ||||
| 		//accumulate(CDR(msgType==2, imsi==$b.imsi, this before[0ms, 10s] $b, $this:this, $cn:callerCN), $cnt:count($cn), $al:collectList($this)) | ||||
| 		accumulate(CDR(msgType==2, imsi==$b.imsi, this before[1ms, 30s] $b, $this:this, $cn:callerCN, $id:id), $cnt:count($cn), $al:collectList($this), $ids:collectList($id)) | ||||
| 		eval($cnt > 1) | ||||
| 		//accumulate (CDR(this before[1ms, 10s] $b, msgType==2, imsi==$b.imsi, $this:this), $cnt1:count($this)) | ||||
| 		//accumulate (CDR(this before[1ms, 10s] $b, msgType==3, imsi==$b.imsi, $this:this), $cnt2:count($this)) | ||||
| 		//eval($cnt1 > 1 && $cnt2 > 1) | ||||
| 	then | ||||
| 		//System.out.println("match rule " + drools.getRule().getName() + " count = " + $al.size() + " event: " + $b); | ||||
| 		//for(int i=0; i<$al.size(); i++) | ||||
| 		//	System.out.println($al.get(i)); | ||||
| 		//sink.sink(drools.getRule().getName(), "has many updatelocation from other CN before sm in 20s", $ids); | ||||
| 		 | ||||
| 		//RuleSink ri = new RuleSink($b.getId(), drools.getRule().getName(), "has many updatelocation from other CN before sm in 10s", $ids); | ||||
| 		//sink.add(ri); | ||||
| end | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| rule "retract event" | ||||
| salience -999999 | ||||
| when | ||||
|     $e: CDR() | ||||
| then | ||||
|     retract( $e ); | ||||
| end | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
					Loading…
					
					
				
		Reference in new issue