|
|
Subject: [drools-user] Help on writing XML rules - msg#00164
Hi,
I'm new to drools. I came across this piece of rule in one of the blogs. The
rule is like this:
when
$cust : Customer( region >= 1 )
$order : Order( customer == $cust, totalAmount > 30 )
then
something...
Following are my questions
1. In the above rule, I specify Order( customer == $cust...) to make the
rule more specific to a customer. Right?
2. Suppose I remove the 'customer == $cust' check from Order, won't the
result be the same?
3. Cal I write the same thing using XML in drools 3.0. Is that possible?
4. Also, in my second condition can I specify some more CEs like
$order: Order( (customer == $cust , (totalAmount > 500 ||
numberoforders < 400) )
Thanks,
Sudha
--
View this message in context:
http://www.nabble.com/Help-on-writing-XML-rules-tf2880224.html#a8048347
Sent from the drools - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
Thread at a glance:
Previous Message by Date:
Re: [drools-user] Problem with serializing WorkingMemory
Michael,
No, this is a genuine issue. Trunk is still under heavy refactorings
and development.
Please, to test and use your application, checkout the stable 3.0.x
branch:
http://anonsvn.labs.jboss.com/labs/jbossrules/branches/3.0.x/
I will fix the issue in trunk asap anyway. Meanwhile, if you can open
a JIRA for it, you get automatically notified when I fix it.
Thank you,
[]s
Edson
Michael Suzio wrote:
OK. Sorry, found the antlr3 jar and now rule loading works. Still a
small issue, and I'm sure it's my fault -- but if someone can identify
what I might have wrongly copied over or not compiled correctly?
Saving working memory
java.io.NotSerializableException:
org.drools.reteoo.ReteooWorkingMemory$WorkingMemoryReteAssertAction
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1081)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
at java.util.ArrayList.writeObject(ArrayList.java:569)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java :585)
at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:917)
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1339)
at java.io.ObjectOutputStream.writeOrdinaryObject
(ObjectOutputStream.java:1290)
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1375)
at java.io.ObjectOutputStream.writeSerialData
(ObjectOutputStream.java:1347)
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1290)
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
at java.io.ObjectOutputStream.writeObject
(ObjectOutputStream.java:302)
at WorkingMemorySaver.saveWorkingMemory(WorkingMemorySaver.java:42)
at DroolsFailureTest.runTest(DroolsFailureTest.java:70)
--
Edson Tirelli
Software Engineer - JBoss Rules Core Developer
Office: +55 11 3124-6000
Mobile: +55 11 9218-4151
JBoss, a division of Red Hat @ www.jboss.com
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
Next Message by Date:
Re: [drools-user] Help on writing XML rules
I'll try to tackle your question on this DRL rule; I haven't used the XML syntax, but anything I say here should be expressible in XML also, it's just a different wayto say the same sort of things to the Rules Engine.
Let's look at your rule, and how it works:when $cust : Customer( region >= 1 ) $order : Order( customer == $cust, totalAmount > 30 )then something...
The when clause of a DRL rule specifies the conditions under which the then clause (the "consequence") will be evaluated. It is based off of assertions we can make about the objects known to the system (which is what our working memory is). Drools works on the basis of object types, which in Java means class types. So, this rule is making assertions about the existence of some sort of Customer object and another sort of Order object within the Working Memory. The exact type of the objects themselves isn't relevant -- if we had an EliteCustomer object in our libraries that was a subclass of Customer, it still passes the "instanceof" criteria to be a Customer, and would be a candidate for this rule.
On these types, we can make assertions beyond just the initial assertion that an object of the desired type exists in the WorkingMemory. We do this by asserting that the object has certain properties. By "property", we mean anything that the Java Bean Specification would call a property. So, for the first example above, we're saying something about the 'region' property. Typically, that means our Customer type has methods with the following signatures:
public void setRegion(int region);public int getRegion();The Drools documentation has more details on this, but the important thing is to know that Drools really wants to look at your objects as POJOs that it can use Java Bean introspectors on and get some information about the assertions you're making.
Assertions in a when clause are, by default, implicitly AND'ed together to satisfy a given rule. So our Order and Customer assertions *are* intimately related.So, in English, the rule is saying something like this:
when There exists in the WorkingMemory an object which is an instanceof Customer (which I'd like to just call $cust from now on for short) whose region property has the value of 1 or more AND There exists in the WorkingMemory an object which is an instanceof Order, and whose "customer" property must be equal to the $cust reference from the first assertion (here I'm a bit fuzzy about whether this is referential equality --
i.e., they must be the exact same object, or equality via the equals() method -- the Drools guys can correct me), and whose totalAmount property is more than 30).then do somethingSo, as you can see, with the implicit AND'ing, I'm making a very specific assertion -- as point #1 of your email says. Point #2 you make is *not* correct; leaving off the "customer == $cust" portion of the rule would make a big difference in the rule, removing the requirement that order and customer match. Most likely, this is undesirable -- you *want* to be sure to evaluate the rule only for matching customers and orders. If there ever were a case where a Customer and Order could exist in the system that were not related, then you might have a problem.
Suppose I had the following objects in the WorkingMemory:Customer A: Name = "Bob" Region = 2Customer B: Name = "Alice" Region = 2Order C: Customer = "Bob"
totalAmount = 55Order D: Customer = "Alice" totalAmount = 60With the original rule, I'm going to see two firings -- one for the combination of A and C, one for the combination of B and D. The wording of the rule ensures those are the only combinations that will satisfy it. However, if I remove the ties between customer and order in the rule, now I'll see a firing of A and C, A and D, B and C, and B and D -- to cover all possible pairings of any customer and any order. Again, this is probably not what you want.
The Drools guys can correct me on the equality issue, but I think otherwise I've got this correct.As far as point #4, yes, you can add more specifics to your assertions just like you showed there. You want to add whatever specifics it takes to ensure the rule only fires for the exact combinations of interest, and it is best to push as much logic as possible into the when condition, so long as you can make those assertions through simple property fields of the object. It gets more complex when the properties are not amenable to such examination (for instance, there does not exist a no-arg getter for the field of interest; in that case, Drools has to do much more work to pass an argument in, and I believe it cannot cache results for future evaluations, meaning that work has to be done many more times than would be needed for the no-arg case).
Let me know if I was confusing. This is hard to get at first, you usually have to play with it and look at many examples.--Michael J. Suziomsuzio@xxxxxxxxx
Previous Message by Thread:
[drools-user] Problem with serializing WorkingMemory
I've run into a problem. Strangely enough, I swear this worked in the past, but then we went into a long coding phase and emerged from it to find out our test cases didn't actually work "in the wild". Took some time, but eventually I figured out the why of that -- and coded better tests.
In any case, here is what is happening:- We create a rulebase from some DRL text (doesn't matter how it gets created, my test code below is *one* example case)- A Working Memory object is created:
WorkingMemory wm =3D3D3D rulebase.newWorkingMemory();- The WorkingMemory is serialized to disk via normal ObjectOutputStream methodsNow, *while the VM is running*, I can create new RuleBase objects, read that WorkingMemory back in, and attach it to those new RuleBase objects, and it always works. However, if I stop the VM, and re-run the sample program below, it fails with this stack trace:
java.lang.ClassNotFoundException: [Lorg.drools.reteoo.ObjectTypeNode; at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at
java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268) at java.lang.ClassLoader.loadClass
(ClassLoader.java:251) at org.drools.rule.CompositePackageClassLoader.loadClass(UnknownSource) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at org.drools.common.ObjectInputStreamWithLoader.resolveClass
(UnknownSource) atjava.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1544) atjava.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466) atjava.io.ObjectInputStream.readArray
(ObjectInputStream.java:1591) atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1299) atjava.io.ObjectInputStream.readObject(ObjectInputStream.java:348) at java.util.HashMap.readObject
(HashMap.java:1067) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) atjava.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946) atjava.io.ObjectInputStream.readSerialData
(ObjectInputStream.java:1809) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719) atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305) atjava.io.ObjectInputStream.readArray
(ObjectInputStream.java:1634) atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1299) atjava.io.ObjectInputStream.readArray(ObjectInputStream.java:1634) atjava.io.ObjectInputStream.readObject0
(ObjectInputStream.java:1299) atjava.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1908) atjava.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1832) at java.io.ObjectInputStream.readOrdinaryObject
(ObjectInputStream.java:1719) atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305) atjava.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1908) atjava.io.ObjectInputStream.readSerialData
(ObjectInputStream.java:1832) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719) atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305) atjava.io.ObjectInputStream.defaultReadFields
(ObjectInputStream.java:1908) atjava.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1832) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719) atjava.io.ObjectInputStream.readObject0
(ObjectInputStream.java:1305) atjava.io.ObjectInputStream.readObject(ObjectInputStream.java:348) at org.drools.common.AbstractRuleBase.newWorkingMemory(UnknownSource) at org.drools.common.AbstractRuleBase.newWorkingMemory
(UnknownSource) at DroolsFailureTest.runTest(DroolsFailureTest.java:52) at DroolsFailureTest.main(DroolsFailureTest.java:25)So, it appears that WorkingMemory objects cannot (at least for me in this case) be serialized, then read back into a new VM. That always fails, and it's quite vexing. Our intention is to be running rules on large amounts of data that periodically come in, and we need to save our progress as we go along and be able to restore that data anywhere in the data cluster that the job gets parceled out to (so, ultimately, the WorkingMemory data is going to go into a database or possibly get written out to a shared filesystem among the drones). If I can't save/restore data transparently between runs, this is pretty much a show-stopper.
Technical details: Java 1.5.0_10 (but I tested this on 1.5.0_04, 1.5.0_06, 1.5.0_08, and 1.5.0_09 -- basically, whatever we had available on other people's workstations), all on Windows boxes. JBoss Rules 3.0.3
and 3.0.5 both seemed to fail consistently.Here is the sample code (it's two classes, save them to appropriate files). I think these should be reproducible cases. Run the DroolsFailureTest twice, and it will work the first time (showing that reads/writes within the VM work), and then fail the second time it is run (when the cached WorkingMemory on disk then is getting read back into a new VM).
import java.io.*;import org.drools.*;import org.drools.compiler.*;public class DroolsFailureTest{ public static void main(String[] args) { boolean removeFile = false;
if (args.length > 0) { removeFile = args[0].equalsIgnoreCase("remove"); } if (removeFile) { WorkingMemorySaver memSaver = getWorkingMemorySaver();
memSaver.clearWorkingMemory(); } runTest(); // run 1 -- should always work runTest(); // run 2 -- fails? System.exit(0); } public static void runTest() { System.out.println
("Getting working memory handler"); WorkingMemorySaver memSaver = getWorkingMemorySaver(); RuleBase rb = getRuleBase(); // Uncomment this -- prove we get a different RuleBase object // each time
// // System.err.println("Rulebase hashcode = " + rb); InputStream is = memSaver.getWorkingMemoryInputStream(); System.out.println("Got input stream " + is);
WorkingMemory wm = null; if (is != null) { System.err.println("Trying to restore object from input stream"); try { wm = rb.newWorkingMemory(is);
System.err.println("Got " + wm); } catch (Exception e) { e.printStackTrace(); } } if (wm == null) { wm = rb.newWorkingMemory();
System.err.println("No working memory, creating new + wm); } System.out.println("Asserted data, running the rules"); // wm.fireAllRules(); System.err.println
("Saving working memory"); memSaver.saveWorkingMemory(wm); } private static RuleBase getRuleBase() { System.setProperty("drools.compiler", "JANINO");
RuleBaseLoader rbl = RuleBaseLoader.getInstance(); String ruleText = getRuleText(); RuleBase rb = null; try { rb = rbl.loadFromReader(new StringReader(ruleText)); } catch (CheckedDroolsException e)
{ e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return rb; } private static String getRuleText() { String ruleText =
"package test;\n" + "rule TestRule\n" + "when\n" + " sObj: String()\n" + "then\n" + "
System.out.println(\"Saw \" + sObj);\n" + "end"; return ruleText; } private static WorkingMemorySaver getWorkingMemorySaver() { WorkingMemorySaver memSaver = new WorkingMemorySaver();
memSaver.setWorkingMemoryDir("C:\\"); return memSaver; }}import java.io.*;import org.drools.*;/** * */public class WorkingMemorySaver{ private File workingMemoryDir = null;
public WorkingMemorySaver() { } public InputStream getWorkingMemoryInputStream() { File workingMemoryFile = getWorkingMemoryFile(); InputStream stream = null; if (
workingMemoryFile.exists()) { try { stream = new FileInputStream(getWorkingMemoryFile()); } catch (FileNotFoundException e) { e.printStackTrace();
} } return stream; } public void saveWorkingMemory(WorkingMemory wm) { try { //noinspection IOResourceOpenedButNotSafelCuyClosed ObjectOutputStream oStream = new ObjectOutputStream((new FileOutputStream(getWorkingMemoryFile())));
oStream.writeObject(wm); } catch (IOException e) { e.printStackTrace(); } } /** * used in case the file becomes corrupted */ public void clearWorkingMemory()
{ try { File workingMemoryFile = getWorkingMemoryFile(); if (workingMemoryFile != null) { boolean deleted = workingMemoryFile.delete(); if (deleted)
{ System.err.println("Deleted working memory file " + workingMemoryFile.getName()); } } } catch (Exception e) { e.printStackTrace(); }
} public File getWorkingMemoryDir() { return workingMemoryDir; } public void setWorkingMemoryDir(File workingMemoryDir) { this.workingMemoryDir = workingMemoryDir; }
public void setWorkingMemoryDir(String workingMemoryDirName) { this.workingMemoryDir = new File(workingMemoryDirName); } private File getWorkingMemoryFile() { return new File(workingMemoryDir, "working_memory.bin");
}}A possible related bug is in this thread:http://www.mail-archive.com/user@xxxxxxxxxxxxxxxxxxx/msg01731.html
Which points out this Sun bug:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=3D3D3D6434149In fact, it looks like my problem is just a variant on Raffael's. Like Raffael, I've tried JBoss
3.0.5 (no help) and Java 1.6 (similar results-- different "stream corrupted" error in my case, but essentially the same). I don't see a resolution to his bug on the archives -- Raffael, did you find a fix? Please let me know!
Sorry for such a long post, but I hope someone can point out what I can do to fix this issue.
Next Message by Thread:
Re: [drools-user] Help on writing XML rules
I'll try to tackle your question on this DRL rule; I haven't used the XML syntax, but anything I say here should be expressible in XML also, it's just a different wayto say the same sort of things to the Rules Engine.
Let's look at your rule, and how it works:when $cust : Customer( region >= 1 ) $order : Order( customer == $cust, totalAmount > 30 )then something...
The when clause of a DRL rule specifies the conditions under which the then clause (the "consequence") will be evaluated. It is based off of assertions we can make about the objects known to the system (which is what our working memory is). Drools works on the basis of object types, which in Java means class types. So, this rule is making assertions about the existence of some sort of Customer object and another sort of Order object within the Working Memory. The exact type of the objects themselves isn't relevant -- if we had an EliteCustomer object in our libraries that was a subclass of Customer, it still passes the "instanceof" criteria to be a Customer, and would be a candidate for this rule.
On these types, we can make assertions beyond just the initial assertion that an object of the desired type exists in the WorkingMemory. We do this by asserting that the object has certain properties. By "property", we mean anything that the Java Bean Specification would call a property. So, for the first example above, we're saying something about the 'region' property. Typically, that means our Customer type has methods with the following signatures:
public void setRegion(int region);public int getRegion();The Drools documentation has more details on this, but the important thing is to know that Drools really wants to look at your objects as POJOs that it can use Java Bean introspectors on and get some information about the assertions you're making.
Assertions in a when clause are, by default, implicitly AND'ed together to satisfy a given rule. So our Order and Customer assertions *are* intimately related.So, in English, the rule is saying something like this:
when There exists in the WorkingMemory an object which is an instanceof Customer (which I'd like to just call $cust from now on for short) whose region property has the value of 1 or more AND There exists in the WorkingMemory an object which is an instanceof Order, and whose "customer" property must be equal to the $cust reference from the first assertion (here I'm a bit fuzzy about whether this is referential equality --
i.e., they must be the exact same object, or equality via the equals() method -- the Drools guys can correct me), and whose totalAmount property is more than 30).then do somethingSo, as you can see, with the implicit AND'ing, I'm making a very specific assertion -- as point #1 of your email says. Point #2 you make is *not* correct; leaving off the "customer == $cust" portion of the rule would make a big difference in the rule, removing the requirement that order and customer match. Most likely, this is undesirable -- you *want* to be sure to evaluate the rule only for matching customers and orders. If there ever were a case where a Customer and Order could exist in the system that were not related, then you might have a problem.
Suppose I had the following objects in the WorkingMemory:Customer A: Name = "Bob" Region = 2Customer B: Name = "Alice" Region = 2Order C: Customer = "Bob"
totalAmount = 55Order D: Customer = "Alice" totalAmount = 60With the original rule, I'm going to see two firings -- one for the combination of A and C, one for the combination of B and D. The wording of the rule ensures those are the only combinations that will satisfy it. However, if I remove the ties between customer and order in the rule, now I'll see a firing of A and C, A and D, B and C, and B and D -- to cover all possible pairings of any customer and any order. Again, this is probably not what you want.
The Drools guys can correct me on the equality issue, but I think otherwise I've got this correct.As far as point #4, yes, you can add more specifics to your assertions just like you showed there. You want to add whatever specifics it takes to ensure the rule only fires for the exact combinations of interest, and it is best to push as much logic as possible into the when condition, so long as you can make those assertions through simple property fields of the object. It gets more complex when the properties are not amenable to such examination (for instance, there does not exist a no-arg getter for the field of interest; in that case, Drools has to do much more work to pass an argument in, and I believe it cannot cache results for future evaluations, meaning that work has to be done many more times than would be needed for the no-arg case).
Let me know if I was confusing. This is hard to get at first, you usually have to play with it and look at many examples.--Michael J. Suziomsuzio@xxxxxxxxx
|
|