【问题标题】:Drools 7 - Reasoning over events associated with inferred factsDrools 7 - 推理与推断事实相关的事件
【发布时间】:2018-11-08 17:58:00
【问题描述】:

我们正在开发一个资源预订系统,我们将在该系统中接收任意时间(从 5 分钟到 2 小时不等)预订资源的请求。没有预定义的插槽。

我们尝试使用 Drools (Fusion) 版本。 7.12.0.Final,编写规则以确保新的预订请求不会覆盖已确认的现有请求。

为了实现上述目的,我们创建了以下 2 个对象:

declare ReservationRequest
    @role ( event )
    @duration (reservationDuration )
    @timestamp ( pickupTime )

    id                  : int
    pickupTime          : Date
    reservationDuration : long   
    reserved            : String
    deliveryEnd     : Date
end

declare Reservation
    reservation             : ReservationRequest
end

“ReservationRequest”被视为事件,因此我们可以使用时间运算符来评估新请求不会与已确认的请求重叠(捕获为推断的“Reservation”事实。

我们编写了以下规则来检查重叠并插入相应的“预订”事实:

rule "Ensure no overlaped reservations using inferred facts"
    enabled true

    when
        reservationRequest : ReservationRequest( )
        not Reservation ( reservation == reservationRequest )
        reservations : Reservation() 
        not ReservationRequest( this overlaps reservations.reservation )
        not ReservationRequest( this overlappedby reservations.reservation  )
        not ReservationRequest( this includes reservations.reservation  )
    then
        insert( new Reservation ( reservationRequest ) );
 end

很遗憾,如果 WM 中存在“预订”事实,上述规则将无法运行。我收到以下错误:

  java.lang.RuntimeException: Conversion to long not supported from com.sample.ReservationRequest
    at org.drools.core.base.extractors.BaseObjectClassFieldReader.getLongValue(BaseObjectClassFieldReader.java:133)
    at org.drools.core.base.ClassFieldReader.getLongValue(ClassFieldReader.java:198)
    at org.drools.core.rule.VariableRestriction$TemporalVariableContextEntry.updateFromTuple(VariableRestriction.java:641)
    at org.drools.core.common.SingleBetaConstraints.updateFromTuple(SingleBetaConstraints.java:116)
    at org.drools.core.phreak.PhreakNotNode.doLeftInserts(PhreakNotNode.java:108)
    at org.drools.core.phreak.PhreakNotNode.doNode(PhreakNotNode.java:85)
    at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:571)
    at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:552)
    at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(RuleNetworkEvaluator.java:379)
    at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:339)
    at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:175)
    at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:133)
    at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:212)
    at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:87)
    at org.drools.core.concurrent.AbstractRuleEvaluator.internalEvaluateAndFire(AbstractRuleEvaluator.java:34)
    at org.drools.core.concurrent.SequentialRuleEvaluator.evaluateAndFire(SequentialRuleEvaluator.java:43)
    at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:1067)
    at org.drools.core.common.DefaultAgenda.internalFireAllRules(DefaultAgenda.java:1014)
    at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1006)
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1337)
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1328)
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1312)
    at com.sample.DroolsTest.main(DroolsTest.java:24)

我们在其他场景中广泛使用了推断事实,但这是我们第一次将它用于事件。所以我们不确定是否支持这种能力(根据相关事件推断事实)。

如果这不受支持,那么在允许从 WM 中逐出/收回其他事件的同时“保存”所需事件的最佳方法是什么。我们可以使用“标志”来标记我们想要保留的事件,但我们希望尽可能避免这种方法。

谢谢

【问题讨论】:

    标签: drools fusion


    【解决方案1】:

    我是 Drools 的粉丝,为什么不直接创建一个 SQL 表,其中包含 start_datetime 和 end_datetime 以及“插入前”触发器,该触发器检查插入的值是否与任何现有(已确认)值重叠在数据库中。如果触发器在插入过程中抛出异常,那么您捕获它并且您知道存在重叠。

    【讨论】:

    • 如果我们的要求这么简单,我会这样做的。但是在我们确认预订之前,我们必须对新的预订请求进行额外的推理。在未来,我们还必须推理哪个资源最适合预订请求,然后将资源时间分配给这个请求——因为我们正在寻求实施 optaplanner。这就是为什么我们试图看看我们是否可以从一开始就利用 Drools,以便我们以后可以将这种推理逻辑整合到我们的求解器中。
    • 清除。我现在添加了一个单独的答案。
    【解决方案2】:

    我建议在变量名前添加 $-sign,这样可以更好地区分字段和变量。

    如果您将方法 boolean isOverlap(ReservationRequest) 添加到 ReservationRequest 类中,那么您可以编写如下内容:

    when
        $reservationRequest : ReservationRequest( )
        not Reservation ( this.reservation.isOverlap($reservationRequest) )
    then
        insert( new Reservation ( $reservationRequest ) );
    

    这应该足够了。我还强烈建议您现在在引用 ReservationRequest 时使用变量名“reservationRequest”,这非常令人困惑。

    【讨论】:

    • 感谢 Drools 大师的回答。不过,我确实需要澄清一下 - 这个 Reservation 的定义是否没有添加“reservation”字段:declare Reservation reservation : ReservationRequest end
    • 糟糕。确实如此。拥有两个类 - Reservation 和 ReservationRequest 然后使用字段名称“reservation”来引用 ReservationRequest 类型的对象是一个糟糕的主意。这让我很困惑。我编辑了我的回复来解决这个问题。
    猜你喜欢
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    相关资源
    最近更新 更多