针对 Azure 逻辑应用规则引擎执行的优化(预览版)

适用于:Azure 逻辑应用(标准)

重要

此功能为预览版,受 Azure 预览版补充使用条款约束。

Azure 逻辑应用规则引擎为规则集(可以使用 Microsoft 规则编辑器创建)提供执行上下文。 本指南介绍了规则引擎工作原理的核心概念,并提供了对操作和执行的优化建议。

核心组件

  • 规则集执行程序

    此组件实施负责规则条件求值和操作执行的算法。 默认规则集执行程序是基于对比网络的正向链接推理引擎,该引擎设计为对内存中操作进行优化。

  • 规则集转换器

    此组件将规则集对象作为输入,并生成规则集的可执行表示。 默认内存中转换器根据规则集定义创建已编译的判别网络。

  • 规则集跟踪侦听器

    此组件接收规则集执行器的输出,并将该输出转发到规则集跟踪和监视工具。

条件求值和操作执行

Azure 逻辑应用规则引擎是一种高效的推理引擎,可将规则链接到 .NET 对象或 XML 文档。 规则引擎使用三阶段算法执行规则集,包括以下阶段:

  • 匹配

    在匹配阶段,规则引擎将使用在规则条件中定义的谓词,根据使用事实类型(在规则引擎的工作内存中维护的对象引用)的谓词来匹配事实。 为了提高效率,模式匹配发生在规则集中的所有规则中,并且跨规则共享的条件仅匹配一次。 规则引擎可能会将部分条件匹配存储在工作内存中,以加快后续模式匹配操作。 模式匹配阶段的输出包含对规则引擎议程的更新。

  • 冲突解决

    在冲突解决阶段,规则引擎会检查作为执行候选的规则,以确定根据预先确定的解决方案,要运行的下一组规则操作。 规则引擎会将匹配阶段找到的所有候选规则添加到规则引擎的议程中。

    默认冲突解决方案基于规则集中的规则优先级。 优先级可以在 Microsoft Rules Composer 中配置的规则属性。 数字越大,优先级越高。 如果触发了多个规则,规则引擎将首先运行优先级较高的操作。

  • Action

    在操作阶段,规则引擎将运行已解析规则中的操作。 请注意,规则操作可以在规则引擎中添加新的事实,这将导致循环继续,也称为前向链接。

    重要

    算法永远不会优先于当前正在运行的规则。 规则引擎会在匹配阶段重复之前执行当前正在运行的规则中的所有操作。 但是,在匹配阶段再次开始之前,规则引擎议程上的其他规则将不会运行。 匹配阶段可能会导致规则引擎在运行之前从议程中删除这些规则。

示例

以下示例显示了匹配、冲突解决和操作的三阶段算法的工作原理:

规则 1:计算收入

  • 声明性表示

    只有当申请人的收入与贷款比率小于 0.2 时,才获取申请人的信用等级。

  • 使用业务对象的 IF-THEN 表示

    IF Application.Income / Property.Price < 0.2
    THEN Assert new CreditRating( Application)
    

规则 2:计算信用等级

  • 声明性表示

    只有当申请人的信用等级超过 725 时,才批准申请人。

  • 使用业务对象的 IF-THEN 表示:

    IF Application.SSN = CreditRating.SSN AND CreditRating.Value > 725
    THEN SendApprovalLetter(Application)
    

下表总结了这些事实:

Fact 说明 字段
应用程序 表示住房贷款申请的 XML 文档。 - 收入:65,000 美元
- SSN:XXX-XX-XXXX
属性 表示要购买的房产的 XML 文档。 - 价格:225,000 美元
CreditRating 包含贷款申请人信用评级的 XML 文档。 - 值:0-800
- SSN:XXX-XX-XXXX

工作内存和议程的更新

规则引擎的工作内存和议程最初为空。 应用程序添加 ApplicationProperty 事实后,规则引擎将按如下所示更新其工作内存和议程:

工作内存 议程
- Application
- Property
规则 1
  • 规则引擎将规则 1 断言到其议程中,因为条件 Application.Income / Property.Price < 0.2 在匹配阶段求值结果为 true

  • 工作内存中不存在任何 CreditRating 事实,因此不为规则 2 的条件求值。

  • 由于规则 1 是议程中的唯一规则,因此该规则将被执行,然后从议程中消失。

  • 规则 1 定义了一个可产生新事实的单一操作,该新事实是添加到工作内存中的申请人的 CreditRating 文档。

  • 执行完规则 1 之后,控件将返回到匹配阶段。

    由于要匹配的唯一新对象是 CreditRating 事实,因此匹配阶段的结果如下所示:

    工作内存 议程
    - Application
    - Property
    - CreditRating
    规则 2
  • 规则 2 现在执行,该规则将调用一个向申请人发送审批信的函数。

  • 执行完规则 2 之后,控件将返回到匹配阶段。 但是,没有更多新的事实可供匹配,并且议程为空,因此前向链接将终止,且规则集执行完成。

议程和优先级

若要了解 Azure 逻辑应用规则引擎如何为规则求值并执行操作,还必须了解议程优先级的概念。

议程

规则引擎的议程是将规则排队执行的时间表。 议程存在于引擎实例中,并作用于单个规则集,而不是一系列规则集。 当事实被断言到工作内存中,并且满足规则的条件时,引擎会将规则放在议程上并根据优先级执行该规则。 引擎按优先级从高到低的顺序执行规则的操作,然后执行议程上下一个规则的操作。

规则引擎将规则中的操作视为一个块,因此在引擎移动到下一个规则之前,所有操作都会运行。 规则块中的所有操作都会执行,而不管块中的其他操作如何。 有关断言的更多信息,请参阅使用控制函数优化规则引擎

以下示例说明议程的工作原理:

Rule 1

IF
Fact1 == 1
THEN
Action1
Action2

规则 2

IF
Fact1 > 0
THEN
Action3
Action4

当将 Fact1 事实(值为 1)断言到引擎中时,规则 1 和规则 2 的条件均已满足。 因此,引擎会将两个规则移至议程以执行其操作。

工作内存 议程
Fact 1(值 = 1) 规则 1
- Action1
- Action2

规则 2
- Action3
- Action4

优先级

默认情况下,所有规则的执行优先级都设置为 0。 但是,可以在每个单独的规则上更改此优先级。 优先级可以大于、等于或小于 0,数字越大优先级越高。 引擎按优先级从高到低的顺序执行操作。

以下示例说明优先级如何影响规则的执行顺序:

规则 1(优先级 = 0)

IF
Fact1 == 1
THEN
Discount = 10%

规则 2(优先级 = 10)

IF
Fact1 > 0
THEN
Discount = 15%

尽管两个规则的条件都满足,但由于规则 2 的优先级较高,因此将先执行规则 2。 最终折扣为 10%,这是由于规则 1 执行操作的结果,如下表所示:

工作内存 议程
Fact1(值 = 1) 规则 2
折扣:15%

规则 1
折扣:10%

操作副作用

如果执行某个操作会影响对象的状态或条件中使用的术语,则称此操作对该对象或术语有“副作用”。 这句话并不意味着操作有副作用,而是对象或术语可能受到一个或多个操作的影响。

例如,假设你具有以下规则:

Rule 1

IF OrderForm.ItemCount > 100
THEN OrderForm.Status = "Important"

规则 2

IF OrderList.IsFromMember = true
THEN OrderForm.UpdateStatus("Important")

在此示例中,OrderForm.UpdateStatusOrderForm.Status 有“副作用”,这意味着OrderForm.Status 可能受到一个或多个操作的影响。

.NET 类成员的 SideEffects 属性默认设置为 true,这可防止规则引擎缓存具有副作用的成员。 在此示例中,规则引擎不会将 OrderForm.Status 缓存在工作内存中。 相反,每次引擎为规则 1 求值时,都会获取 OrderForm.Status 的最新值。 如果 SideEffects 属性值为 false,则规则引擎会在引擎首次为 OrderForm.Status 求值时缓存该值。 但是,对于后续前向链接场景中的求值,引擎将使用缓存的值。

Microsoft 规则编辑器目前不提供修改 SideEffects 属性值的方法。 但是,可以通过业务规则框架(一个符合 Microsoft .NET 标准的类库)以编程方式设置 SideEffects 属性值。 可以在绑定时使用 ClassMemberBinding 类来设置此值,以指定规则条件和操作中使用的对象方法、属性和字段。 ClassMemberBinding 类具有一个名为 SideEffects 的属性,该属性包含一个布尔值,用于指示访问成员是否会更改其值。

性能注意事项

本节讨论 Azure 逻辑应用规则引擎在各种场景下以及使用不同配置和调整参数值时的性能。

事实类型

规则引擎访问 .NET 事实所需的时间比访问 XML 事实所需的时间短。 如果可以在规则集中选择使用 .NET 事实或 XML 事实,请考虑使用 .NET 事实,以提高性能。

规则优先级

规则的优先级设置可以大于、等于或小于 0,数字越大,优先级越高。 操作按优先级从高到低的顺序执行。 当规则集使用 AssertUpdate 调用实施前向链接行为时,可以使用 Priority 属性优化链接。

例如,假设规则 2 依赖于规则 1 设置的值。 如果规则 1 具有更高的优先级,则规则 2 仅在规则 1 触发并更新值后执行。 相反,如果规则 2 具有更高的优先级,则规则可以触发一次,然后在规则 1 触发并更新规则 2 条件中的事实后再次触发。 这种情况可能会,也可能不会生成正确的结果,但显然,与仅触发一次相比,触发两次对性能的影响更大。

有关更多信息,请参阅使用 Microsoft 规则编辑器创建规则

逻辑 OR 运算符

规则引擎经过优化,可执行逻辑 AND 运算符,并将引擎解析为析取范式的规则重构为析取范式,以便仅在顶层使用逻辑 OR 运算符

如果在条件中使用更多逻辑 OR 运算符,则会产生更多排列,从而扩展规则引擎的分析网络。 因此,规则引擎可能需要很长时间才能规范化规则。

以下列表提供了此问题的可能解决方法:

  • 将规则更改为析取范式,这样,OR 运算符将仅位于顶层。

    考虑以编程方式创建规则,因为你可能会发现在 Microsoft 规则编辑器中以析取范式构建规则可能很棘手。

  • 开发一个执行 OR 运算并返回布尔值的辅助组件,然后在规则中使用该组件。

  • 将规则拆分为多个规则,并让规则检查先前执行的规则设置的标志,或者使用先前执行的规则断言的对象,例如:

    • 规则 1IF (a == 1 OR a == 3) THEN b = true

      规则 2IF (b == true) THEN …

    • 规则 1IF (a == 1 OR a == 3) THEN Assert(new c())

      规则 2IF (c.flag == true) THEN …

Update 调用

Update 函数会更新规则引擎工作内存中存在的事实,这会导致对在条件中使用更新事实的所有规则进行重新求值。 此行为意味着 Update 函数调用可能非常昂贵,如果许多规则由于更新的事实而需要重新求值,则更是如此。 在有些情况下,可以避免重新为规则求值。

例如,考虑以下规则:

Rule 1

IF PurchaseOrder.Amount > 5
THEN StatusObj.Flag = true; Update(StatusObj)

规则 2

IF PurchaseOrder.Amount <= 5
THEN StatusObj.Flag = false; Update(StatusObj)

规则集中所有其余规则在其条件中使用 StatusObj.Flag。 对 StatusObj 对象调用 Update 函数时,所有规则都会被重新求值。 无论 Amount 字段的值是什么,除规则 1规则 2 之外的所有规则都将重新求值两次,一次是在 Update 调用之前,一次是在 Update 调用之后。

相反,可以在调用规则集之前将 Flag 值设置为 false,然后仅使用规则集中的规则 1 来设置标志。 在这种情况下,仅当 Amount 值大于 5 时,才会调用 Update 函数。 如果金额小于或等于 5,则不会调用 Update 函数。 这样,​​仅当 Amount 值大于 5 时,才会对除规则 1规则 2 之外的所有规则进行两次求值。

SideEffects 属性行为

XmlDocumentFieldBindingClassMemberBinding 类中,SideEffects 属性确定是否缓存绑定字段、成员或列的值。

XmlDocumentFieldBinding 类中,SideEffects 属性的默认值为 false。 但是,在 ClassMemberBinding 类中,SideEffects 属性的默认值为 true

因此,如果引擎在规则集中第二次或更晚访问 XML 文档中的字段,引擎将从缓存中获取该字段的值。 但是,如果引擎在规则集中第二次或之后访问 .NET 对象的成员,则引擎将从 .NET 对象中获取值,而不是从缓存中获取值。

此行为意味着,如果将 ClassMemberBinding 中的 SideEffects 属性设置为 false,则可以提高性能,因为从第二次开始,引擎将从缓存中获取成员的值。 但是,只能以编程方式设置属性值,因为 Microsoft 规则编辑器不会公开 SideEffects 属性。

Instances 和 selectivity

XmlDocumentBindingClassBinding 类各自具有以下属性,规则引擎使用它们的值来优化条件求值。 这些属性值允许引擎先在条件求值中使用尽可能少的实例,然后使用其余实例。

  • Instances:工作内存中类实例的预期数量。

    如果事先知道对象实例的数量,则可以将 Instances 属性设置为此数字以提高性能。

  • Selectivity:成功满足规则条件的类实例的百分比。

    如果事先知道满足条件的对象实例的百分比,则可以将 Selectivity 属性设置为此百分比以提高性能。

只能以编程方式设置这些属性值,因为 Microsoft 规则编辑器不会公开它们。

支持类继承

继承是指无需重写原始类,即可使用现有类的所有功能并扩展这些功能的能力,这是面向对象的编程 (OOP) 语言中的一项关键功能。

Azure 逻辑应用规则引擎支持以下类型的类继承:

  • 实施继承:无需其他编码即可使用基类的属性和方法的能力。

  • 接口继承:仅使用属性名称和方法名称的能力,但子类必须提供实施。

使用规则引擎,可以根据通用基类编写规则,但断言到规则引擎中的对象可以来自派生类。

以下示例具有一个名为 Employee 的基类,同时派生类名为 RegularEmployeeContractEmployee

class Employee
{
    public string Status()
    {
        // member definition
    }
    public string TimeInMonths()
    {
        // member definition
    }
}

class ContractEmployee : Employee
{
   // class definition
}
class RegularEmployee : Employee
{
   // class definition
}

对于此示例,假设你具有以下规则:

规则 1

IF Employee.TimeInMonths < 12
THEN Employee.Status = "New"

At run time, if you assert two objects, a **ContractEmployee** instance and a **RegularEmployee** instance, the engine evaluates both objects against the Rule 1.

You can also assert derived class objects in actions by using an **Assert** function. This function causes the engine to reevaluate rules that contain the derived object and the base type in their conditions as shown in the following example, which demonstrates implementation inheritance:

**Rule 2**

```text
IF Employee.Status = "Contract"
THEN Employee.Bonus = false
Assert(new ContractEmployee())

断言后,引擎会重新为其条件中包含 Employee 类型或 ContractEmployee 类型的所有规则求值。 即使仅断言派生类,但如果规则是使用基类而不是派生类中的方法来编写的,那么也会断言基类。