【底层服务/编程功底系列】「手把手教学系列」带你打造一个属于自己的规则引擎服务,打破任何业务难题(逻辑模型和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

相关文章
|
10月前
|
人工智能 算法 API
国产化用于单导联和六导联的心电算法及API服务
随着智能设备普及,心电图功能逐渐应用于智能手表、体脂仪等设备。苏州唯理推出单导联及6导联心电算法API服务,由AI驱动,1分钟内快速评估心律失常、房颤、早搏等问题,已广泛用于医疗设备及三甲医院。其算法还可评估压力、疲劳、情绪状态,筛查效率远超进口设备。唯理率先实现国产医疗级心电芯片,支持快速集成与私有化部署,适用于多种智能硬件。
|
11月前
|
JSON 安全 Java
API 一键转换 MCP 服务!Higress 助今日投资快速上线 MCP 市场
今日投资的技术负责人介绍了如何通过Higress MCP 市场完善的解决方案,快捷地将丰富的金融数据 API 转化为 MCP 工具,帮助用户通过 MCP 的方式非常轻松地调用专业金融数据,自由快速地构建自己的金融大模型应用。
1320 23
|
人工智能 自然语言处理 API
硅基流动入驻阿里云云市场,核心API服务将全面接入阿里云百炼平台💐
2025年6月18日,AI Infra企业硅基流动与阿里云达成战略合作,加入“繁花计划”并入驻云市场。其大模型推理平台SiliconCloud核心API将接入阿里云百炼平台,依托灵骏智能计算集群为客户提供高效服务。作为国内领先的MaaS平台,SiliconCloud已集成百余款开源大模型,服务600万用户及众多企业。双方将在算力协同、行业解决方案等领域深化合作,推动AI生态发展。
1443 0
|
人工智能 API 开发工具
GitHub官方开源MCP服务!GitHub MCP Server:无缝集成GitHub API,实现Git流程完全自动化
GitHub MCP Server是基于Model Context Protocol的服务器工具,提供与GitHub API的无缝集成,支持自动化处理问题、Pull Request和仓库管理等功能。
3381 2
GitHub官方开源MCP服务!GitHub MCP Server:无缝集成GitHub API,实现Git流程完全自动化
|
人工智能 算法 安全
OpenRouter 推出百万 token 上下文 AI 模型!Quasar Alpha:提供完全免费的 API 服务,同时支持联网搜索和多模态交互
Quasar Alpha 是 OpenRouter 推出的预发布 AI 模型,具备百万级 token 上下文处理能力,在代码生成、指令遵循和低延迟响应方面表现卓越,同时支持联网搜索和多模态交互。
1077 1
OpenRouter 推出百万 token 上下文 AI 模型!Quasar Alpha:提供完全免费的 API 服务,同时支持联网搜索和多模态交互
|
人工智能 缓存 程序员
大模型文生图服务API设计原来如此简单(1)
文生图大模型的API设计其实很简单!无论是Midjourney这样的商业产品,还是ComfyUI这样的开源工具,它们的核心API设计都遵循着相似的简单原则。
620 1
|
机器学习/深度学习 设计模式 API
Python 高级编程与实战:构建 RESTful API
本文深入探讨了使用 Python 构建 RESTful API 的方法,涵盖 Flask、Django REST Framework 和 FastAPI 三个主流框架。通过实战项目示例,详细讲解了如何处理 GET、POST 请求,并返回相应数据。学习这些技术将帮助你掌握构建高效、可靠的 Web API。
|
JSON 物联网 API
阿里云API芝士堂[物模型管理][模型]
将近一年没有关注阿里云物联网的api,最近看了下官网的文档,api列表中赫然多出了物模型的管理和使用两大类.这也难怪,物模型被誉为物联网世界的原子. 通过物模型可以有效的使用属性,服务和事件就可以表示出纷繁复杂和多姿多彩的物联网世界中的各种类型的设备;目前物模型并没有统一的规范,所以阿里,小米, 京东和中移动等大厂,都是各自制定一套自己的规范;阿里云这面主要是在自家的ICA联盟定义了一套物模型的规范.本文也从实践角度分享一下物模型相关api的使用.
702 0
|
8月前
|
人工智能 自然语言处理 测试技术
Apipost智能搜索:只需用业务语言描述需求,就能精准定位目标接口,API 搜索的下一代形态!
在大型项目中,API 数量庞大、命名不一,导致“找接口”耗时费力。传统工具依赖关键词搜索,难以应对语义模糊或命名不规范的场景。Apipost AI 智能搜索功能,支持自然语言查询,如“和用户登录有关的接口”,系统可理解语义并精准匹配目标接口。无论是新人上手、模糊查找还是批量定位,都能大幅提升检索效率,降低协作成本。从关键词到语义理解,智能搜索让开发者少花时间找接口,多专注核心开发,真正实现高效协作。
|
8月前
|
缓存 监控 前端开发
顺企网 API 开发实战:搜索 / 详情接口从 0 到 1 落地(附 Elasticsearch 优化 + 错误速查)
企业API开发常陷参数、缓存、错误处理三大坑?本指南拆解顺企网双接口全流程,涵盖搜索优化、签名验证、限流应对,附可复用代码与错误速查表,助你2小时高效搞定开发,提升响应速度与稳定性。