Problem with temporal operations spanning daylight to standard time
by lhorton
Most of the USA went from Standard Time to Daylight Time this past weekend.
We use some of the temporal operations in our rules, mainly to do
calculations of date differences by whole days, and some of the calculations
are wrong. The ones in error involve comparing dates where one is standard
time and one is daylight savings time. I wrote a small test case to prove
this.
I have a simple Person class:
public class Person {
private Date birthdate;
private int status;
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
and a simple drl file:
package com.drools.resources;
import com.drools.person.Person;
import java.util.Date;
import java.util.Calendar;
global Long now
rule "Birthday Rule"
dialect "mvel"
when
$person : Person(birthdate != null)
Date($bDate : time before[3d] now) from $person.birthdate
then
$person.setStatus(3);
end
rule "Debug Birthday Rule"
dialect "mvel"
when
$person : Person(birthdate != null)
then
System.out.println("now is " + new Date(now));
System.out.println("birthdate is " + $person.getBirthdate());
end
and two tests:
@Test
public void testTemporalJanuary() throws Exception {
KnowledgeBase base =
createKnowledgeBaseFromRulesFile("src/com/drools/resources/temporal.drl");
StatelessKnowledgeSession kSession =
createStatelessKnowledgeSession(base);
// test january - both dates are standard time
Date now = new Date(2012-1900, 00, 13);
kSession.getGlobals().set("now", now.getTime());
Person p = new Person();
p.setStatus(0);
p.setBirthdate(new Date(2012-1900, 00, 10));
kSession.execute(p);
assertTrue(p.getStatus() == 3);
}
@Test
public void testTemporalMarch() throws Exception {
KnowledgeBase base =
createKnowledgeBaseFromRulesFile("src/com/drools/resources/temporal.drl");
StatelessKnowledgeSession kSession =
createStatelessKnowledgeSession(base);
// test March: one day standard, the other is daylight
Date now = new Date(2012-1900, 02, 13);
kSession.getGlobals().set("now", now.getTime());
Person p = new Person();
p.setStatus(0);
p.setBirthdate(new Date(2012-1900, 02, 10));
kSession.execute(p);
assertTrue(p.getStatus() == 3);
}
the first test (testTemporalJanuary) compares January 13 to January 10, and
it passes (matches the before[3d] condition).
the second test (testTemporalMarch, which is the same except for using March
instead of January) fails.
The output of the debug rule for these tests is:
now is Fri Jan 13 00:00:00 PST 2012
birthdate is Tue Jan 10 00:00:00 PST 2012
now is Tue Mar 13 00:00:00 PDT 2012
birthdate is Sat Mar 10 00:00:00 PST 2012
--
View this message in context: http://drools.46999.n3.nabble.com/Problem-with-temporal-operations-spanni...
Sent from the Drools: User forum mailing list archive at Nabble.com.
14 years, 3 months
Avoid propagation of update in a then block.
by Patrik Dufresne
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
14 years, 3 months
[Drools Planner] Hard constraint appears to be ignored
by Reinis
Hello, it appears that hard constraint I have defined is being ignored
in some rare cases. Here's an example:
This is what my application logs after getting best solution after
solver has returned from solve():
2012-02-23 21:28:54,595 [main] INFO Project Project1 assignment
563:[2012-02-27T13:00:00.000/2012-02-27T17:00:00.000] was assigned to John
2012-02-23 21:28:54,597 [main] INFO Project Project2 assignment
508:[2012-02-27T13:00:00.000/2012-02-27T17:00:00.000] was assigned to John
(The log says that John was assigned twice in same time period to two
different assignments (assignment 563 and assignment 508)
Here short explanation of the relevant domain data
assignment.id = 563
assignment.interval = 2012-02-27T13:00:00.000/2012-02-27T17:00:00.000
assignment.project = Project1
assignment.resource = John
And this is rule that, to my opinion should've prohibited that two
assignments get assigned to the same resource:
rule "only one assignment within interval for the same resource"
when
$leftAssignment : Assignment($leftId : id, $interval :
interval, resource != null, $resource : resource)
$rightAssignment : Assignment(interval == $interval, resource
== $resource, id != $leftId)
then
insertLogical(new IntConstraintOccurrence("only one assignment
within interval for the same resource", ConstraintType.NEGATIVE_HARD, 1,
$leftAssignment, $rightAssignment));
end
The score looks like this:
2012-02-23 21:28:54,594 [main] DEBUG The hard score is: 0 and the soft
score is: -532
So no hard constraints are broken according to planner.
My question is not what is wrong with this particular example (unless it
is obvious for you), but if you can think of any anti-pattern that would
cause this behavior?
What I already checked is:
- this happens really sporadically (most of the time the result is
CORRECT but in 1 from 5 runs I get this kind of error);
- I checked, re-checked and re-re-checked all the hashCode, compareTo,
solutionHashCode, solutionCompare, clone, ... methods - they appear to
be correct;
- moves are simple and I tried to keep them consistent with the way
moves in drools-planner examples are constructed;
Would be great if you could give me a hint to what direction I should
look next.
br
Reinis
14 years, 3 months
logicalInsert and construction of an inferred fact.
by devan.vanreenen@gmail.com
Hi there,
Kindly assist.
I am playing around with Inference and Truth maintenance
I have 2 questions.
1) When doing a logicalInsert() in the consequence of a rule - is this the
same as doing a insertLogical()? The reason I ask is that when creating rule
in Guvnor it doesnt recognize logicalInsert() but recognizes
insertLogical()?
2) Is there a way for Guvnor to create the inferred fact (dynamically) or
must I create the inferred fact seperately and place in a jar and upload the
the POJO model jar to Guvnor before the inferred fact can be logically
inserted?
Any help would be much appreciated.
Thanks
Devan
--
View this message in context: http://drools.46999.n3.nabble.com/logicalInsert-and-construction-of-an-in...
Sent from the Drools: User forum mailing list archive at Nabble.com.
14 years, 3 months
NPE in FireAllRulesCommand (bug?)
by Mike Melton
Drools 5.3.1.Final.
I have a use case where I am executing a BatchExecutionCommand against a
stateless session. One of the sub-commands is a FireAllRulesCommand, from
which I would like to retrieve the number of rules actually fired. Since
there is no factory or constructor method to configure both a maximum rules
to fire and an out identifier, I have to use code like this to set up
my FireAllRulesCommand:
FireAllRulesCommand farc = (FireAllRulesCommand)
CommandFactory.newFireAllRules(maxRulesToFire);
farc.setOutIdentifier("num-rules-fired");
commands.add(farc); // commands is List<Command<?>> which I later use to
construct a BatchExecutionCommand
At runtime, when I execute the BatchExecutionCommand, I get an NPE
at FireAllRulesCommand:110. After some investigating, I determined that the
value returned from (ExecutionResultImpl) ((KnowledgeCommandContext)
context).getExecutionResults() is null, which causes the NPE.
As far as I can tell, the cause of this breaks down like so:
- StatelessKnowledgeSession.execute() fires with the batch command as input.
- It constructs a KnowledgeCommandContext, setting the ExecutionResults
parameter of the constructor to null (line 254).
- KnowledgeCommandContext.executionResults is a private member with no
setter so there is no way to give it a value after it's been instantiated.
- The FireAllRulesCommand fires as part of the batch, and when it tries to
access the execution results from the context, the NPE is thrown.
StatelessKnowledgeSession.execute() later gets the execution results from
the session itself, via the ExecutionResultsImpl instance which is
constructed and passed to the startBatchExecution() method on line 262. I
haven't had time to try this myself, but if we constructed
the ExecutionResultsImpl earlier and passed it to both
the KnowledgeCommandContext constructor and the startBatchExecution()
method, would the problem be alleviated?
In other words, something like this
(StatelessKnowledgeSessionImpl.java:251):
public <T> T execute(Command<T> command) {
StatefulKnowledgeSession ksession = newWorkingMemory();
ExecutionResults results = new ExecutionResultImpl();
KnowledgeCommandContext context = new KnowledgeCommandContext( new
ContextImpl( "ksession",
null ),
null,
null,
ksession,
results
);
try {
((StatefulKnowledgeSessionImpl)
ksession).session.startBatchExecution( results );
If this is indeed a bug and not something silly I'm missing, I'll be happy
to submit a JIRA and even a pull request with the fix.
Thanks
Mike
14 years, 3 months
Class test fails (!= same as ==)
by Wolfgang Laun
Using 5.3.0.Final, arbitrary facts and the rule shown below:
import org.drools.reteoo.InitialFactImpl
rule "Clear" when
$f: Object() #######
then
if( ! ($f instanceof InitialFactImpl) ){
System.out.println( "retract a " + $f.getClass() );
retract( $f );
}
end
This retracts my Foo, Bar and Counter facts. Good.
$f: Object( class == Foo.class ) ####### changed
This retracts all of my Foo facts. Excellent.
$f: Object( class != Foo.class ) ####### changed again
This retracts only Foo facts. Bad.
-W
14 years, 3 months
MVEL and nested properties takes longer time to build working memory
by Anto Paul
Hi,
I have rules that uses nested properties. There are more than thousands
of such rules. Before using any nested properties, time to build working
memory(from decision tables) was pretty fast. After using nested
properties, rule compilation time increased by many folds and it is worse
in environments where NAS is used instead of SCSI disks.
Worst thing is I am not able to profile app using VisualVM as it gives
error that 64k limit of instrumented methods exceeded. So took some thread
dump using jstack and see that most often thread is doing class loading.
This is performed by MVEL classes.
On seeing this I used custom class loader in KnowledgeBuilder and
printed all loaded classes. I do not see that MVEL is using custom class
loader and is directly reading class using some other class loader.This
class loading is taking pretty long time when using network disks.
Is there any way to speed up rule compilation time when using nested
properties.Is there anything like a hint to tell MVEL to load fields of an
object directly from that class instead of searching it in entire
classpath? I see something like "m:" in
MVELDialectRuntimeData.getParserConfiguration().
Using Drools 5.30 Final and Decision tables.
Thanks,
Anto
14 years, 3 months