Механизм правил – это логика или условие, например: "Когда некоторые условия оцениваются как истинные, выполните некоторую задачу". Механизм правил можно рассматривать как сложный интерпретатор операторов if/then

Rule Engine состоит из трех компонентов

  • Правила
  • Факт/ы
  • Оценщик

Определение условия правила

Мы будем использовать просеивание для определения правил, он предоставляет синтаксис типа запроса mongodb для определения правила и простой API для проверки по текущим объектам.

Чтобы определить правило, вы можете использовать операторы запросов mongodb, такие как
$in → Для проверки заданного значения в диапазоне
$lte → Для проверки заданного значения меньше определенного значения

Давайте определим правило просеивания

Правило — Пользователь принадлежит к городу "Дели" и имеет возраст от 20 до 30 лет.

import sift from 'sift';
const youngUsersWithCityDelhi = sift({ age: {$gt: 20, $lt: 30}, city: 'Delhi' });
const oldUsersWithCityDelhi = sift({ age: {$gt: 50}, city: 'Delhi' });

Здесь вы создали два правила, вы можете хранить эти правила в памяти или хранить их в БД, поскольку их можно преобразовать в строку.

Определите факты

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

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

const Person1 = {
  age: 10,
  city: 'Delhi'
}
const Person2 = {
  age: 25,
  city: 'Delhi'
}

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

Как правило, будет один факт для каждого запроса или варианта использования, но все может измениться в соответствии с требованиями.

Определить репозиторий правил

Repostiroy отвечает за фильтрацию/выбор подходящих правил для определенного сценария, а затем проверяет подходящие правила, какие из них применяются, а затем принимает соответствующие

Оценщик правил

С созданными фильтрами правила оценки довольно просты. В приведенном выше примере мы создали два правила и два контрольных факта. Вот как мы можем проверить, применимо ли правило к факту или нет.

import sift from 'sift';
const youngUsersWithCityDelhi = sift({ age: {$gt: 20, $lt: 30}, city: 'Delhi' });
const oldUsersWithCityDelhi = sift({ age: {$gt: 50}, city: 'Delhi' });
const Person1 = {
  age: 10,
  city: 'Delhi'
}
const Person2 = {
  age: 25,
  city: 'Delhi'
}

console.log(youngUsersWithCityDelhi(Person1)) // false
console.log(youngUsersWithCityDelhi(Person2)) // true

Множитель перенапряжения

Постановка задачи

Учитывая список правил всплеска с условием и множителем, рассчитайте множитель всплеска для данного сценария.

Правило

Создадим класс для правила, у которого будет свое условие и множитель

export default class Rule {
    constructor(name, condition) {
        this.name = name;
        this.condition = condition;
    }
}
export class SurgeRule extends Rule {
    constructor(name, condition, surgeMultiplier) {
        super(name, condition);
        this.surgeMultiplier = surgeMultiplier;
    }
}

Факт/ы

Определите факт, убедитесь, что схема факта совпадает со схемой правила. Факт может быть создан с использованием комбинации нескольких атрибутов объектов, таких как параметры запроса пользователя и другие объекты.

const fact1 = {
    rain: true,
    isPremiumUser: false,
    orderAmount: 400
}
const fact2 = {
    rain: false,
    isPremiumUser: true,
    orderAmount: 600
}

Репозиторий

Репозиторий — это место, где будут храниться все правила и связанные с ними метаданные. Он будет использоваться для фильтрации неактивных правил или любой необходимой пользовательской фильтрации.

export class RuleRepository {
    constructor(rules) {
        this.rules = rules;
    }

getRules() {
    return this.rules;
    }

 getRulesForRain() {
    return this.rules.filer(rule => rule.rain == true);
   }
}

основной

import sift from 'sift';
import { SurgeRule } from './rule.js';
import { RuleRepository } from './rule-repository.js';
import { SurgeService } from './surge-service.js';

const lowSurgeMultiplierRule = new SurgeRule('low-surge', {rain: false, isPremiumUser: true, orderAmount: {$gt: 500}}, 1.1);
const mediumSurgeMultiplierRule = new SurgeRule('mid-surge', {rain: false, isPremiumUser: false, orderAmount: {$gt: 500}}, 1.5);
const highSurgeMultiplierRule = new SurgeRule('high-surge', {rain: true, isPremiumUser: true, orderAmount: {$gt: 500}}, 2);
const defaultSurgeMultiplierRule = new SurgeRule('high-surge', {}, 1.3);
const rules = [lowSurgeMultiplierRule, mediumSurgeMultiplierRule, highSurgeMultiplierRule, defaultSurgeMultiplierRule];
const ruleRepository = new RuleRepository(rules)
const surgeService = new SurgeService(ruleRepository, sift)
const fact1 = {
    rain: true,
    isPremiumUser: false,
    orderAmount: 400
}
const fact2 = {
    rain: false,
    isPremiumUser: true,
    orderAmount: 600
}
console.log(surgeService.getSurgeMultiplier(fact1)) // 1.3 as it matched with last rule
console.log(surgeService.getSurgeMultiplier(fact2)) // 1.1

Пример кода можно найти по адресу — https://replit.com/@09saurabh09/RuleEngineSift

Хороший, плохой и уродливый

Хороший

  • Определение правила легко, поддерживает несколько операторов
  • Проверка правила делегирована просеиванию
  • Может храниться в любой БД
  • Может работать с моделью с несколькими матчами, гибкой для использования так, как вы хотите

Плохой

  • Необходимо преобразовать/сериализовать перед сохранением правил
  • Невозможно фильтровать правила на основе условия правила
  • Необходимо написать дополнительный код для составления правил
  • Зависит от языка

Уродливый

  • Необходимо перебрать все правила, чтобы найти возможное совпадение

Спасибо

Спасибо, что прочитали эту статью! Если вы хотите углубиться и быть в курсе моих последних идей и статей, обязательно подпишитесь на меня на Medium и не стесняйтесь связаться со мной в LinkedIn.

Рекомендации

https://github.com/crcn/sift.js