1. 概述

本文将介绍什么是反向链接(Backward Chaining)以及如何在Drools中使用它。这是Drools业务规则引擎系列文章的一部分。

2. Maven依赖

首先添加drools-core依赖:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>9.44.0.Final</version>
</dependency>

3. 正向链接

正向链接(Forward Chaining)从数据出发,通过分析数据逐步推导出结论。典型场景是:通过检查已知节点连接来发现新路线。

4. 反向链接

与正向链接相反,反向链接直接从结论(假设)开始,通过回溯一系列事实来验证其有效性

两种链接方式的本质区别:

  • ✅ 正向链接:数据驱动(输入是数据)
  • ⚠️ 反向链接:目标驱动(输入是目标)

典型场景:验证两个节点之间是否存在连接路线。

5. Drools中的反向链接

Drools最初是作为正向链接系统设计的,但从5.2.0版本开始支持反向链接。我们通过一个简单示例来验证假设:长城是否属于地球

5.1 数据准备

构建简单的事实库,描述事物及其位置关系:

  1. 地球
  2. 亚洲,地球
  3. 中国,亚洲
  4. 长城,中国

5.2 规则定义

/resources/com/baeldung/drools/rules/目录下创建BackwardChaining.drl文件,包含核心查询和规则:

query belongsTo(String x, String y)
    Fact(x, y;)
    or
    (Fact(z, y;) and belongsTo(x, z;))
end

添加两个辅助规则用于结果验证:

rule "Great Wall of China BELONGS TO Planet Earth"
when
    belongsTo("Great Wall of China", "Planet Earth";)
then
    result.setValue("Decision one taken: Great Wall of China BELONGS TO Planet Earth");
end

rule "print all facts"
when
    belongsTo(element, place;)
then
    result.addFact(element + " IS ELEMENT OF " + place);
end

5.3 应用实现

创建Java类表示事实:

public class Fact {
 
    @Position(0)
    private String element;

    @Position(1)
    private String place;

    // getters, setters, constructors, and other methods ...    
}

使用@Position注解指定属性值的传递顺序。再创建结果POJO:

public class Result {
    private String value;
    private List<String> facts = new ArrayList<>();
 
    //... getters, setters, constructors, and other methods
}

最后执行测试:

public class BackwardChainingTest {

    @Before
    public void before() {
        result = new Result();
        ksession = new DroolsBeanFactory().getKieSession();
    }

    @Test
    public void whenWallOfChinaIsGiven_ThenItBelongsToPlanetEarth() {

        ksession.setGlobal("result", result);
        ksession.insert(new Fact("Asia", "Planet Earth"));
        ksession.insert(new Fact("China", "Asia"));
        ksession.insert(new Fact("Great Wall of China", "China"));

        ksession.fireAllRules();
        
        assertEquals(
          result.getValue(),
          "Decision one taken: Great Wall of China BELONGS TO Planet Earth");
    }
}

执行流程:

  1. 注入事实(亚洲属于地球、中国属于亚洲、长城属于中国)
  2. 通过BackwardChaining.drl中的递归查询belongsTo(String x, String y)处理事实
  3. 使用反向链接验证假设("长城属于地球")的真伪

6. 总结

本文展示了Drools的反向链接功能,通过检索事实列表来验证决策的有效性。完整示例可在GitHub仓库中找到。


原始标题:An Example of Backward Chaining in Drools