【问题标题】:Drools - How to accumulate facts that don't share a property with a fact in working memoryDrools - 如何积累与工作记忆中的事实不共享属性的事实
【发布时间】:2016-02-05 03:03:48
【问题描述】:

我想从嵌套集合中创建事实集合,其中事实不与工作内存中的另一个事实共享属性。

假设我有一个 Person 类,其中包含一组 Address 对象。我想要来自 Person John 的所有地址事实的集合,这些事实与当前工作内存中的地址事实具有相同的邮政编码。

我认为这样做的唯一方法是使用“来自累积”,但我不知道如何在源模式行中添加附加条件。当我尝试以下操作时,出现规则编译错误:

when
    p:   Person(name == "John")
    h:   HashSet(size > 0) from accumulate (addr: Address(zc: zipcode) from p.addresses /*and not Address(zipcode == zc)*/, 
                                            init(Set s = new HashSet();)
                                            action(s.add(addr);),
                                            result(s) 
                                           )    

我需要在“then”子句中一次性遍历最终集合的内容;否则我会将源模式和“非”检查从“来自累积”中移出,并完全取消“来自累积”。

有什么方法可以做到我所描述的吗?提前致谢。

【问题讨论】:

    标签: drools accumulate


    【解决方案1】:

    由于来自$person.address 的“即时”事实无法与 WM 网络中的适当事实相结合,您将不得不求助于 Java。

    when
    $person: Person(name == "John")
    $except: HashSet from collect Address()
    hashset: HashSet(size > 0)
                from accumulate (addr: Address() from $person.addresses, 
                   init(Set s = new HashSet();)
                   action( if( ! $except.contains(addr) ){
                             s.add(addr);
                           } ),
                   result(s) )
    

    如果 Person 的 Address 组件也是正确的事实,那么所有这些都不是必需的。在 DB 设计中根据 Normal Forms 的数据模型也更适合 Drools。

    编辑如果您只需要跳过具有特定邮政编码的地址,请累积该组邮政编码。

    when
    $person: Person(name == "John")
    accumulate( Address($zip: zipcode); $except: collectSet($zip) )
    hashset: HashSet(size > 0)
                from accumulate ($addr: Address( $zx: zipcode) from $person.addresses, 
                   init(Set s = new HashSet();)
                   action( if( ! $except.contains( $zx ) ){
                             s.add( $addr );
                           } ),
                   result(s) )
    

    【讨论】:

    • zipcode != $except 不将邮政编码与集合进行比较吗?您将如何获得 $except 中每个元素的邮政编码?我试过你的解决方案,我得到了[Error: incompatible types in statement: class java.util.HashSet (compared from: class java.lang.String)]。作为解释,$p.addresses 的 Address 对象实际上是 WM 中的正确事实,但它们被其他规则删除了。本质上,我想用这条规则做的是找出当前在 WM 中的事实与被删除并存储在 $p.addresses 中的事实之间的区别。
    • 糟糕,这是上次尝试的遗留问题。已编辑。
    • 修改后的解决方案不检查邮政编码,对吗?只有当地址对象本身不等于 WM 中的地址事实时,它才会将地址添加到最终的哈希集中。
    • 如果不知道数据的布局和语义,就很难做好。如果您只需要跳过某些邮政编码,则 HashSet 应该仅由邮政编码组成。请参阅编辑
    【解决方案2】:

    如果您要比较的地址在您的会话中已经是一个事实(并且您在会话中拥有其中一个或者您有唯一标识它的方法),那么您可以试试这样的:

    rule "Test"
        $p: Person(name == "John")
        $a: Address()
        $s: Set( size > 0 ) from collect (
            Address(zipcode != $a.zipcode) from $p.getAdresses()
        )
    then
        //The Set $s contains all the addresses from John having
        //a different zipcode than the Address in your working memory. 
    end
    

    希望对你有帮助,

    【讨论】:

    • 不幸的是,这对我不起作用有两个原因:1)我还想在 WM 中没有地址事实时构建集合。那么最终的集合应该只包含 $p.addresses 中的所有元素。 2) 如果我在 WM 中有多个地址事实,它们与 $p.addresses 中的地址共享一个邮政编码,但它们是不同的邮政编码(例如,01234 和 56789 都在 WM 和 $p.addresses 中),那么该规则将触发两次。我需要一次性完成最后一组。
    猜你喜欢
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多