[rules-users] Avoid propagation of update in a then block.

Mike Melton mike.melton at gmail.com
Tue Mar 13 23:50:09 EDT 2012


I just realized that I changed my mind on implementation mid-post and
misled you a bit. You do *not* need a special implementation of Map since
you are never reasoning over it; the accumulate rule consequence decomposes
the map results into DfsSearchResult facts. So replace any references to
DfsSearchResults above with Map.

Sorry for any confusion.

Mike
On Mar 13, 2012 10:12 PM, "Mike Melton" <mike.melton at gmail.com> wrote:

> Sorry - I didn't have the time earlier to fully parse the more complex
> rule. The problem you're having is that the engine reevaluates the
> conditions on each working memory change, and since, as you noticed, the
> list has changed, the rule fires again. The no-loop attribute prevents a
> rule from reactivating itself "with the current set of facts". You do not
> have the same set of facts, and so no-loop is not applicable in your case.
>
> It looks to me like you want to insert the results of the Dfs.search()
> operation as a fact or list of facts, and then include a pattern in your
> condition that prevents the rule from firing if these results exist in
> working memory. You would then have another rule or set of rules that
> process the results, retracting them as they go. Once all the results from
> one firing of the accumulate rule have been processed and retracted, then
> the accumulate rule would be free to fire again on the next set of data.
>
> (An aside: since Dfs.search() returns a Map, you'll probably want to
> create your own implementation since a rule with a pattern on Map() would
> evaluate true for any map that happens to be in working memory. However, a
> rule that's looking for DfsSearchResults would only match in your
> particular case. Another (perhaps better) option is to use traits to have
> your Map "don" a trait that your other rules can then reason on. Traits are
> still an experiment feature but I've played with them and they are very
> cool.)
>
> Before I ramble too much further, here is a very pseudocoded version of
> what I'm talking about. I'm going to assume that Dfs.search() returns
> something called DfsSearchResults; whether that type is an implementation
> of Map or a trait is semi-irrelevant.
>
> We're also going to assume a new type called DfsSearchResult:
>
> declare DfsSearchResult
>   assignment : PlanifEventAssignment
>   employee : EmployeeValue
> end
>
> So your accumulate rule would be:
>
> rule "close-shift"
>  when
>   not DfsSearchResult( ) // Keeps this rule from activating again until
> all results of the previous firing are processed
>   $shift : Shift( )
>   $assignments : ... // this condition stays the same
>   $availables : ... // this condition stays the same too
>   $results : DfsSearchResults( size > 0 ) from Dfs.search( $assignments,
> $availables )
>  then
>   for ( DfsSearchResult dsr : $results ) { // the magic of pseudocode is
> it doesn't compile and we don't care!
>    PlanifEventAssignment assignment = ...
>    EmployeeValue employee = ...
>    insert( new DfsSearchResult( assignment, employee ) );
>   }
> end
>
> And now you'll have a processing rule:
>
> rule "update-assignment"
>  when
>   $dsr : DfsSearchResult( $a : assignment, $e : employee )
>  then
>   modify($a) { setClose(true); setEmployee($e); }
>   retract($dsr);
> end
>
>
> I think that will get you as least in the right direction. I hope this
> helps.
>
> Mike
>
> P.S. Now that I think about it, I'd like to amend the guideline I wrote in
> my last email: "No looping in the consequence unless it is to decompose a
> collection of data into simple facts that are much easier to reason over...
> or if I have another really good reason."
>
>
> 2012/3/13 Patrik Dufresne <ikus060 at gmail.com>
>
>> Hi Mike,
>>
>> I see your point, it's very valid for the snippet rule, but can't be
>> apply to the real one since I need to run a function using eval().
>>
>> Patrik Dufresne
>>
>>
>>
>> On Tue, Mar 13, 2012 at 4:45 PM, Mike Melton <mike.melton at gmail.com>wrote:
>>
>>> Let the rule engine do what it does best. You are fighting against the
>>> optimizations of the engine by trying to control the flow. You can rewrite
>>> your rule as
>>>
>>> rule "my-rule"
>>>  when
>>>   $entity : Entity( closed == false )
>>>  then
>>>   modify($entity) { setClosed(true); }
>>> end
>>>
>>> The rule will fire (once) for each Entity which matches the condition. I
>>> haven't taken the time to apply the same exercise to your more complex
>>> rule, but a general rule you should abide by is "No looping in the
>>> consequence unless I have a really good reason."
>>>
>>> Mike
>>>
>>>
>>> 2012/3/13 Patrik Dufresne <ikus060 at gmail.com>
>>>
>>>>  Hi,
>>>>
>>>> I have some trouble to figure out how to stop / start the propagation
>>>> of updates within a Then block.
>>>> Here is a snippet to represent the problem I have.
>>>>
>>>> rule "my-rule"
>>>>     when
>>>>         $objects : List()
>>>>                 from accumulate( $entity : Entity(closed==false),
>>>> collectList($entity) )
>>>>     then
>>>>         for(Object obj : $objects) {
>>>>             ((Entity) obj).setClosed(true);
>>>>             update(obj);
>>>>         }
>>>> end
>>>>
>>>> When this rule's consequence is called first, the first enity in the
>>>> list is 'update', but then update if propagated to immediately causing the
>>>> rule to be evaluated with all the entities minus the updated one. So I'm
>>>> wondering if there is a transaction like operation allowing me to update
>>>> all the entities in the list and then fire the rules.
>>>>
>>>> According to the documentation no-loop should have help me for this.
>>>>
>>>> Here is the original rules
>>>> rule "close-shift"
>>>> salience -1
>>>>  when
>>>> $shift : Shift( )
>>>> $assignments : List( size > 0 )
>>>>  from accumulate (
>>>> $assignment : PlanifEventAssignment(
>>>> close == false,
>>>>  shift == $shift ),
>>>> collectList($assignment) )
>>>> $availables : List( size >= $assignments.size )
>>>>  from accumulate ( ( and
>>>> ShiftAssignment(
>>>> shift == $shift,
>>>>  $employee : employee)
>>>> $available : EmployeeAvailable (
>>>> employee == $employee,
>>>>  assignment.shift == $shift) ),
>>>> collectList($available) )
>>>> eval( Dfs.search($assignments, $availables) != null )
>>>>  then
>>>> // Recalculate the result.
>>>> Map table = Dfs.search($assignments, $availables);
>>>>  for(Object entry : table.entrySet()) {
>>>> PlanifEventAssignment assignment =
>>>> (PlanifEventAssignment)((Entry)entry).getKey();
>>>>  EmployeeValue employee = (EmployeeValue)((Entry)entry).getValue();
>>>> assignment.setClose(true);
>>>>  assignment.setEmployee(employee);
>>>> update(assignment);
>>>> }
>>>> end
>>>>
>>>>
>>>> Patrik Dufresne
>>>>
>>>> _______________________________________________
>>>> rules-users mailing list
>>>> rules-users at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>
>>>>
>>>
>>> _______________________________________________
>>> rules-users mailing list
>>> rules-users at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>
>>>
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20120313/b70291ff/attachment.html 


More information about the rules-users mailing list