Drools Decision Tree Generator Plugin

16 Apr, 2021 | 3 minutes read

Most of us are familiar with the phrase Business Rules Engine and why they exist. As you know, Business Rules Engines serve to automate decisions in various steps of a business process. The automation is done on the basis of pre-defined conditions. The benefits of having Business Rules Engines are huge, some of them being improved compliance, improved quality of work reduced manual work, and chances for human errors. In our blog post, we will not go over Business Rules Engines and their benefits, but we will talk more about creating the Drools Decision Tree Generator plugin.

Some time ago, our CTO, Marjan Sterjev published a post where he explains how to make the Nools Decision Tree Generator plugin (you can check his post here: Drow.io Decision Tree Generator). Correlated to his blog, we want to explain how to make the same functionality by using Drools.

Drools is a Business Rules Management System (BRMS) solution. It is a Java-based, open-source project backed by JBoss and Red Hat. It allows solutions to separate data and business logic. (References: Credera.com)

Drools implements and extends the RETE algorithm. The Drools Rete implementation is called ReteOO, signifying that Drools has an enhanced and optimized implementation of the Rete algorithm for Object-Oriented systems.

rule "name-of-the-rule"  
   when  
      LHS #One or more conditions  
   then  
      RHS #One or more actions  
end  

The Rule is composed of two parts, left-hand-side LHS is a set of productions that contains the unordered sequence of the patterns (conditions) and right-hand-side RHS (actions).

Our Drools rules look like this:

declare Product      
    F1 : int  
    F2 : int  
    F3: int  
    result : char  
end  
	  
rule "Rule 0"  
    when  
         $p : Product(F1<50, F2<40, F1<20)  
	then  
	     $p.result='A';  
end  
	  
rule "Rule 1"  
    when  
         $p : Product(F1<50, F2<40, F1>=20)  
    then  
         $p.result='B';  
end  
	  
rule "Rule 2"  
    when  
         $p : Product(F1<50, F2>=40, F3<30)  
    then  
         $p.result='C';  
end  
	  
rule "Rule 3"  
    when  
         $p : Product(F1<50, F2>=40, F3>=30)  
    then  
         $p.result='D';  
end  
	  
rule "Rule 4"  
    when  
         $p : Product(F1>=50, F3<70, F2<10)  
    then  
         $p.result='A';  
end  
	  
rule "Rule 5"  
    when  
         $p : Product(F1>=50, F3<70, F2>=10)  
	    then  
         $p.result='B';  
end  
	  
rule "Rule 6"  
   when  
         $p : Product(F1>=50, F3>=70, F1<80)  
   then  
         $p.result='C';  
end  
	  
rule "Rule 7"  
   when  
         $p : Product(F1>=50, F3>=70, F1>=80)  
   then  
         $p.result='D';  
end

In this blog, we will create a plugin that will allow us to draw Decision Trees in Draw.io and export the generated Drools rules.

  • Definitions: Fact’s structure and its attributes
  • Fact type: Used when creating the rules
  • Fact name: Used when creating the rules

When using Drools syntax, the properties have the following data structure:

Drools syntax properties

Tools and Drools syntax are very similar, we need to make changes in the traverseDroolsNode function:

function traverseDroolsNode(node, stack, rules, metadata) {  
       let expressionPushed = false;  
       if (node.children != null && node.children.length > 0) {  
           if (node.sourceExpression != null) {  
              stack.push(node.sourceExpression);  
              expressionPushed = true;  
            }  
            node.children.forEach((n) => {  
              traverseDroolsNode(n, stack, rules, metadata);  
            });  
        }  
        else {  
            if (node.sourceExpression != null) {  
              stack.push(node.sourceExpression);  
              expressionPushed = true;  
            }  
            const statement = stack.join(', ');  
            let rule = 'rule \"Rule ' + rules.length + '\"\n';  
            rule += '\twhen\n';  
            rule += '\t\t$' + metadata.factName + ' : ' + metadata.factType + '(' + statement + ')\n';  
            rule += '\tthen\n';  
            rule += '\t\t$' + metadata.factName + '.result=\'' + node.value + '\';\n';  
            rule += 'end';  
            rules.push(rule);  
        }  
        if (expressionPushed)  
            stack.pop();  
    }  

After the changes, we will create a submenu in the menu IW which will generate drool rules:

mxResources.parse('generateNoolsRules=Generate Nools Rules...');  
mxResources.parse('generateDroolsRules=Generate Drools Rules...');  
	  
uiEditor.actions.addAction('generateDroolsRules', function () {  
      const decisionTree = getDecisionTree(uiEditor.editor.graph.model);  
      const rules = buildDroolsRules(decisionTree);  
      uiEditor.saveData('decision-tree.drl', 'drools', rules, 'text/plain');  
});  
	  
uiEditor.actions.addAction('generateNoolsRules', function () {  
      const decisionTree = getDecisionTree(uiEditor.editor.graph.model);  
      const rules = buildNoolsRules(decisionTree);  
      uiEditor.saveData('decision-tree.nools', 'nools', rules, 'text/plain');  
	  
}); 
	 
let insertBeforeDiv = null;
for (let i = uiEditor.menubar.container.childNodes.length - 1; i >= 0; i--) {
      const div = uiEditor.menubar.container.childNodes[i];
      if (div.text != null && div.text != '') {
        insertBeforeDiv = div;
        break;
      }
}
	
uiEditor.menubar.addMenu('\u22eeIW', function (menu, parent) {  
        uiEditor.menus.addMenuItems(menu, ['generateNoolsRules'], parent);  
        uiEditor.menus.addMenuItems(menu, ['generateDroolsRules'], parent);  
}, insertBeforeDiv); 

When the coding process is finished we can load the tree and generate the new rules with the plugin as shown in the picture below:

Finally, our goal is completed and we have two plugins based on Nools and Drools for Drow.io. If you need any help with the setup don’t hesitate to reach us.