Статьи

Learn Drools (часть 4): выводы

Согласно словарю, умозаключение означает «Предположение или вывод, который сделан рационально и логически на основе данных фактов или обстоятельств».

Логический вывод основывается на фактах, поэтому обоснование такого вывода часто является логичным.

Пример. Согласно техническому интервью, мы можем предположить, что кандидат хороший, плохой или умеренный. Здесь следует отметить, что мы не знаем, насколько хорош кандидат, поскольку мы не работаем с ними, но по ответам (фактам) кандидата мы можем логически судить и прийти к выводу.

Итак, как работают выводы Друла?

Попробуем понять это с помощью постановки задачи.

Мы хотим дать ноутбук тем людям, которые работают в ИТ-отделе, чье назначение — менеджер.

Когда мы получим эту проблему, мы попытаемся решить ее с помощью правила Drools. Вводя логику, мы используем Ifdepertment == «IT» и isManager = true, затем печатаем «Give Laptop».

Так просто, как, что.

Решение

rule "give Laptop"
  when
     $dept: Department(name=="IT");
     $emp: Employee(dept == $dept,manager==true);

  then
  $emp.setMessage("Give Laptop");
  System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end

Это элегантный способ решить эту проблему?

Ответ зависит. Если эта проверка состояния IT Manager (depertment == «IT» и isManager = true) используется в нескольких правилах, то это не элегантный способ реализовать ее. Мы можем сделать это лучше, и вот потенциал, где мы можем использовать вывод.

С другой стороны, если в этом условии используется только одно или несколько правил и в будущем не требуется никаких изменений, сделайте это проще. Приведенное выше правило прекрасно, так как я большой последователь  YAGNI  (он вам не понадобится).

Почему вышеупомянутое не является разумным способом определить правила, в которых одно и то же условие используется в нескольких из них?

Допустим, условие ИТ-менеджера используется в 100 различных правилах, и на основании этого условия мы будем предпринимать разные действия. Пока что состояние не изменилось, поэтому наш дизайн хорош. Но подумайте, изменились ли требования к условиям — теперь клиент хочет (отдел == «ИТ» и isManager = true и опыт> 15). Теперь этот фактор опыта установлен выше 15, и это необходимо учитывать.

Итак, нам нужно изменить условие в 100 правилах. Простое изменение тогда трудно осуществить, потому что условие было продублировано более 100 раз.

Было бы неплохо, если бы мы могли спроектировать таким образом, чтобы мы могли определить условие в одном месте и использовать эту ссылку в других местах — например, мягкую ссылку в Unix или переменные среды в Windows.

Делая это, мы можем использовать ссылку на условие в каждом правиле. Мы устанавливаем JAVA_HOME = «C; // java»; и использовать JAVA_HOME в любом месте, чтобы объявить путь Java, поэтому в случае, если мы изменим путь Java на c: // javaone, это будет отражено везде.

К счастью, мы можем сделать то же самое в Drools через умозаключение. Давайте посмотрим, как это сделать шаг за шагом.

Шаг 1

Создайте правило, в котором мы определяем условие, и создаем ссылку на него в части «then», чтобы мы могли использовать эту ссылку в других правилах.

rule "IT Manager Inference"
   when
      $dept: Department(name=="IT");
      $emp: Employee(dept == $dept,manager==true);
   then
   insert(new ITManager($emp));
end

Обратите внимание на часть правила, в которой мы вставляем Java-объект ITManager, который принимает ссылку на сотрудника. Этим оператором мы инструктируем Drools вставлять объект ITManager в KnowledgeFactory, который содержит части «когда». Он действует как ссылка, как ключ JAVA_HOME.

Шаг 2

Let’s create other rules where we use this IT Manager reference.

rule "give Manager Laptop"
   when
      $emp: Employee();
      $itManager: ITManager(emp == $emp);

   then
   $emp.setMessage("Give Laptop");
   System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end

Pay attention to the «when» part here. We check to see if the current employee is matching the  ITManager condition. Here, Drools replaces ITManger with the actual «when» condition stated in the ITManager inference rule.

Step 3

Let’s look at our complete Drools rule file.

package com.rules

import com.example.droolsExample.pojo.Employee
import com.example.droolsExample.pojo.Department
import com.example.droolsExample.pojo.ITManager

rule "IT Manager Inference"
   when
      $dept: Department(name=="IT");
      $emp: Employee(dept == $dept,manager==true);
   then
   insert(new ITManager($emp));
end
rule "give Manager Laptop"
   when
      $emp: Employee();
      $itManager: ITManager(emp == $emp);

   then
   $emp.setMessage("Give Laptop");
   System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end

This setup ensures any changes in we made will be automatically reflected in our «Give Laptop» rule.

Step 4: Java Objects

Employee.java

package com.example.droolsExample.pojo;

public class Employee {

   String name;
   boolean manager;
   String message;
   Department dept;
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public boolean isManager() {
      return manager;
   }
   public void setManager(boolean manager) {
      this.manager = manager;
   }
   public String getMessage() {
      return message;
   }
   public void setMessage(String message) {
      this.message = message;
   }
   public Department getDept() {
      return dept;
   }
   public void setDept(Department dept) {
      this.dept = dept;
   }
}

ITManager.java

package com.example.droolsExample.pojo;

public class ITManager {

   private Employee emp;
   public ITManager(Employee emp)
   {
      this.emp=emp;
   }


   public Employee getEmp() {
      return emp;
   }

   public void setEmp(Employee emp) {
      this.emp = emp;
   }
}

Department.java

package com.example.droolsExample.pojo;

public class Department {

   String name;

   public String getName() {
      return name;
   }

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

DroolTest.java

package com.example.droolsExample;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;

import com.example.droolsExample.pojo.Department;
import com.example.droolsExample.pojo.Employee;



public class DroolsTest {

   public static void main(String[] args) throws DroolsParserException,
          IOException {
      DroolsTest droolsTest = new DroolsTest();
      droolsTest.executeDroolsEmployee("/com/rules/employeeInfernce.drl");
   }

      public void executeDroolsEmployee(String ruleFile) throws DroolsParserException, IOException {

      PackageBuilder packageBuilder = new PackageBuilder();

      InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);

      Reader reader = new InputStreamReader(resourceAsStream);
      packageBuilder.addPackageFromDrl(reader);
      org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
      RuleBase ruleBase = RuleBaseFactory.newRuleBase();
      ruleBase.addPackage(rulesPackage);

      WorkingMemory workingMemory = ruleBase.newStatefulSession();

      Department dep = new Department();
      dep.setName("Civil");

      Department dep1 = new Department();
      dep1.setName("IT");

      Employee emp = new Employee();
      emp.setName("Shamik Mitra");
      emp.setManager(true);
      emp.setDept(dep1);

      Employee emp1 = new Employee();
      emp1.setName("Samir Mitra");
      emp1.setManager(true);
      emp1.setDept(dep);

      workingMemory.insert(dep);
      workingMemory.insert(dep1);
      workingMemory.insert(emp);
      workingMemory.insert(emp1);
      workingMemory.fireAllRules();

   }

}

Step 5: Output

Shamik Mitra: IT:Give Laptop

And that’s it! Congratulations, you’ve set up an inference.