I need to write a rule in Drools 6.5 that checks for the existence of an event of type A. There is a second class named B which has a field date.
While checking for existence of an event A, if at least one event of type B exists, A must happen after the latest B.date in order for the rule to fire; otherwise the rule should fire regardless of any B events.
Both event types of A and B have their own explicit timestamp field.
when
// TODO if at least one event of type B exists, A must happen after max(b.date). Otherwise, the rule must fire regardless of any B
$a : A( ... )
then
...
How do I perform this check?
EDIT: If no B is present in the working memory, and A meets the requirements, the rule must fire regardless.
This will fire for each A meeting the temporal constraint that it should happen after all Bs.
$b: B()
not B(this after $b)
$a : A( this after $b )
If you want to fire this only once, for any number of As, use exists in front of A and omit the binding.
Related
Drools version: 6.5.0
A rule flow sequence which takes (Start -> A -> B -> End) route, the expectation is all the rules in A (RuleflowGroup: A) will be executed first before all the rules in B (RuleflowGroup: B). But the result it produces from the implementation of the AgendaEventListener methods (i.e., beforeMatchFired, afterMatchFired) follows the reverse order. Rules associated with B are executed first before rules associated with A.
Any explanation would be very helpful.
Please find the rule flow diagram below.
If it is the same with version 7.x that i am currently using, it is because is a bit more complicated than you think. It is not just a flow. (A->B->C), is a stack.
So it is A then B/A then C/B/A. And when C finishes executing is returning back to B/A and then A.
If you want to get rid of that you can add a rule at last level, with lowest priority and
eval (true) in the when part and halt() in the then part to end the session before it returns to previous ruleflow group.
The users on my site follow these actions:
Send requests of Type A arbitrarily (meaning, I am satisfied with using something like between(1.0,5.0)
Send requests of Type B exactly every second (but must follow Type A)
Send requests of Type C exactly every second (but must follow Type B)
Send requests of Type D arbitrarily (but must follow Type C).
My idea was:
Create a TaskSet for each request type (so that types B and C will have wait_time = between(1.0,1.0))
Use self.interrupt() in each request type once the request sets are exhausted.
However, how do I establish order (for example, B must happen only after A has finished)?
class WebsiteUser(HttpLocust):
task_set = [TypeA, TypeB, TypeC] #current idea, but this doesn't guarantee order between A,B,C.
wait_time = between(1.0, 1.0)
Is it true that rule B should be triggered before A? Because it doesn't work for me.
rule A
salience 0
timer(int: 20s)
when
...
rule B
salience 1
timer(int: 20s)
when
...
Edit:
Conditions of the two are equal, as thus both are supposed to be triggered on the same event and condition was omitted for clearness. The point is that I would like to trigger rules after 20s timeout and make them ordinal is that possible?.
Rules with a timer are scheduled for execution as soon as the condition evaluates to true. You haven't shown the conditions for A and B, so further analysis isn't possible. It is very likely that the two timers aren't started at the very same point in time, so the expiry times can be ordered A < B. If you need B before A, run the timer for B. Add a conditional element for letting A fire without a timer and let the consequence of B insert a fact to
meet this conditional element. Roughly:
rule B
timer(int: 20s)
when...
then
insert( new TriggerForA() )
end
rule A
when
$t: TriggerForA()
...
then
delete( $t );
end
Can i only have one agenda-group declaration for the same rule in Drools 6?
Can I put this?
rule "rule_x"
agenda-group "group_x"
agenda-group "group_y"
when
then
end
I want to active a this rule when several groups are focused.
Most rule attributes are just syntactic sugar, and agenda-group is one of them. It's easy to achieve the same effect by falling back to logic patterns.
Define
class Group { private String name; ... }
and use one instance of it as a fact to represent the currently active group. Rules will have to show an additional pattern:
rule in-group-one
when
Group( name == "one" )
...
If the rule to be in several groups at the same time:
rule in-groups-one-two
when
Group( name in ("one", "two") )
You can also mimic the behaviour of agenda group stacking.
Later
The idea of focussing more than one group at the same time should be considered very carefully. While it is clear that a rule in groups a, b and c should fire when these three groups are in focus, it isn't clear at all what should happen with a rule in groups a and b, or with another rule in groups a, c and d. Whatever should happe can indeed be expressed in logic, but does it make sense, and (more importantly) is it useful?
The most basic use of from clause is not working, even when I know there are elements in the list and there is no conditions for the elements being extracted from that list, and I have other rules working properly.
Here is what happens, there are many variables in my problem, but I have simplified to this:
Having this two rules, the firstone is made to demostrate that fixedShipmentValueData list, has at least one element. However, the second rule isn't fired, even when the only different thing it does from the firstone, is to use the from clause and put a variable name.
rule "Print list value"
ruleflow-group "fixed-values"
no-loop
when
cParams: CustomerParameters(list: fixedShipmentValueData)
then
System.out.format("There are %s elements at fixedShipmentValue and fixed value is %s%n",list.size(),
((ParameterValues)list.get(0)).getFixedShipmentValue());
end
rule "Do something with the list"
ruleflow-group "fixed-values"
no-loop
when
cParams: CustomerParameters(list: fixedShipmentValueData)
ParameterValues($fixedShipmentValue: fixedShipmentValue) from list
then
System.out.format("fixed Shipment Value is %s%n", $fixedShipmentValue);
end
This looks so simple... I have expent enough time as to be out of ideas.
Without seeing the Java code for CustomerParameters, ParameterValues and the application part that creates, composes and inserts the fact(s) there's just one scenario I know that can reproduce the effect as you have told it. Consider this:
A List<Base> is field list in class X. There are subclasses SubA and SubB both extending Base. Create X, add objects of class SubA to list. A rule (like "Print list value") will show that the list is not empty.
However, a rule using a pattern such as
X( $list: list )
SubB() from $list
will never fire, since there are no SubB's in Base.list.