Статьи

JBoss Drools — Начало работы

Этот пост будет посвящен тому, как я справляюсь с JBoss Drools . Причиной этого является то, что SAP выкупила действующий механизм правил моей компании, а Drools — одна из альтернатив, которую мы рассмотрим, как только у кого-то появятся навыки для подтверждения концепции.

Хотя документации кажется довольно много, я всегда нахожу, что помогает просмотреть примеры, что я и собираюсь сделать здесь. На первый взгляд слюни могут быть довольно пугающими, они состоят из:

Слюни Эксперт (правило двигателя)
Будучи разработчиком, я начну с настоящих правил и их реализации.

Другие части, к которым я вернусь позже:
Слюни Гувнор (BRMS / BPMS)
Drools Flow (процесс / рабочий процесс)
Drools Fusion (обработка событий / временные рассуждения)
Drools Planner (автоматизированное планирование)

Итак, для начала.
Для начала, я просто хочу промокнуть, загружаю только плагин Eclipse и бинарные файлы

Нужно установить плагин Eclipse, используется сайт обновления . Разархивируйте двоичные файлы в каталог и с помощью настроек плагина Eclipse укажите на этот каталог.

Плагин eclipse позволит вам создать проект Drools, который включает в себя «библиотеку Drools», но если вы используете maven, вам нужно указать на репозиторий JBoss для зависимостей Drools, для KnowledgeRuntimeLoggerFactory требуется XStream, который вы можете просто получить из стандартный репозиторий Maven. Ниже мой POM:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 <modelversion>4.0.0</modelVersion>
 <groupId>javaitzen.drools</groupId>
 <artifactid>LearningToDrool</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <properties>
  <drools.version>5.1.1</drools.version>
 </properties>
 <repositories>
  <repository>
   <name>JBoss</name>
   <id>JBoss</id>
  </repository>
 </repositories>
 <dependencies>
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-core</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>org.drools</groupId>
   <artifactid>drools-compiler</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-api</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>com.thoughtworks.xstream</groupId>
   <artifactId>xstream</artifactId>
   <version>1.3.1</version>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
  
</project>

Чтобы добавить правило, в src / main / rules щелкните правой кнопкой мыши -> New -> Other… Drools / Rule Resource, обязательно выберите «отдельное правило». Это оставляет вас с пустым файлом drl:

1
2
3
4
5
6
7
8
9
package javaitzen.drools.rules
  
rule "A stand alone rule"
   
 when
  #conditions
 then
  #actions 
end

Чтобы понять и использовать язык правил, я прочитал документацию Drools и проект примеров.
На самом деле мне потребовалось немного разобраться, это основной синтаксис и то, как объекты обрабатываются в правилах, и я изо всех сил пытался найти что-то, что на самом деле объясняет это просто, поэтому я попробую.

Замечание об именах переменных … им не нужно иметь ‘$’, но он использовался в примере и без него быстро запутывается.

Теперь, чтобы пройтись по частям правила:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package javaitzen.drools.rules
  
import javaitzen.drools.RoolVO
  
rule "Basic Rule"
   
 when
 $vo : RoolVO( stringValue == "Learning to drool",
                      $booleanVal : booleanValue )
 eval( $booleanVal )
 then
        System.out.println( "First Rule" );
 $vo.setStringValue("Done.");
end

Пакет и ключевое слово import говорят сами за себя, что происходит после того, когда not нет.
То, что происходит в «$ vo: RoolVO (stringValue ==« Учимся пускать слюни », $ booleanVal: booleanValue)», на самом деле выглядит так:

stringValue == «Learning to drool» — это ограничение, которое позволяет нам находить все известные в базе знаний объекты RoolVO, у которых значение getStringValue () равно «Learning to drool». Если есть несколько экземпляров RoolVO, которые соответствуют, мы будем запускать это правило более одного раза, они также называются совпадающими объектами. Вы также можете иметь несколько ограничений, разделенных «,».

$ booleanVal: booleanValue — мы объявляем новую локальную переменную типа boolean с именем $ booleanVal и получаем ее значение из isBooleanValue.

$ vo: RoolVO — мы объявляем новую локальную переменную типа RoolVO с именем $ vo.

Следующая строка:
«Eval ($ booleanVal)» — оценивает логическую переменную, которая должна быть оценена как истинная для части правила then, которая будет вызвана.
Потом:
System.out.println («Первое правило»); — Стандартный системный выход.
$ vo.setStringValue ( «Готово.»); — Устанавливает значение String для текущего объекта RoolVO, который соответствует ограничениям, на «Готово».

Основные классы / интерфейсы, необходимые для выполнения основного правила, выглядят следующим образом:
org.drools.KnowledgeBase и это фабрика
org.drools.KnowledgeBaseFactory:
Это хранилище всех соответствующих определений знаний; он содержит правила, процессы, функции, модели типов.

org.drools.builder.KnowledgeBuilder и его фабрика org.drools.builder.KnowledgeBuilderFactory:
Преобразует / анализирует исходный файл (.drl, .xsl) в пакет знаний, который может понять база знаний.

StatefulKnowledgeSession создан с помощью базы знаний .newStatefulKnowledgeSession ();
Этот сеанс используется для связи с действительным механизмом правил.

Чтобы процитировать слюни JavaDocs:
StatefulKnowledgeSession — наиболее распространенный способ взаимодействия с механизмом правил. StatefulKnowledgeSession позволяет приложению устанавливать итеративный диалог с механизмом, где процесс рассуждения может запускаться несколько раз для одного и того же набора данных.

Я написал простой тест для правила, которое я описал ранее.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package javaitzen.drools;
  
import static org.junit.Assert.assertEquals;
  
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.junit.Before;
import org.junit.Test;
  
public class TestBasicRules {
  
 private KnowledgeBase kbase;
   
 @Before
 public void setup() {
  KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
  kbuilder.add(ResourceFactory.newClassPathResource("basic.drl"), ResourceType.DRL);
  KnowledgeBuilderErrors errors = kbuilder.getErrors();
  if (errors.size() > 0) {
   for (KnowledgeBuilderError error: errors) {
    System.err.println(error);
   }
   throw new IllegalArgumentException("Could not parse knowledge.");
  }
  kbase = KnowledgeBaseFactory.newKnowledgeBase();
  kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
       
    
 }
   
 @Test
 public void testBasic() {
  
  StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
  KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
  
  RoolVO vo = new RoolVO();
  vo.setStringValue("Learning to drool");
  vo.setBooleanValue(true);
  ksession.insert(vo);
  ksession.fireAllRules();
  for (Object o: ksession.getObjects()) {
   if(o instanceof RoolVO) {
    assertEquals("Done.", ((RoolVO) o).getStringValue());
   }
  }
  logger.close();
    
 }
  
}

Честно говоря, Drools не настолько интуитивен, как Quickrules из того, что я видел в этой первой задаче. Однако ниже я начну смотреть на использование потоков правил, функциональности таблицы решений, а также руководствуясь правилами:

Надеемся, что те, кто сотрудничает с конструкцией DSL (Domain Specific Language), позволяют создавать более интуитивно понятные правила.

Ранее я прошел основной синтаксис и требования, чтобы разработать и протестировать правило.
Теперь, чтобы расширить это, документация Drools на самом деле довольно хороша, ее просто масса, поэтому я попытаюсь сосредоточиться только на некоторых основных темах.

Сначала мне нужно было сделать небольшую вещь, чтобы заставить правила запускаться из ваших тестов с использованием maven. .Drls не находятся в пути к классам по умолчанию, а простым способом было добавить следующее в POM:

1
2
3
4
5
6
7
<build>
  <resources>
   <resource>
    <directory>src/main/rules</directory>
   </resource>
  </resources>
</build>

Теперь больше правил сценариев и использования:

Коллекции:
Запрос к содержимому a может быть выполнен двумя способами: contains и memberOf, разница в том, что коллекция, используемая вместе с memberOf, должна быть переменной.

Drl:

1
2
3
4
5
6
7
rule "Use a Collection"
 when
  $vo : RoolVO( listValue contains  "items" )
 then 
  $vo.setStringValue("Done.");
  logger.log(Level.INFO,"Used a collection");
end

Обычные выражения:
Вы можете использовать регулярное выражение в качестве критерия выбора, а также с ключевыми словами Совпадения, а не Совпадения.

Drl:

1
2
3
4
5
6
7
rule "Use a Regular Expression"
 when
  $vo : RoolVO( stringValue matches  "(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)")
 then 
  $vo.setStringValue("Done.");
  logger.log(Level.INFO,"Found the date with a regular expression dd/mm/yyyy");
end

Глобальные переменные:
Вы можете определить глобальные переменные, они не должны использоваться, поскольку они иногда находятся в коде, для передачи информации между методами или в этом случае правилами. Их скорее следует использовать для предоставления данных или услуг, которые используются правилами. Примером может служить что-то вроде логгера, специфичного для приложения, или, возможно, данные постоянного поиска, загружаемые при запуске приложения.

Тест:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class TestBasicRules {
  
 private KnowledgeBase kbase;
 private Logger javaLogger = Logger.getLogger("testLogger");
 @Test
 public void testGlobal() {
  
  StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
  
  RoolVO vo = new RoolVO();
  vo.setStringValue("Global");
  ksession.insert(vo);
  ksession.setGlobal("logger", javaLogger);
  ksession.fireAllRules();
  checkDone(ksession);   
 }

Drl:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package javaitzen.drools.rules
  
import javaitzen.drools.RoolVO
import java.util.logging.Level
  
global java.util.logging.Logger logger;
  
rule "Use a Global "
   
 when
  $vo : RoolVO( stringValue == "Global")
 then 
  $vo.setStringValue("Done.");
  logger.log(Level.INFO,"Logging with a global");
end

Атрибуты правила:
В правиле вы можете указать атрибут, есть несколько из них. Я просто упомяну пару удобных (цитирую официальную документацию):

нет петли
значение по умолчанию: false
тип: логическое
Когда следствие правила модифицирует факт, это может привести к повторной активации правила, что приведет к рекурсии. Если для параметра no-loop установлено значение true, попытка создать активацию для текущего набора данных будет игнорироваться.

выпуклость
значение по умолчанию: 0
тип: целое число
Значимость — это форма приоритета, при которой правила с более высокими значениями значимости получают более высокий приоритет при заказе в очереди активации.

диалект
значение по умолчанию: как указано в пакете
Тип: Строка
возможные значения: «java» или «mvel»
Диалект определяет язык, который будет использоваться для любых кодовых выражений в кодовом блоке LHS или RHS. В настоящее время доступны два диалекта: Java и MVEL. Хотя диалект можно указать на уровне пакета, этот атрибут позволяет переопределить определение пакета для правила.

дата эффективной
значение по умолчанию: N / A
тип: строка, содержащая определение даты и времени
Правило может быть активировано, только если текущая дата и время находятся после атрибута даты вступления в силу.

дата истечения срока действия ,
значение по умолчанию: N / A
тип: строка, содержащая определение даты и времени
Правило не может активироваться, если текущая дата и время находятся после атрибута date-expires.

Руководствуясь правилом:
Редактор управляемых правил, кажется, позволяет делать все, что вы можете сделать в коде, только визуально и, возможно, более интуитивно понятным для тех, кто не является разработчиком. Единственное, что вам нужно сделать, это убедиться, что объекты, которые вы хотите использовать, импортированы в .package в том же месте, что и созданный файл .brl.

Таблицы решений:
На мой взгляд, мир на самом деле работает на электронных таблицах. Нам всем нравится думать, что он работает только благодаря нам и нашим модным приложениям, но, по правде говоря, мир будет пропускать электронные таблицы больше, чем любое другое отдельное приложение.

Деловые люди, предъявляющие нам наши требования, понимают электронные таблицы, некоторые из них лучше, чем мы, разработчики, и это самый большой бонус на таблицах решений. Таблица решений Drools на первый взгляд выглядела так, как будто ее было бы не так просто передать бизнес-пользователям, как таблица Quickrules, но на самом деле она довольно четко разделена на «код» и «данные».

Теперь разбить таблицу решений на части …
При создании таблицы решений плагин eclipse дает вам пример, я собираюсь разобраться с этим.

C2: Набор правил для ключевых слов, просто чтобы заявить, что эта электронная таблица является набором правил (пакетом).
D2: Имя набора правил (пакета).
В этой строке вы можете указать следующие необязательные ключевые слова:
Последовательный — ячейка справа от этого может быть истинным или ложным. Если это правда, то значимость используется для обеспечения того, чтобы правила срабатывали сверху вниз.
Импорт — в ячейке справа содержится список классов для импорта, разделенных запятыми.
Переменные. Ячейка, расположенная непосредственно справа, может содержать глобальные объявления, которые поддерживает Drools. Это тип, за которым следует имя переменной. (если необходимо несколько переменных, разделите их запятыми).

C3 / D4: примечание заголовок и фактические примечания.

C5: ключевое слово и имя RuleTable. Ключевое слово «RuleTable» должно появляться в верхней части первого столбца условия. Вы можете иметь несколько таблиц правил на листе, они должны быть просто разделены линией.

C6: Помечает столбец как столбец СОСТОЯНИЕ, G6, делает это для ДЕЙСТВИЯ. Вам нужен по крайней мере один из них для того, чтобы таблица была действительной. Если в столбце СОСТОЯНИЕ нет данных, то это условие не применяется.
Другие столбцы необязательные ключевые слова:
ПРИОРИТЕТ — Это заявляет, что значения этого столбца установят значимость
DURATION — Это установит значения продолжительности для строки правила.
NO-LOOP — То же, что и в drl, это указывает, не разрешено ли циклу правило.

C7: Этот и последующие столбцы в строке определяют фактические переменные, указанные в таблице правил.

C8: Этот и последующие столбцы в строке указывают, откуда мы получаем данные.

Строка 9 и столбец B — это просто метки / заголовки, облегчающие понимание данных, все остальные поля и столбцы перед тем, как их можно спрятать, чтобы не напугать «менее техничных». Тогда таблица внутри B9 — это данные, в которых данные конкретного правила определены, возможно, непосредственно из спецификации, не разработчиком.

Я загрузил этот проект в свой проект кода Google, если кто-то захочет. У меня возникла небольшая проблема с таблицей решений, потому что я запускаю OpenOffice дома, а не Microsoft Office, плагин ожидает Excel, поэтому он оставляет уродливый маленький красный X в моем проекте, но он прекрасно открывается за пределами IDE и по-прежнему компилируется в maven.

В следующем посте я посмотрю на поток правил и начну заниматься монстром Гувнором.

Ссылка: учимся слюни … Часть 1 и учимся слюни … Часть 2 от нашего партнера JCG