Drools rule dynamic practice

0 24
Author: Li Zhen, Kang Rui, Liu Bin, Wang Beiying, JD LogisticsOne , Business App...

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

Drools rule dynamic practice

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:

  1. Simple configuration rules can be connected to easycode, and the platform provides a configuration page for jsf interaction.
  1. 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 throughKieSessionorStatelessKieSessionInteract with the working memory. The entire process is not complex. Note KieHelperIt 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 KieHelperto 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 usedKieHelperto 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@Beanand 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 kieFileSystemThen reload the entire kieBaseThis can reload the rules, but this behavior is heavy and costly

It can also be done through kieBaseAdding 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 StatelessKieSessionInteracting 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 KieSessionIt 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
你可能想看:
最后修改时间:
admin
上一篇 2025年03月28日 14:25
下一篇 2025年03月28日 14:47

评论已关闭