Coupons use a rules engine to calculate offers (drools)

There are more and more promotional patterns for e-commerce, and the rules are becoming more and more complex. Therefore, frequent changes in rules may lead to frequent version development and launch. Therefore, the business hopes to be able to go online quickly, which requires products to be able to achieve Modify the code to go online quickly.

In all fairness, the current methods of coupons are relatively fixed, usually general coupons, discount coupons, full discount coupons, and full free coupons. Even without the rule engine, the design of most coupons can support the needs of the business side. For some complex rules on the business side, such as superposition rules and mutual exclusion rules, they are usually part of the configuration of coupons. In the calculation of coupon prices, mutual exclusion and superposition have been realized.

In fact, the calculation logic of coupons is very complicated. Especially when multiple coupons can be used, different levels of coupons must be considered. It is still very troublesome to implement in the rule engine. In addition, because drools can only express in the form of when-then and does not implement a complete programming language paradigm, it is difficult to implement complex business logic in drools scripts.

We also conducted research on groovy scripts. In the next article, we will use groovy to implement the business logic of coupons. In the coupon scenario, it can be more flexible than drools.

Rule Engine

The core of the rule engine consists of two parts:

  1. rule script;
  2. Compilation, interpretation and execution of rule scripts;

Usually, rule scripts are implemented in independent languages, and most rule engines use java’s open source library antlr . antlr is an open source grammar parser. Although the rule script grammar is simple, it is also an independent language. Therefore, grammar analysis and lexical analysis are necessary. In addition, most rule engines can call each other with the JVM. The processing of this part should be relatively complicated, and those who are interested can study the source code.

drools rules engine

The drools rule engine is mainly used in scenarios such as risk control, anti-fraud, intelligent marketing, outlet monitoring, intelligent underwriting, and business flow automation. The core is to move the business logic code from java code to drools script. If you need to modify the business logic , you only need to modify the drools script, not the background code.

Usually in practice, we save the script in the database, and most of the time, there is no need to modify the drools script. If the business logic changes, you can modify the drools script, and then load the script from the database again with the java code, thus realizing

By separating the business logic code from the background code, it can be modified at any time

The basic flow of a drools rule engine is:

rule rule001
when
\tcondition
then
\tResults of the
end

Drools has several important concepts, namely:

Facts

Facts in drools can be simply understood as input

Working memory

Working memory can be simply understood as the operating environment of drools

LHS RHS

LHS: condition part, namely When

RHS: result part, ie then

Interaction with java

The power of drools is that it can be deeply combined with java, refer to java code, and call java methods. During the execution of rules, it is often necessary to interact with java, pass parameters, judge conditions, update results, etc.

KieServices, kieSession, KieContainer, KieFileSystem, KieModule

  • KieServices: The overall entrance of kie, which can be used to create Container, resource, fileSystem, etc.
  • KieContainer: KieContainer is a KieBase container, through KieContainer to get specific KieSession
  • KieFileSystem: Kie’s virtual file system, including resources and organizational structure, drools scripts can be loaded through KieFileSystem
  • KieModule: is a container that contains multiple kiebase definitions.
  • KieRepository: It is a repository of KieModule, including all KieModule descriptions, distinguished by a ReleaseId

There are many concepts and it is difficult to understand. I think this is why many people say that drools is very important.

Java usage process

In fact, we don’t need to care about so many macro concepts for the time being, let’s start with hello world.

Usually, the usage process of java is:

  1. get kieSession;
  2. Insert variables into kieSession
  3. Call kieSession.fireAllRules()

Suppose we put the drools script in the resource/rules directory, and the code to get kieSession is as follows:

 private static Resource[] getRuleFiles() throws IOException {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        return resourcePatternResolver.getResources("classpath*:rules/" + "**/*.drl");
    }

    private static KieSession getSession() throws Exception {
        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kfs = kieServices. newKieFileSystem();

        for (Resource file : getRuleFiles()) {
            log.info("rule file: " + file.getFilename());
            try {
                kfs.write(ResourceFactory.newClassPathResource("rules/" + file.getFilename(), "UTF-8"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
        Results results = kieBuilder. getResults();
        if (results. hasMessages(Message. Level. ERROR)) {
            for (Message msg : results. getMessages()) {
                log.error("drools script error info : " + msg.getText());
            }
            throw new Exception("drools script error");
        }
        return kieServices.newKieContainer(KieServices.Factory.get().getRepository().getDefaultReleaseId()).newKieSession();
}

The code to execute the rule:

 KieSession kieSession = getSession();
        kieSession.insert(order);
        kieSession.insert(coupon);
        kieSession.insert(result);
        int hit = kieSession.fireAllRules(); // hit is the number of rules that all rules are hit

Code explanation

The code is based on spring boot, and this project is only a demonstration project. Therefore, the database part is not involved, and this part of the implementation can be refined in practice.

The code is open source: https://github.com/guotie/drools

Core process

The core of the coupon is the interface for calculating the price, which is often called the inquiry interface.

Therefore, we wrote several drools scripts:

  • Discount offer calculation script
  • Full discount discount calculation script
  • Calculation script for full gifts
  • Payment discount calculation script
  • other

For example, the contents of the discount offer calculation script are as follows:

package com.mall.coupon.drools.rules;

// discount type

import com.mall.coupon.drools.model.Coupon
import com.mall.coupon.drools.model.Order
import com.mall.coupon.drools.model.OrderItem
import com.mall.coupon.drools.model.EnquiryResult

global com.mall.coupon.drools.service.CouponBatchService couponBatchService
global com.mall.coupon.drools.service.UserCouponService userCouponService
//global com.mall.coupon.drools.service.UserCouponService userCouponService
global com.mall.coupon.drools.service.UserService userService

// discount coupons

// order discounts the entire order
rule "rule-discount-order"
when
    $result: EnquiryResult()
    $order: Order()
    $coupon: Coupon(couponType == "5" & amp; & amp; subCouponType == "1" & amp; & amp;
        (minBuyAmount == 0 || $order. totalAmount >= minBuyAmount))
then
    System.out.println("hit discount-order");
    $result.setTotalDiscount($order.getTotalAmount() * $coupon.getNominal() / 100);
end


// sku discounts specific sku items
rule "rule-discount-sku"
when
    $item: OrderItem()
    $result: EnquiryResult()
    $coupon: Coupon(couponType == "5" & amp; & amp; subCouponType == "2" & amp; & amp;
        (minBuyAmount == 0 || $item.totalAmount >= minBuyAmount) & amp; & amp;
        couponBatchService.skuUsable($coupon.getCouponBatchCode(), $item.getProductSkuId()))
then
    System.out.println("coupon code: " + $coupon.getCouponBatchCode());
    System.out.println("couponBatchService: " + couponBatchService);
    System.out.println("hit discount-sku");
    $result.setTotalDiscount($item.getTotalAmount() * (100 - $coupon.getNominal()) / 100);
end

Summary

If we need to add a new type of coupon, then we only need to add the drools script of this type of coupon. After the test is correct, the background code can be reloaded, which realizes the rapid deployment of business rules.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge Java skill tree Use JDBC to operate the databaseDatabase operation 118850 people are learning the system