Русский
Русский
English
Статистика
Реклама

Использование Decision Table в JBoss Drools

Правила. Мы знаем это слово с самого детства. Сначала родители учат нас, как нужно правильно поступать, потом мы приходим в школу, где учителя диктуют свои порядки. В университете мы вновь сталкиваемся с правилами, которые для нас устанавливают преподаватели и деканат. По мере взросления мы начинаем следовать законам, которые разработаны государством. Что общего у всех этих правил? То, что они выверены годами, десятилетиями, а некоторые даже и поколениями. Представьте, какой была бы наша жизнь, если бы правила менялись часто: каждую неделю или каждый день!

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

Что это вообще такое?

Довольно часто в процессе разработки коммерческого софта мы сталкиваемся с проблемой, когда некоторую логику расчета необходимо передать на сторону заказчика. Зачастую представитель этого заказчика не хочет (или не может) использовать какой-либо язык программирования для описания необходимой логики работы приложения. В таких случаях на помощь приходят BRMS или Business Rule Management System. Это информационная система для создания, управления и исполнения той самой
бизнес-логики приложения, её также называют бизнес-правилами. Обычно такие системы состоят из сервера, на котором происходит выполнение правил - это юрисдикция программистов, и средств ведения самих правил - это уже зона ответственности бизнеса.

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

BRMS фреймворков на рынке достаточно много. Свои решения предлагают многие крупные компании: IBM, Red Hat, Agiloft, SAS и даже Bosch. Все они либо платные, либо не подходили нам по разным критериям. Мы решили начать с уже зарекомендовавшей себя системы JBoss Drools. Она достаточно надежная, проверенная временем, используется в банковских решениях, ритейле и телекоме, а также предоставляет возможность ведения бизнес-правил как на специальном языке DRL, так и с помощью Excel-таблиц. Существует также и несколько UI-решений для ведения правил. Так как наши аналитики используют единую систему ведения справочников и нам удобнее хранить правила там, от использования UI мы отказались в пользу понятных бизнесу Excel-таблиц.

Что же такое бизнес-правило и как оно выглядит?

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

У нас есть респондент, который обладает характеристикойГендерная идентичность (gender). В зависимости от значения этой характеристики респонденту выставляетсяПол (SEX).То есть, еслиgender = male, то значению свойства Пол нужно будет поставить1. В противном случае это будет2. На языке DRL это правило будет выглядеть следующим образом:

rule "Rule 1 Example 1"      when         $s: Respondent($s.gender == "male")      then         $s.addResult("SEX", "1");end rule "Rule 2 Example 2"      when         $s: Respondent($s.gender == "female")      then         $s.addResult("SEX", "2"); end

Таким образом, мы имеем некий синтаксис, очень похожий на языкGherkin. В нашем случае у нас есть два правила, которые состоят из условия (указанного после ключевого словаwhen) и результата, которой будет получен в ходе выполнения этого условия (идет после словаthen).Условия в терминологииDroolsпринято называтьLeftHandSide(илиLHS), а действия -RightHandSide(илиRHS). Стоит упомянуть еще об одном объекте:Respondent.Этоfact,то есть объект в текущей памятиDrools, над которым будут производиться те или иные преобразования. В нашем случае у этого объекта присутствуют свойстваgenderиresult. Для того, чтобы было удобнее работать с объектами,frameworkпредусматривает возможность введения переменных. Обычно переменные начинаются с символа$.

Вот так это правило будет выглядеть на языкеExcel-таблиц:

Пример правила в ExcelПример правила в Excel

Как создать таблицу правил?

Прежде, чем мы перейдем к описанию основных конструкций, используемых в таблицах, необходимо разобраться, как правильно формировать эту таблицу. Стоит отметить, чтоDroolsумеет работать как с таблицами, созданными в табличных редакторахMiscrosoftExcelилиOpenOffice, так и с форматомCSV. Перед применением правил они будут сконвертированы из табличной формы вDRL-формат.

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

Область настройки правилОбласть настройки правил

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

  • RuleSet здесь указывается имя пакета для сгенерированного файлаDRL. Этот параметр обязательно должен стоять первым

  • Import через запятую указываются факты с указанием пакета, а также такиеJava-классы, которые можно использовать в расчетах, например,java.lang.Math

  • Functions здесь можно описывать функции, которые будут работать в рамках данногоRuleSetа. Функции должны соответствоватьDRL-синтаксису.

В области описания правил тоже есть свои зарезервированные слова, при этом главным словом являетсяRuleTable, которое указывает на то, что таблица ниже соответствует таблице правил, которую движокDroolsдолжен преобразовать вDRL-синтаксис. Опционально можно указать название для таблицы правил. В нашем случае этоnameforRuleTable.

Область описания правилОбласть описания правил

Начиная со следующей строки идут колонки:

  • NAME имя правила. Его можно не указывать.

  • DESCRIPTION расшифровка для правила. Его тоже можно не указывать. Эти два параметра нужны для того, чтобы не потеряться в большом количестве правил.

  • CONDITION это тотLeftHandSideили указание условия, на основании которого будет выполненACTION. Этот параметр обязателен.

  • ACTION действие, которое необходимо применить к факту. В нашем случае это методaddResult, который добавляет вMapзначения результирующих переменных. Этот параметр обязателен. В блокеACTIONвыполняетсяJava-код, поэтому наличие точки с запятой здесь также обязательно. Также через точку с запятой можно указать сколько угодно методов.

    Следует отметить, что количествоCONDITIONиACTIONможет быть больше одного.

Как отмечалось ранее, строкой ниже идет присваивание переменной$sфактаRespondent. Отмечу, что его полное имя с названием пакета, в котором он находится, нужно обязательно указать в параметреImport. Если у нас несколькоCONDITIONотносятся к одному факту, тогда ячейки с фактом необходимо объединить в одну. Также мы можем работать с разными фактами в разныхCONDITION-колонках: для этого мы просто указываем новый факт и новую переменную, не забыв добавить его вImport.

Далее, на следующей строке, у нас идет описание самих правил в колонкеCONDITIONи действий в колонкеACTION, которые необходимо выполнить. Какие могут быть условия и действия к выполнению, я описал ниже. А пока перейдем к следующей строке. Это строка заголовков полей (Text-Parameter-Resultна картинке). Ее указывать обязательно. В противном случае те переменные/условия, которые будут указаны вместо этой строки,Droolsпроигнорирует. Далее у нас идет указание самих условий.

Какие могут быть условия?

В интернете достаточно много информации о том, как писать условия, но она разрозненная. Главной задачей этой статьи было собрать воедино все часто встречающиеся варианты.

Для начала стоит упомянуть еще раз, что все манипуляции мы будем производить над объектомRespondent. В нашей терминологии респондент это лицо, которое принимает участие в исследовании. У каждого респондента есть свой набор свойств (например, гендерная принадлежность, рассмотренная ранее). Для того, чтобы показать все многообразие условий, с которыми работаетDrools, я вынес каждое свойство в отдельное поле классаRespondent. Для простоты понимания, в качестве еще одного поля класса добавляемMap<String,String>result, в котором будем собирать все результирующие переменные. Таким образом, классRespondentбудет выглядеть так:

public class Respondent {    public int id;    public String gender;    public Boolean isActive;    public Integer age;    public List<String> pets;    public String city;    public List<String> devices;    public Map<String, String> properties;    public Car car;    public MobileBrand mobileBrand;    public Household household;    public Map<String, String> result = new HashMap<>();    public void addResult(String key, String value) {        result.put(key, value);    }//  getters, setters, constructor}

Самое простое правило, по определению гендерной принадлежности, мы уже рассмотрели. А что, если нам нужно определить половой признак только у тех респондентов, которые участвуют в исследовании? Для фильтрации таких респондентов мы будет использовать булеву переменнуюisActive.Значениеtrue респондент участвует в исследовании,falseнет.

Правила опредения пола респондентаПравила опредения пола респондента

На рисунке выше показано, как мы объединили два условия: активность респондента и его половой признак. Не трудно догадаться, что в таком случае происходит объединение правил, находящихся в одной строке, по логическомуИ. Два условия объединены одним фактомRespondent. Вот так выглядит описание правила на языкеDRL:

rule "name_for_RuleTable_20"when$s: Respondent(isActive == true, gender == "male")then$s.addResult("SEX", "M");endrule "name_for_RuleTable_21"when$s: Respondent(isActive == true, gender == "female")then$s.addResult("SEX", "F");end

Стоит отметить использование параметра$param-этот параметр работает в рамках одного столбца и во время компиляции правил он будет заменен на конкретное значение из ячейки. То есть условиеisActive== $paramбудет преобразовано вisActive==true. В случае работы с булевыми или целочисленными переменными экранировать его не надо. ДвижокDroolsпонимает, что это не строка. В случае работы со строками экранирование обязательно, как показано в примере со свойствомgender.

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

Правила определения половозрастного атрибутаПравила определения половозрастного атрибута

Данное правило производит разбивку активных респондентов по половому признаку, а также на две возрастные категории - до 17 лет включительно и после 18 лет. Повторюсь, в случае работы с числами экранирующие кавычки не требуются.

Еще один пример, где кавычки не требуются это перечисления. Допустим, каждый из респондентов обладает мобильным телефоном. В зависимости от того, какого бренда телефон, мы запишем в результирующую переменнуюPHONE_SALES_PERзначение процента продаж на мировом рынке мобильных устройств за 2019 год. Так как результирующий словарь в качестве значения принимает строку, то$paramнеобходимо экранировать. Также стоит отметить, чтоMobileBrandнеобходимо добавить в настройкуImportв области описания правил.

Правила определения процента продажПравила определения процента продаж

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

Правила определения сегмента рынка смартфоновПравила определения сегмента рынка смартфонов

В данном примере у нас будет два правила: если бренд мобильного телефона нашего респондента маркиSAMSUNGилиAPPLE, тогда в результирующую переменную мы запишем значениеPREMIUM. В случае, когда бренд телефонаHUAWEIилиXIAOMI, значение будетNOT_PREMIUM. (Прошу владельцев данных смартфонов меня извинить за то, что отнес ихкнепривилегированным :) ) Другими словами, мы выбираем значение из массива значений.

А если у нас обратная задача, когда мы имеем массив значений и при вхождении конкретного значения выполняется действие? В подобном случае мы используем конструкциюcontains. Эта конструкция работает со всеми объектами интерфейсаjava.util.Collection. В нашем примере у объектаRespondentесть коллекция домашних животныхpets.Мы сделали выборку тех респондентов, которые не достигли совершеннолетия и указали в своих ответах в качестве домашнего животного кошку или собаку. Третье правило сработает в том случае, если в семье есть и собака, и кошка. Так как домашнее животное это строковая переменная, то переменную$param мы заключаем в кавычки.

Правило определения домашнего животногоПравило определения домашнего животного

В следующих двух примерах мы рассмотрим еще один оператор работы с коллекциями:forall(<оператор>){<условие>}.В первом примере правило сработает в случае выполнения условия в фигурных скобках и хотя бы одного из перечисленных через запятую параметров в ячейке. Во втором примере должно выполниться условие в фигурных скобках со всеми параметрами, перечисленными через запятую в соответствующей ячейке. Другими словами, в первом примере объединение условий происходит через логическоеИЛИ, тогда как во втором черезИ. Это условие и указывается в фигурных скобках. Важно отметить, что переменная, которая будет обращаться к значению ячейки, в данном случае указывается без словаparam. Еще один интересный момент, который я хотел бы отметить в примерах ниже это отсутствие ссылки на факт ($s). Дело в том, что если мы работаем с одним фактом, тоDroolsпонимает, что мы обращаемся полям класса-факта (cityиdevices), поэтому указание переменной в описанииCONDITIONможно опустить.

Правила определения округа и интернет-активностиПравила определения округа и интернет-активности

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

Правила определения количества устройств в собственностиПравила определения количества устройств в собственности

Когда у объекта-факта много вложенных свойств, это немного затрудняет понимание объекта, а также работу с ним. Поэтому мы стараемся все свойства объекта привести к словарю с парой ключ-значение.Droolsимеет удобный механизм обращения к значениям словаря по ключу:

Правила определения образованияПравила определения образования

В нашей практике мы часто получаем значение с древовидными структурами, когда объект имеет вложенные классы со своими наборами свойств. Предлагаю разобрать несколько таких примеров. Допустим, у каждого респондента есть вложенный объектCarcнабором свойств: порядковый номер, марка автомобиля, модель и год выпуска. И, к примеру, нам необходимо категоризировать автомобиль по году выпуска. Для того, чтобы обратиться к объекту в родительском объекте-факте, необходимо явно указать новую переменную и вложенный объект. В ячейке описания условия нужно сослаться на этот дочерний объект с помощью ключевого словаfrom:

Правила определения возраста автомобиляПравила определения возраста автомобиля

Достаточно удобно объединять вложенные объекты и их наборы свойств, которые представлены в виде словаря. В примере, описанном ниже, у объектаCar,который является частью фактаRespondent,естьMap<String,String>properties с набором свойств. В данном наборе правил мы обращаемся к свойствуPOWER. Также в описании условий правил присутствует функцияDroolsgetValue. Ее реализацию необходимо вынести в блокFunctions в области настройки правил:

Описание функции getValueОписание функции getValue

И само правило:

Правила определения мощности автомобиляПравила определения мощности автомобиля

В заключение описания возможных реализаций условий хотелось бы показать комплексный пример использования словаря во вложенном объекте, где в качестве значения по ключу используется массив данных. Условие задачи звучит следующим образом: необходимо отобрать тех респондентов, у которых в домохозяйстве есть приставкаPlayStation. Другими словами, у дочернего объектаHouseholdфактаRespondentнеобходимо найти свойствоTVDevicesи проверить наличие приставкиPlayStation. Правило будет выглядеть следующим образом:

Правило определения наличия PlayStationПравило определения наличия PlayStation

Как все это применять?

Все описанные выше условия мы можем комбинировать различным образом между собой или создавать длинные цепочки правил через логическое объединение. Но как мы можем эффективно использовать блокACTION? Как я уже отмечал, в этом блоке мы можем воспользоваться всем арсеналом возможностейJava. В описанных примерах я использовал достаточно тривиальный метод добавления значения в словарь. Очень часто, особенно для отладки правил, удобно использовать вACTIONлогирование или вывод на консоль.

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

  • setустанавливает значение свойства факта, но не уведомляет движокDroolsоб этом;

  • updateуведомляет движок о том, что факт был изменен посредством одного или несколькихset;

  • modifyэто некая сумма двух предыдущих действий, здесь происходит установка одного или нескольких свойств факта, а также уведомляется движок об изменении факта;

  • insertдобавление нового факта.

Приведу пример наиболее часто используемого выраженияmodify.

В первомRuleTableмы производим отбор тех активных респондентов, у которых по каким-то причинам возраст больше 99 лет и меньше 0. Если такие респонденты найдены, то выражение изменит факт$r, то естьRespondentaи установит ему значениеfalse.В следующемRuleTableу нас будет уже измененное свойствоisActiveи неактивным респондентам в свойствеREJECTEDзапишется значениеTRUE.

В заключение

Моей задачей было рассказать об основном функционале использования логики для описанияCONDITION. Безусловно, есть и другие варианты использования. Все приведенные мной примеры упрощены для того, чтобы было легче начать использование разных конструкций как опытным программистам, так и начинающим. В реальном продакшене правила получаются гораздо сложнее и объемнее.Drools позволяет реализовать достаточно сложную логику. В официальной документации есть даже примеры реализации игр, но, к сожалению, без помощи табличного представления.

Информацию по запускуDroolsи работе с ним можно с легкостью найти в интернете или же форкайте мой проект с примерами на гитлаб (https://github.com/sxexesx/drools-decision-table).

Спасибо за внимание! Надеюсь, данная статья окажется полезна тем, кто хочет погрузиться в удивительный мирBRMS!

Источник: habr.com
К списку статей
Опубликовано: 18.12.2020 00:05:23
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Java

Визуальное программирование

Brms

Drools

Jboss

Excel

Decision table

Rules

Ruleset

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru