【底层服务/编程功底系列】「手把手教学系列」带你打造一个属于自己的规则引擎服务,打破任何业务难题(逻辑模型和API设计)(一)

简介: 【底层服务/编程功底系列】「手把手教学系列」带你打造一个属于自己的规则引擎服务,打破任何业务难题(逻辑模型和API设计)

规则引擎是什么

规则引擎是一种基于规则的软件系统,它可以自动化地执行规则,从而实现业务流程控制、风险管理、决策支持等功能。规则引擎通常由三个主要组件组成:规则信息库、逻辑推理引擎和执行引擎。



规则信息库

规则信息库是规则引擎的数据核心,它包含了所有的规则。

规则可以是 业务规则决策规则计算规则 等等。规则信息库通常采用类似于数据库的结构来存储规则,每个规则都有一个唯一的标识符、一个条件部分和一个结果部分。

  • 条件部分描述了规则的前提条件
  • 结果部分描述了规则的执行结果

逻辑推理引擎

逻辑推理引擎是规则引擎的计算核心,它负责根据规则信息库中的规则和输入数据来推导出结果。

逻辑推理引擎通常采用基于规则的推理机制,即根据规则的前提条件和输入数据来匹配规则,并执行规则的结果部分。

推理引擎还可以支持多种推理算法,如前向推理、后向推理、混合推理等。

程序执行引擎

程序执行引擎是规则引擎的执行核心,它负责将推理引擎计算出的结果应用到实际业务中。

程序执行引擎通常采用类似于工作流引擎的方式来执行规则,即按照规则的执行顺序来依次执行规则组件。程序执行引擎还可以支持多种执行方式,如同步执行、异步执行、批量执行、延时执行或者定时执行等。

程序执行引擎的优点在于它可以将 业务规则计算逻辑 从应用程序中分离出来,从而实现 业务逻辑可配置可扩展可重用 。程序执行引擎还可以提高业务流程的自动化程度,减少人工干预,提高业务处理效率和准确性。

总之,规则引擎是一种强大的软件工具,它可以帮助企业实现业务流程控制、风险管理、决策支持等功能,提高业务处理效率和准确性

规则引擎的使用场景

当然可以,请问您需要的规则引擎是用于什么样的场景和目的呢?例如,是用于业务流程控制、风险管理、决策支持等方面。同时,您需要考虑的因素还包括规则的复杂度、数据量、性能要求等等。


规则引擎的核心逻辑模型的介绍

以下是规则引擎的核心逻辑模型的大概架构图,如下所示:


接下来我们,针对于Rule规则模型以及RuleEngine运作引擎模型的大概行为以及服务能力进行相关的介绍和说明。

Rule规则模型

Rule规则模型属于规则引擎中最基础的数据信息模型,同样也是整个规则引擎执行逻辑的“物质基础”,它为程序执行引擎和逻辑推理引擎提供了根本方向。它主要由三部分组成:


Action- 触发行为

Action(触发行为)主要表示为执行某种行为或者操作的模式,大家可以理解为执行处理的一个操作。例如:当我们发觉我们饿了,我们就应该去吃饭,而这里的“吃饭”代表着就是Action行为操作。至于吃什么,就如同我们的参数一样,传递苹果我们就吃苹果;传递香蕉,我们就吃香蕉。

代码案例

下面我们代码去实现一个Action触发的接口模型,其中Action触发行为的视实现,只有通过

java

复制代码

@FunctionalInterface
public interface Action {
    void execute(Facts facts) throws Exception;
}

从以上代码可以看出,该代码段主要代表了值的执行行为和内容。其中,它的参数类型为Facts。Facts是用户可以自定义的事实,它表示实际的参数,也可以称为事实参数(Fact Parameters)。关于Facts的具体内容,我们将在后面的参数部分进行介绍,目前暂时不进行过多赘述。

大家只要知道Action接口主要用于定义我们的执行行为就可以了,当规则的条件评估为 "true "时执行操作。

Condition-条件判断

Condition的条件接口,主要用于控制和判断是否要执行上面所定义的Action接口所要执行的行为动作,通过evaluate方法的返回值,从而判断是否需要进行执行Action接口的实际功能。下面则是我们定义的Condtion条件判断接口的执行逻辑代码。

java

复制代码

@FunctionalInterface
public interface Condition {
    /**
     * Evaluate the condition according to the known facts.
     * @param facts known when evaluating the rule.
     * @return true if the rule should be triggered, false otherwise
     */
    boolean evaluate(Facts facts);
    /**
     * A NoOp {@link Condition} that always returns false.
     */
    Condition FALSE = facts -> false;
    /**
     * A NoOp {@link Condition} that always returns true.
     */
    Condition TRUE = facts -> true;
}

其中这两个字段,主要用于Lamda表达式作为一个变量处理。因为属于Lamda表达式,所以不会立刻加载,属于懒惰操作加载处理。

java

复制代码

/**
     * A NoOp {@link Condition} that always returns false.
     */
    Condition FALSE = facts -> false;
    /**
     * A NoOp {@link Condition} that always returns true.
     */
    Condition TRUE = facts -> true;

从对于Condition接口的定义的evaluate(Facts facts);方法,可以看出来,它的参数也是Facts。因此可以的得出结论,Condition也是根据实际情况的参数进行判断是否符合满足条件进行执行对应的Condition条件。

Parameter-实际参数

首先Parameter的实际参数模型,主要属于一个抽象、泛化的类型数据模型,最简单也最方便的数据模型就是Map数据模型。但是由于Map的性能以及一些定制化功能的开发量过多,所以我们再次没有选择Map,而是选择了自定义K-V结构化的数据模型。



Fact的参数模型

当涉及到Fact数据模型子元素时,它通常采用键-值(K-V)结构。这种结构由两部分组成:键(Key)和对应的值(Value)。键用于标识和索引数据,而值则包含了与该键相关联的具体信息。

Fact数据模型子元素的关键特点是它们的多样性和可扩展性。通过使用K-V结构,我们可以根据实际需求存储和表达各种类型的数据。例如,对于一个商品,可以使用键值对来表示商品的名称、价格、描述等信息。

另一个重要的特征是Fact的可组合性。多个Fact数据模型子元素可以组合成一个更复杂的数据集合。这种组合性使得我们能够处理和管理大量的数据,并在需要时对其进行灵活的访问和操作。

总结一下,Fact数据模型子元素是基于K-V结构的,用于存储和表示各种类型数据的元素。它们具有多样性、可扩展性和可组合性的特点,使我们能够有效地处理和管理复杂的数据集合。

代码案例

java

复制代码

public class Fact<T> {
  private final String name;
  private final T value;
  /**
   * Create a new fact.
   * @param name of the fact
   * @param value of the fact
   */
  public Fact(String name, T value) {
    Objects.requireNonNull(name, "name must not be null");
    Objects.requireNonNull(value, "value must not be null");
    this.name = name;
    this.value = value;
  }
  /**
   * Get the fact name.
   * @return fact name
   */
  public String getName() {
    return name;
  }
  /**
   * Get the fact value.
   * @return fact value
   */
  public T getValue() {
    return value;
  }
  @Override
  public String toString() {
    return "Fact{" +
        "name='" + name + '\'' +
        ", value=" + value +
        '}';
  }
  /*
   * The Facts API represents a namespace for facts where each fact has a unique name.
   * Hence, equals/hashcode are deliberately calculated only on the fact name.
   */
  
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Fact<?> fact = (Fact<?>) o;
    return name.equals(fact.name);
  }
  @Override
  public int hashCode() {
    return Objects.hash(name);
  }
}
Facts的参数模型

在这种情况下,参数主要由Fact数据模型子元素(K-V结构)和K-V结构体集合组成。实际过程中可能会有多个K-V对应的数据需要传输,因此需要使用另一个容器来组装参数数据集合模型,即Facts。Facts表示多个Fact,即多个K-V结构的数据集合。

java

复制代码

public class Facts implements Iterable<Fact<?>> {
    private final Set<Fact<?>> facts = new HashSet<>();
    /**
     * Add a fact, replacing any fact with the same name.
     *
     * @param name of the fact to add, must not be null
     * @param value of the fact to add, must not be null
     */
    public <T> void put(String name, T value) {
        Objects.requireNonNull(name, "fact name must not be null");
        Objects.requireNonNull(value, "fact value must not be null");
        Fact<?> retrievedFact = getFact(name);
        if (retrievedFact != null) {
            remove(retrievedFact);
        }
        add(new Fact<>(name, value));
    }
    
    /**
     * Add a fact, replacing any fact with the same name.
     * 
     * @param fact to add, must not be null
     */
    public <T> void add(Fact<T> fact) {
        Objects.requireNonNull(fact, "fact must not be null");
        Fact<?> retrievedFact = getFact(fact.getName());
        if (retrievedFact != null) {
            remove(retrievedFact);
        }
        facts.add(fact);
    }
    /**
     * Remove a fact by name.
     *
     * @param factName name of the fact to remove, must not be null
     */
    public void remove(String factName) {
        Objects.requireNonNull(factName, "fact name must not be null");
        Fact<?> fact = getFact(factName);
        if (fact != null) {
            remove(fact);
        }
    }
    /**
     * Remove a fact.
     *
     * @param fact to remove, must not be null
     */
    public <T> void remove(Fact<T> fact) {
        Objects.requireNonNull(fact, "fact must not be null");
        facts.remove(fact);
    }
    /**
     * Get the value of a fact by its name. This is a convenience method provided
     * as a short version of {@code getFact(factName).getValue()}.
     *
     * @param factName name of the fact, must not be null
     * @param <T> type of the fact's value
     * @return the value of the fact having the given name, or null if there is
     * no fact with the given name
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String factName) {
        Objects.requireNonNull(factName, "fact name must not be null");
        Fact<?> fact = getFact(factName);
        if (fact != null) {
            return (T) fact.getValue();
        }
        return null;
    }
    
    /**
     * Get a fact by name.
     *
     * @param factName name of the fact, must not be null
     * @return the fact having the given name, or null if there is no fact with the given name
     */
    public Fact<?> getFact(String factName) {
        Objects.requireNonNull(factName, "fact name must not be null");
        return facts.stream()
                .filter(fact -> fact.getName().equals(factName))
                .findFirst()
                .orElse(null);
    }
    /**
     * Return a copy of the facts as a map. It is not intended to manipulate
     * facts outside of the rules engine (aka other than manipulating them through rules).
     *
     * @return a copy of the current facts as a {@link HashMap}
     */
    public Map<String, Object> asMap() {
        Map<String, Object> map = new HashMap<>();
        for (Fact<?> fact : facts) {
            map.put(fact.getName(), fact.getValue());
        }
        return map;
    }
    /**
     * Return an iterator on the set of facts. It is not intended to remove
     * facts using this iterator outside of the rules engine (aka other than doing it through rules)
     * 
     * @return an iterator on the set of facts
     */
    @Override
    public Iterator<Fact<?>> iterator() {
        return facts.iterator();
    }
    /**
     * Clear facts.
     */
    public void clear() {
        facts.clear();
    }
    @Override
    public String toString() {
        Iterator<Fact<?>> iterator = facts.iterator();
        StringBuilder stringBuilder = new StringBuilder("[");
        while (iterator.hasNext()) {
            stringBuilder.append(iterator.next().toString());
            if (iterator.hasNext()) {
                stringBuilder.append(",");
            }
        }
        stringBuilder.append("]");
        return stringBuilder.toString();
    }
}

当看到Facts的源码时,可以发现它与线程池的Executors组件相似。事实上,Facts可以被看作是一个类似工厂方法的组件,它帮助我们维护内部的Fact集合,并提供了对这些Fact数据集合进行增加、删除、更新和查询(CRUD操作)的能力。不仅如此,Facts还能提供其他辅助方法来处理这些内部数据集合。通过使用Facts数据模型,我们能够更加高效地管理和操作数据集合。


【底层服务/编程功底系列】「手把手教学系列」带你打造一个属于自己的规则引擎服务,打破任何业务难题(逻辑模型和API设计)(二)https://developer.aliyun.com/article/1471069

相关文章
|
2月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
97 9
|
3月前
|
人工智能 Serverless API
一键服务化:从魔搭开源模型到OpenAI API服务
在多样化大模型的背后,OpenAI得益于在领域的先发优势,其API接口今天也成为了业界的一个事实标准。
一键服务化:从魔搭开源模型到OpenAI API服务
|
3月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
3月前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
2月前
|
IDE API 定位技术
Python--API编程:IP地址翻译成实际的物理地址
Python--API编程:IP地址翻译成实际的物理地址
|
4月前
|
API Java Python
API的神秘面纱:从零开始构建你的RESTful服务
【8月更文挑战第31天】在现代网络应用开发中,RESTful API已成为数据交互的标准。本文通过比较流行的技术栈(如Node.js、Python的Django和Flask、Java的Spring Boot)及其框架,帮助你理解构建RESTful API的关键差异,涵盖性能、可扩展性、开发效率、社区支持、安全性和维护性等方面,并提供示例代码和最佳实践,指导你选择最适合项目需求的工具,构建高效、安全且易维护的API服务。
59 0
|
16天前
|
JSON API 数据格式
淘宝 / 天猫官方商品 / 订单订单 API 接口丨商品上传接口对接步骤
要对接淘宝/天猫官方商品或订单API,需先注册淘宝开放平台账号,创建应用获取App Key和App Secret。之后,详细阅读API文档,了解接口功能及权限要求,编写认证、构建请求、发送请求和处理响应的代码。最后,在沙箱环境中测试与调试,确保API调用的正确性和稳定性。
|
28天前
|
供应链 数据挖掘 API
电商API接口介绍——sku接口概述
商品SKU(Stock Keeping Unit)接口是电商API接口中的一种,专门用于获取商品的SKU信息。SKU是库存量单位,用于区分同一商品的不同规格、颜色、尺寸等属性。通过商品SKU接口,开发者可以获取商品的SKU列表、SKU属性、库存数量等详细信息。
|
29天前
|
JSON API 数据格式
店铺所有商品列表接口json数据格式示例(API接口)
当然,以下是一个示例的JSON数据格式,用于表示一个店铺所有商品列表的API接口响应
|
2月前
|
编解码 监控 API
直播源怎么调用api接口
调用直播源的API接口涉及开通服务、添加域名、获取API密钥、调用API接口、生成推流和拉流地址、配置直播源、开始直播、监控管理及停止直播等步骤。不同云服务平台的具体操作略有差异,但整体流程简单易懂。