Слюни 7 - Рассуждения о событиях, связанных с предполагаемыми фактами

Мы работаем над системой резервирования ресурсов, где мы будем получать запросы на резервирование ресурса на любое произвольное время (от 5 минут до 2 часов). Предустановленных слотов нет.

Мы пытаемся использовать Drools (Fusion) ver. 7.12.0.Наконец, написать правила, которые гарантируют, что новые запросы на бронирование не переопределяют существующие запросы, которые были подтверждены.

Для достижения вышеизложенного мы создали следующие 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. Мы могли бы использовать «флаги», чтобы отметить события, которые мы хотим сохранить, но мы хотели бы избежать этого подхода, если это возможно.

Спасибо


person groove    schedule 08.11.2018    source источник


Ответы (2)


Как бы я ни был фанатом Drools, почему бы вам просто не создать таблицу SQL с start_datetime и end_datetime вместе с триггером «перед вставкой», который проверяет, что вставленное значение не перекрывается ни с одним из существующих (подтвержденных) значений в БД. Если триггер генерирует исключение во время вставки, вы его перехватываете и знаете, что существует перекрытие.

person Master Drools    schedule 09.11.2018
comment
Если бы наше требование было таким простым, я бы так и сделал. Но мы должны сделать дополнительное обоснование новых запросов на бронирование, прежде чем мы сможем подтвердить бронирование. В будущем нам также придется подумать о том, какой ресурс лучше всего подходит для запроса на резервирование, а затем выделить время этих ресурсов для этого запроса — для этого мы ищем реализацию optaplanner. Вот почему мы пытаемся понять, сможем ли мы использовать Drools с самого начала, чтобы позже включить эту логику рассуждений в наш решатель. - person groove; 09.11.2018
comment
Чистый. Я добавил отдельный ответ сейчас. - person Master Drools; 12.11.2018

Я рекомендую добавлять знак $ перед именами переменных, чтобы вы могли лучше различать поля и переменные.

Если вы добавите метод boolean isOverlap(ReservationRequest) в класс ReservationRequest, вы можете написать что-то вроде этого:

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

Этого должно быть достаточно. Я также настоятельно рекомендую использовать имя переменной «reservationRequest», когда вы ссылаетесь на ReservationRequest прямо сейчас, это очень сбивает с толку.

person Master Drools    schedule 12.11.2018
comment
Спасибо за ваш ответ Мастер Друлс. Однако мне нужно одно уточнение: не добавляет ли это определение резервирования поле «резервирование» :declare Резервирование резервирования: ReservationRequest end - person groove; 12.11.2018
comment
Упс. Оно делает. Это ужасная идея иметь два класса — Reservation и ReservationRequest, а затем использовать резервирование имени поля для ссылки на объект типа ReservationRequest. Это меня смутило. Я отредактировал свой ответ, чтобы исправить это. - person Master Drools; 13.11.2018