在 Drools 中,memberOf / contains 是否需要将测试对象作为事实明确插入?

In Drools, does memberOf / contains require the tested object to be inserted as fact explicitly?

我仍在努力思考流口水的一些基础知识。 我不明白的一件事是我必须在什么级别上明确地将事实添加到会话中,而不是将某事声明为事实或(它有什么不同?)作为规则中的变量。

问题:我是否总是必须显式添加事实,或者 drools 是否也以某种方式将声明的变量视为事实?

假设我有这个简化的层次结构:

public class Container {
    private Collection<Element> elements;
    // other stuff
}

public class Element {
    private SubElement subElement;
    // other stuff  
}

public class SubElement {
    private code;
    // other stuff
}

现在我想要 find/match 一个容器,其中包含具有给定代码的子元素的元素。 这是我创建的规则:

global Collection qualifyingCodes;
rule "container rule"
when
    // find a container 
    $container : Container( $elements : elements )

    // where there is an element within its elements list
    $element : Element(this memberOf $elements)

    // that has a sub element
    $subElement : SubElement(this == $element.subElement)

    // for which the code is in the (global) list of codes
    eval(qualifyingCodes.contains($subElement.code)) 
then
    ....

现在它似乎工作正常,但前提是我将容器、元素和子元素作为事实分别添加到我的会话中。 我希望能够将容器对象作为事实添加,并且由于 "declared" $elements/$element/$subElement drools 也会将这些理解为事实。 有没有办法做到这一点(或者我总是必须展平我的数据结构并将它们添加为单独的事实)?

感谢任何建议!

作为事实插入的 POJO 可以与模式匹配,而无需建立上下文(正如您的规则很好地说明的那样)。

但是,可以创建一个上下文,其中一组有限的 POJO(可能已作为事实插入或未作为事实插入)可以通过模式匹配:通过 from 短语。这基本上是相同的规则,但 Element 和 SubElement 不是事实:

rule "from rule"
when
  // find a container 
  $container : Container( $elements : elements )

  // where there is an element within its elements list
  $element : Element($subEl: subElement ) from $elements

  // that has a sub element
  $subElement : SubElement(this == $element.subElement, data == "DEF")
                from $subEl;
then
    System.out.println( "found Container " + $container +
                        " for " + $subElement.getData());
end

但是,除了在一般上下文中可见之外,作为事实的插入还有另一个结果:可以在引擎意识到该修改的情况下修改事实。在 "from rule" 中,不可能修改 $subElement,因此任何将 SubElement 的数据设置为 "DEF" 的修改都不会触发此规则(即使插入 SubElement POJO 也不会)。 =13=]

为了完整起见:通过添加对父对象的引用也简化了对象层次结构(组合)的推理,例如

rule "linkage rule"
when
    // a sub element GHI
    $subElement : SubElement( data == "GHI", $element: element)
then
    System.out.println( "found Container " + $element.getContainer() +
                        " for " + $subElement.getData());
end