Drools basic syntax

1 rules document composition

A very important task when using Drools is to write rule files. Usually, the suffix of rule files is drl.

drl is the abbreviation of Drools Rule Language. Write specific rules in the rules file.

The contents of a complete set of rules are as follows:

keyworddescribe
packagePackage name is limited to logical management. Queries or functions under the same package name can be called directly
importUsed to import classes or static methods
globalglobal variable
functionCustom function
queryquery
rule endRegular body

Rule files supported by Drools include both drl and Excel file types.

2 regular grammatical structure

The rule body is an important part of the content of the rule file. It is used to judge business rules and process business results.

The syntax structure of rule body is as follows:

rule "ruleName"
    attributes
    when
        LHS 
    then
        RHS
end

Rule: keyword, indicating the beginning of the rule. The parameter is the unique name of the rule.

attributes: rule attribute, which is an optional parameter between rule and when.

when: keyword, followed by the condition part of the rule.

LHS(Left Hand Side): the common name of the condition part of a rule. It consists of zero or more conditional elements. If LHS is empty, it is treated as a condition element that is always true. (left hand side)

then: keyword, followed by the result part of the rule.

RHS(Right Hand Side): the common name of the consequence or action part of a rule. (right hand side)

End: keyword, indicating the end of a rule.

3 Notes

The annotations used in the drl form of rule files are the same as those used in Java classes, which are divided into single line annotations and multi line annotations.

Single line comments are marked with "/ /", and multi line comments start with "/" and end with "/". The following example:

//Annotation of rule rule1, which is a single line annotation
rule "rule1"
    when
    then
        System.out.println("rule1 trigger");
end

/*
Comments for rule rule2,
This is a multiline comment
*/
rule "rule2"
    when
    then
        System.out.println("rule2 trigger");
end

4 Pattern matching

We already know that the matcher in Drools can match the pattern of all rules in Rule Base with the Fact object in Working Memory, so we need to define rules in the LHS part of the rule body and perform pattern matching. The LHS part consists of one or more conditions, which are also called patterns.

The syntax structure of pattern is: binding variable name: Object(Field constraint)

The bound variable name can be omitted. Generally, it is recommended to start with $for the naming of bound variable names. If the binding variable name is defined, you can use this binding variable name in the RHS part of the rule body to operate the corresponding Fact object. The Field constraint part is 0 or more expressions that need to return true or false.

For example, in our introductory case:

//Rule 2: if the total price of the books purchased is between 100 and 200 yuan, 20 yuan will be given
rule "book_discount_2"
    when
        //Order is a type constraint and originalPrice is an attribute constraint
        $order:Order(originalPrice < 200 && originalPrice >= 100)
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("Successfully matched to rule 2: 20 yuan discount for books with a total price of 100 to 200 yuan");
end

From the above example, we can see that the matching conditions are:

1. There must be a Fact object of type Order in the working memory ----- type constraint

2. The originalPrice property value of the Fact object must be less than 200 ------ property constraint

3. The originalPrice property value of the Fact object must be greater than or equal to 100 ------ property constraint

The above conditions must meet the current rules at the same time before they can be activated.

Binding variables can be used on both objects and their attributes. For example, the above example can be changed to:

//Rule 2: if the total price of the books purchased is between 100 and 200 yuan, 20 yuan will be given
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100)
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("Successfully matched to rule 2: 20 yuan discount for books with a total price of 100 to 200 yuan");
end

The LHS part can also define multiple patterns. Multiple patterns can be connected with and or without writing. The default connection is and.

//Rule 2: if the total price of the books purchased is between 100 and 200 yuan, 20 yuan will be given
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100) and
        $customer:Customer(age > 20 && gender=='male')
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("Successfully matched to rule 2: 20 yuan discount for books with a total price of 100 to 200 yuan");
end

5 comparison operator

The comparison operators provided by Drools are as follows:

symbolexplain
>greater than
<less than
>=Greater than or equal to
<=Less than or equal to
==equal to
!=Not equal to
containsCheck whether a property value of a Fact object contains a specified object value
not containsCheck whether a property value of a Fact object does not contain a specified object value
memberOfDetermine whether a property of a Fact object is in one or more collections
not memberOfDetermine whether a property of a Fact object is not in one or more collections
matchesDetermine whether the attribute of a Fact object matches the provided standard Java regular expression
not matchesDetermine whether the attributes of a Fact object do not match the provided standard Java regular expressions

The first six comparison operators are exactly the same as those in Java. Let's focus on the last six comparison operators.

The first six comparison operators are exactly the same as those in Java. Let's focus on the last six comparison operators.

5.1 grammar

  • contains | not contains syntax structure

    Object(Field[Collection/Array] contains value)

    Object(Field[Collection/Array] not contains value)

  • memberOf | not memberOf syntax structure

    Object(field memberOf value[Collection/Array])

    Object(field not memberOf value[Collection/Array])

  • matches | not matches syntax structure

    Object(field matches "regular expression")

    Object(field not matches "regular expression")

contain means that the front contains the back, and memberOf means that the back contains the front.

5.2 operation steps

Step 1: create an entity class to test the comparison operator

package com.itheima.drools.entity;
import java.util.List;

/**
 * Entity class
 * Used to test comparison operators
 */
public class ComparisonOperatorEntity {
    private String names;
    private List<String> list;

    public String getNames() {
        return names;
    }

    public void setNames(String names) {
        this.names = names;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }
}

Step 2: create the rule file comparisoperator DRL

package comparisonOperator
import com.itheima.drools.entity.ComparisonOperatorEntity
/*
 The current rule file is used to test the comparison operators provided by Drools
*/

//Test comparison operator contains
rule "rule_comparison_contains"
    when
        ComparisonOperatorEntity(names contains "wolf")
        ComparisonOperatorEntity(list contains names)
    then
        System.out.println("rule rule_comparison_contains trigger");
end

//Test comparison operator not contains
rule "rule_comparison_notContains"
    when
        ComparisonOperatorEntity(names not contains "wolf")
        ComparisonOperatorEntity(list not contains names)
    then
        System.out.println("rule rule_comparison_notContains trigger");
end

//Test comparison operator memberOf
rule "rule_comparison_memberOf"
    when
        ComparisonOperatorEntity(names memberOf list)
    then
        System.out.println("rule rule_comparison_memberOf trigger");
end

//Test comparison operator not memberOf
rule "rule_comparison_notMemberOf"
    when
        ComparisonOperatorEntity(names not memberOf list)
    then
        System.out.println("rule rule_comparison_notMemberOf trigger");
end

//Test comparison operator matches
rule "rule_comparison_matches"
    when
        ComparisonOperatorEntity(names matches "Zhang.*")
    then
        System.out.println("rule rule_comparison_matches trigger");
end

//Test comparison operator not matches
rule "rule_comparison_notMatches"
    when
        ComparisonOperatorEntity(names not matches "Zhang.*")
    then
        System.out.println("rule rule_comparison_notMatches trigger");
end

Step 3: write unit tests

//Test comparison operator
@Test
public void test3(){
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();

    ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();
    comparisonOperatorEntity.setNames("wolf");
    List<String> list = new ArrayList<String>();
    list.add("wolf");
    list.add("Lisi");
    comparisonOperatorEntity.setList(list);

    //Provide the data to the rule engine. The rule engine will match the rules based on the provided data. If the rules match successfully, the rules will be executed
    kieSession.insert(comparisonOperatorEntity);

    kieSession.fireAllRules();
    kieSession.dispose();
}

6 execute specified rules

From the previous case, we can see that when we call the rule code, the rules that meet the conditions will be executed. So how do we implement if we just want to execute one of these rules?

Drools provides us with a way to execute specified rules through rule filters. There is no need to modify the rule file, just modify the Java code, as follows:

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();

ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();
comparisonOperatorEntity.setNames("wolf");
List<String> list = new ArrayList<String>();
list.add("wolf");
list.add("Lisi");
comparisonOperatorEntity.setList(list);
kieSession.insert(comparisonOperatorEntity);

//Implementing only specified rules through rule filters
kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_comparison_memberOf"));

kieSession.dispose();

7 keywords

Drools' keywords are divided into hard keywords and soft keywords.

Hard keywords are clearly not used when we define package names or rule names in the rules file, otherwise the program will report an error. Although soft keywords can be used, they are not recommended.

Hard keywords include: true false null

Soft keywords include: lock on active date effective date expires no loop auto focus activation group agenda group ruleflow group entry point duration package import dialog sales enabled attributes rule extend when then template query declare function global Eval not in or and exists forall aggregate collect from action reverse result end over init

For example:
rule true  //No
rule "true"  //Yes

8 Drools built in method

The main function of the RHS part of the rule file is to control the execution of the rule engine by inserting, deleting or modifying the Fact data in the working memory. Drools provides some methods to operate the data in the working memory. * * after the operation is completed, the rule engine will re match the relevant rules. * * the rules that were not successfully matched may be successfully matched after we modify the data.

Create the following entity classes:

package com.itheima.drools.entity;

import java.util.List;

/**
 * student
 */
public class Student {
    private int id;
    private String name;
    private int age;
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

8.1 update method

The update method is used to update the data in the working memory and re match the relevant rules. (to avoid dead circulation)

Step 1: write a rule file /resources/rules/student DRL, the contents of the file are as follows

package student
import com.itheima.drools.entity.Student

/*
 The current rule file is used to test the built-in methods provided by Drools
*/

rule "rule_student_age Less than 10 years old"
    when
        $s:Student(age < 10)
    then
        $s.setAge(15);
        update($s);//Update the data, resulting in re matching of relevant rules
        System.out.println("rule rule_student_age Triggered when less than 10 years old");
end

rule "rule_student_age Less than 20 years old and more than 10 years old"
    when
        $s:Student(age < 20 && age > 10)
    then
        $s.setAge(25);
        update($s);//Update the data, resulting in re matching of relevant rules
        System.out.println("rule rule_student_age Triggered when less than 20 years old and more than 10 years old");
end

rule "rule_student_age Over 20 years old"
    when
        $s:Student(age > 20)
    then
        System.out.println("rule rule_student_age Triggered over 20 years old");
end

Step 2: write unit tests

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();

Student student = new Student();
student.setAge(5);

//Provide the data to the rule engine. The rule engine will match the rules based on the provided data. If the rules match successfully, the rules will be executed
kieSession.insert(student);

kieSession.fireAllRules();
kieSession.dispose();

From the console output, you can see that the three rules defined in the rule file have been triggered.

When updating data, attention should be paid to prevent a life and death cycle.

8.2 insert method

The function of the insert method is to insert data into the working memory and re match the relevant rules.

Step 1: modify student The contents of the DRL file are as follows

package student
import com.itheima.drools.entity.Student

/*
 The current rule file is used to test the built-in methods provided by Drools
*/

rule "rule_student_age Equal to 10 years old"
    when
        $s:Student(age == 10)
    then
        Student student = new Student();
        student.setAge(5);
        insert(student);//Insert data, resulting in re matching of relevant rules
        System.out.println("rule rule_student_age Equal to 10 years old trigger");
end

rule "rule_student_age Less than 10 years old"
    when
        $s:Student(age < 10)
    then
        $s.setAge(15);
        update($s);
        System.out.println("rule rule_student_age Triggered when less than 10 years old");
end

rule "rule_student_age Less than 20 years old and more than 10 years old"
    when
        $s:Student(age < 20 && age > 10)
    then
        $s.setAge(25);
        update($s);
        System.out.println("rule rule_student_age Triggered when less than 20 years old and more than 10 years old");
end

rule "rule_student_age Over 20 years old"
    when
        $s:Student(age > 20)
    then
        System.out.println("rule rule_student_age Triggered over 20 years old");
end

Step 2: write unit tests

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();

Student student = new Student();
student.setAge(10);

//Provide the data to the rule engine. The rule engine will match the rules based on the provided data. If the rules match successfully, the rules will be executed
kieSession.insert(student);

kieSession.fireAllRules();
kieSession.dispose();

It can be found from the console output that all four rules have been triggered. This is because only the first rule can be successfully matched during the first rule matching. However, inserting a data into the working memory in the first rule causes the rule matching to be repeated. At this time, the second rule can be successfully matched. The data modification in the second rule leads to the successful matching of the third rule, and so on. Finally, the four rules are matched and executed successfully.

8.3 retract method

The function of the retract method is to delete the data in the working memory and re match the relevant rules.

Step 1: modify student The contents of the DRL file are as follows

package student
import com.itheima.drools.entity.Student

/*
 The current rule file is used to test the built-in methods provided by Drools
*/

rule "rule_student_age Delete data when equal to 10 years old"
    /*
    salience: Set the execution priority of the current rule. The higher the value, the higher the priority. The default value is 0
    Because the matching conditions of the current rule are the same as those of the following rules, priority needs to be set to ensure that the current rule is executed first
    */
    salience 100 
    when
        $s:Student(age == 10)
    then
        retract($s);//The function of the retract method is to delete the data in the working memory and re match the relevant rules.
        System.out.println("rule rule_student_age Delete data trigger when equal to 10 years old");
end

rule "rule_student_age Equal to 10 years old"
    when
        $s:Student(age == 10)
    then
        Student student = new Student();
        student.setAge(5);
        insert(student);
        System.out.println("rule rule_student_age Equal to 10 years old trigger");
end

rule "rule_student_age Less than 10 years old"
    when
        $s:Student(age < 10)
    then
        $s.setAge(15);
        update($s);
        System.out.println("rule rule_student_age Triggered when less than 10 years old");
end

rule "rule_student_age Less than 20 years old and more than 10 years old"
    when
        $s:Student(age < 20 && age > 10)
    then
        $s.setAge(25);
        update($s);
        System.out.println("rule rule_student_age Triggered when less than 20 years old and more than 10 years old");
end

rule "rule_student_age Over 20 years old"
    when
        $s:Student(age > 20)
    then
        System.out.println("rule rule_student_age Triggered over 20 years old");
end

Step 2: write unit tests

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();

Student student = new Student();
student.setAge(10);

//Provide the data to the rule engine. The rule engine will match the rules based on the provided data. If the rules match successfully, the rules will be executed
kieSession.insert(student);

kieSession.fireAllRules();
kieSession.dispose();

It can be found from the console output that only the first rule is triggered, because the data in the working memory is deleted in the first rule, resulting in the second rule not matching successfully.

Tags: Java drools

Posted by dewed on Mon, 30 May 2022 03:20:24 +0530