Author: Li Zhen, Kang Rui, Liu Bin, Wang Beiying, JD Logistics
One , Business Application Background of Rule Engine
Business logicThere are often some long-winded judgments that need to write a lot of if-else statements, or some judgment logic needs to be frequently modified. If this logic is implemented in Java code, it will face many disadvantages such as uncontrollable code scale and frequent modification of logic for online release. In this case, we need to integrate rule engines to manage these judgments online
Part Two: Rule Engine Selection

There are also many open-source rule engines at present. According to the original project dependencies and brief contact with rule engines, we have focused on understanding the following several
drools:
-Community active, continuously updated
-Widely used
-Complex
-High learning cost
https://github.com/kiegroup/drools
easy-rule:
-Easy to learn
-Meets the needs of use
-No new version has been released for a long time
https://github.com/j-easy/easy-rules
easycode:
-Maintained by the JD Logistics team
-Based on flowable dmn implementation
-Configuration is simple and intuitive
-A large number of systems have been using it
Summary:
- Simple configuration rules can be connected to easycode, and the platform provides a configuration page for jsf interaction.
- Complex rules require dynamic rule generation, and easycode currently does not support it. Considering popularity and activity, drools is stronger than easy-rule, so drools is chosen.
Part Three: Simple Drools Example
3.1 Introduce dependencies
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools.version}</version>
</dependency>
3.2 Write a drl file
We write a simple demo
The rule is:
Match a sku object
0<price<=100 10 points
100<price<=1000 100 points
1000<price<=10000 1000 points
A new file named rules/skupoints.drl is added under the resources folder, with the following content
package com.example.droolsDemo
import com.example.droolsDemo.bean.Sku;
// 10 points
rule "10_points"
when
$p : Sku( price > 0 && price <= 100 )
then
$p.setPoints(10);
System.out.println("Rule name is [" + drools.getRule().getName() + "]");
end
// 100 points
rule "100_points"
when
$p : Sku( price > 100 && price <= 1000 )
then
$p.setPoints(100);
System.out.println("Rule name is [" + drools.getRule().getName() + "]");
end
// 1000 points
rule "1000_points"
when
$p : Sku( price > 1000 && price <= 10000 )
then
$p.setPoints(1000);
System.out.println("Rule name is [" + drools.getRule().getName() + "]");
end
3.3 Usage
@Test
public void testOneSku() {
Resource resource = ResourceFactory.newClassPathResource("rules/skupoints.drl");
KieHelper kieHelper = new KieHelper();
kieHelper.addResource(resource);
KieBase kieBase = kieHelper.build();
KieSession kieSession = kieBase.newKieSession();
Sku sku1 = new Sku();
sku1.setPrice(10);
kieSession.insert(sku1);
int allRules = kieSession.fireAllRules();
kieSession.dispose();
System.out.println("sku1:" + JSONObject.toJSONString(sku1))
System.out.println("allRules:" + allRules);
@Test
public void testOneSku2() {
Resource resource = ResourceFactory.newClassPathResource("rules/skupoints.drl");
KieHelper kieHelper = new KieHelper();
kieHelper.addResource(resource);
KieBase kieBase = kieHelper.build();
StatelessKieSession statelessKieSession = kieBase.newStatelessKieSession();
Sku sku1 = new Sku();
sku1.setPrice(10);
statelessKieSession.execute(sku1);
System.out.println("sku1:" + JSONObject.toJSONString(sku1))
3.4 Output
3.5 Summary
As shown above, we use drools simply, we only need to pay attention to the syntax of the drl file. The working memory generated by the rules from the drl file is throughKieSession
orStatelessKieSession
Interact with the working memory. The entire process is not complex. Note KieHelper
It is only a simple use in the demo, and the demo includes the way to manage the container using beans, which should not be used even in simple usage scenarios KieHelper
to reload the rules.
However,,This does not meet our needs for online judgment or frequent rule changes.Therefore, in practice, we need to use a higher-level usage method of drools.
Four, drools dynamic practice
From the above simple demo, we can see that the rules depend on the drl file. In actual business use, it is necessary to dynamically modify the rules and cannot directly use the drl file.
The following are the four dynamic solutions I have learned about:
- drt file, create a template, dynamically generate drl files, which is also the way we are currently using.
- Excel file import, which is actually similar to template files, and still cannot be directly used by business personnel.
- Assemble strings by yourself, dynamically generate drl files, which is the way most online articles use, and it is too primitive.
- API method, the API method of drools is complex, and it requires a sufficient understanding of the drl file to use it.
Finally, let's introduce the actual use of drools in the project
4.1 Configure rules
Our business scenario can be understood as a network structure composed of multiple buffer pools.
The following is an example:
In the figure above, each block is a buffer pool, and each line is a connection from buffer pool A to buffer pool BRules.In actual scenarios, there are hundreds of buffer pools, the vast majority of which have their own rules, forming a complex network of rules. Based on business requirements, the flow rules of buffer pools need to be changed frequently. We need to be able to dynamically change the conditions of these connections or change the connections in the business. In this case, if static drl files are used to implement these rules, hundreds of rule files are required, with a large maintenance burden, and the cost of making the rules effective after each modification is high. Against this background, we have tried to use the higher-level applications of drools, bothDynamic rulesPractice.
We have added the creation of flow rules in the page for creating buffer pools. Each buffer pool maintains its own flow rules, which is a line for itself. As shown in the following figure:
4.2 Dynamic generation of drl
Content of drt file:
(The actual business template is more complex than this, with certain validations and business logic. This section has been simplified.)
template header
// Parameters required for the template
id
cluePoolId
sourceList
cooperateTypeList
regionId
secondDepartmentId
battleId
outCluePoolId
amountCompareFlag
amount
salience
package rulePoolOut
// Global objects
global java.util.List list;
global java.util.List stopIdList;
global java.util.List ruleIdList;
// Imported java classes
import com.example.drools.bean.ClueModel
import org.springframework.util.CollectionUtils
import org.apache.commons.lang3.StringUtils;
import java.lang.Long
template "CluePoolOut"
// Rule name
rule "clue_pool_@{cluePoolId}_@{id}"
// Parameter indicates whether the current rule is not allowed to execute multiple times
no-loop true
// Parameter priority
salience @{salience}
// Parameter rule group This group rule can only have one rule生效
activation-group "out_@{cluePoolId}"
// Matching LHS
when
$clue:ClueModel(cluePoolId == @{cluePoolId})
ClueModel(CollectionUtils.isEmpty(@{sourceList}) || source memberOf @{sourceList})
ClueModel(CollectionUtils.isEmpty(@{cooperateTypeList}) || cooperateType memberOf @{cooperateTypeList})
ClueModel(secondDepart == @{secondDepartmentId})
ClueModel(regionNo == @{regionId})
ClueModel(battleId == @{battleId})
ClueModel(null != estimateOrderCount && (Long.valueOf(estimateOrderCount) @>{amountCompareFlag} Long.valueOf(@{amount})))
// If the RHS to be executed is configured to support Java syntax
then
ruleIdList.add(@{id});
$clue.setCluePoolId(Long.valueOf(@{outCluePoolId}));
list.add(@{outCluePoolId});
update($clue);
end
end template
Generate drl content: Generate drl content based on a queue and the path of the template
List<CrmCluePoolDistributeRuleBusinessBattleVO> ruleCenterVOS = new ArrayList<>();
CrmCluePoolDistributeRuleBusinessBattleVO vo = new CrmCluePoolDistributeRuleBusinessBattleVO();
vo.setAmountCompareFlag('>');
vo.setAmount(100L);
ruleCenterVOS.add(vo);
String drl = droolsManager.createDrlByTemplate(ruleCenterVOS, "rules/CluePoolOutRuleTemplate.drt");
public String createDrlByTemplate(Collection<?> objects, String path) {
ObjectDataCompiler compiler = new ObjectDataCompiler();
try (InputStream dis = ResourceFactory.newClassPathResource(path, this.getClass()).getInputStream()) {
return compiler.compile(objects, dis);
} catch (IOException e) {
log.error("Failed to create drl file!", e);
return null;
4.3 Load drl
In the above simple example, we usedKieHelper
to load rule files into the working memory. In fact, we cannot reload all rule files in each match, so we canSingletonThe usage rules container, through the following method or can also use@Bean
and other ways to manage the container.
private final KieServices kieServices = KieServices.get();
// kie file system, needs caching, if a new one is created every time a rule is added, it may cause problems. That is, the rules added to the file system before are lost
private final KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
// Requires a globally unique one
private KieContainer kieContainer;
By writing content to kieFileSystem
Then reload the entire kieBase
This can reload the rules, but this behavior is heavy and costly
It can also be done through kieBase
Adding a file for loading has a low cost, but the cost of synchronizing instances is high.
KnowledgeBaseImpl kieBase = (KnowledgeBaseImpl)kieContainer.getKieBase(kieBaseName);
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
Resource resource = ResourceFactory.newReaderResource(new StringReader(ruleContent));
builder.add(resource, ResourceType.DRL);
if (builder.hasErrors()) {
throw new RuntimeException("Failed to add rule!" + builder.getErrors().toString());
kieBase.addPackages(builder.getKnowledgePackages());
4.4 Matching
Through StatelessKieSession
Interacting with the rule engine
// Get a connection
StatelessKieSession kieSession = droolsManager.getStatelessKieSession(RuleTemplateEnum.CLUE_POOL_OUT_RULE.getKieBaseName());
// Create global variable objects
List<Long> list = new ArrayList<>();
List<Long> stopIdList = Lists.newArrayList();
List<String> result = new ArrayList<>();
List<Long> ruleIdList = new ArrayList<>();
// Set global variables
kieSession.setGlobal("ruleIdList", ruleIdList);
kieSession.setGlobal("list", list);
kieSession.setGlobal("stopIdList", stopIdList);
kieSession.setGlobal("result", result);
// Execute rules
kieSession.execute(clueModel);
If used KieSession
It needs to be closed after use
kieSession.insert(clueModel);
kieSession.fireAllRules();
kieSession.dispose();
During the execution of the rules, various listeners can be added to monitor various changes in the process. Due to space limitations, it is left for everyone to explore.
5. Summary
From the above process, we experienced the creation and use of dynamic rules. Dynamic rules meet our needs for rule dynamic changes and unified management.
I have also summarized several advantages and disadvantages of drools under this usage method.
Advantages:
- Rules are dynamic and convenient
- Good performance in matching rules in the working memory
- Almost all rule requirements can be met
- Built-in methods are rich and perfect
Disadvantages:
- Distributed consistency needs to be handled independently
- It is necessary to develop an understanding of the drl grammar
- The learning curve is steep
- The matching process monitoring means needs to be implemented independently
Exploration and practice of optimizing the file size of Android dynamic link libraries
Android penetration testing 12: IDA dynamic debugging so
Dynamic CNN model for identifying fake personal profiles in online social networks
Git leak && AWS AKSK && AWS Lambda cli && Function Information Leakage && JWT secret leak
How does GARTNER define mobile target defense (dynamic target defense, MTD)?
Be vigilant against the new worm virus disguised as the 'Synaptics touchpad driver program'
2025 latest & emulator WeChat mini-program packet capture & mini-program reverse engineering

评论已关闭