Showing posts with label rule engines groovy scripting java. Show all posts
Showing posts with label rule engines groovy scripting java. Show all posts

Monday, February 19, 2007

Many rule engines compile the rules to achieve better performance. Drools uses Janino to compile the rules dynamically. Other rules engines use proprietary approaches. With code for javac being made public, rules in java syntax can also be compiled. Since the advent of Mustang, there's been a lot of talk about scripting support in java and I thought why not try something with a scripting language for instance. A benchmark I saw on the net revealed that groovy was by far the fastest next only to Rhino. My inherent suspicion of javascript made me to advise my team to use Groovy and this blog contains the results of our findings. I asked my team to to beat the timings of a fictitious evaluator that would evaluate the rules in 30ms or so.
To be honest, they were circumspect from the beginning but put up a brave front to me anyways. Later they told me it was the time taken to initialize the scripting engine, the binding of the params etc that worried them. So I asked them to try a lot of techniques like pre-cooking (a term I coined for initializing everything beforehand and leaving only the binding and evaluation for the last minute) for achieving better performance.

Now for some Groovy lessons. Groovy can be integrated in your java program in multiple ways.

1. GroovyShell approach
You could use the Groovy shell which wouldn't be much unlike a call to system in c or Runtime.exec in java. This is by far the slowest and I gave up this approach soon as I tried it.


2. GroovyClassLoader approach
The second approach was using the GroovyClassLoader. The groovy class is loaded into the ‘GroovyClassLoader’ and the ‘evaluate’ method invoked using reflection. The ‘GroovyClassLoader’ provides a ‘loadClass’ method for this purpose. However, this method only accepts a source file of a groovy script as input which it then compiles and returns a ‘GroovyClass’ object. The code for this approach is given below:

ClassLoader parent = ScriptRunnerLoader.class.getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);

Object [] ps = vect.toArray(); // parameters to the method
File groovyFile = new File(ruleDir + File.separator + rname + ".groovy");
// Get an groovyClass object
Class groovyClass = loader.parseClass(groovyFile);

//create instance of class
groovyObject = (GroovyObject) groovyClass.newInstance();
//call method
Object obj = groovyObject.invokeMethod("evaluate", ps);


3. Groovy class approach
The last approach was using compiled groovy class. This is the most straightforward way of calling the groovy class and therefore the most efficient. The groovy class is directly imported into the application and the ‘evaluate’ method is called, similar to function calls made on other java objects in the application. This approach yields drastic improvement in performance, as there is no overhead of classloading or from interpreting the rules. The code for this is as below:

Vector vc = (Vector) vec.get(s);
String rname = (String) vc.get(0);

int rno = Integer.parseInt(rname.substring(4));

if(skipListContains(rno))
continue;

Vector vect = (Vector) vc.get(2);
String cond = (String) vc.get(1);

Object [] ps = vect.toArray();
Class groovyClass = Class.forName("rules." + rname);
groovyObject = (GroovyObject) groovyClass.newInstance();


Object res = groovyObject.invokeMethod("evaluate", ps);

Moral:
Don't expect some benefit when the real benefit lies elsewhere. In this case, the benefit of groovy was in its rich syntax and closure support and not in terms of cpu cycles.

Conclusion:
Groovy is great. But it is yet another java syntax. For someone who works with java day in and day out and looking for something new, give Ruby, beanshell, python and F3 a test drive. Forget such things as benchmarks for the time being and do what your heart tells you.