Wednesday, August 27, 2014

Pluggable Knowledge with Custom Assemblers, Weavers and Runtimes

As part of the Bayesian work I've refactored much of Kie to have clean extension points. I wanted to make sure that all the working parts for a Bayesian system could be done, without adding any code to the existing core.

So now each knowledge type can have it's own package, assembler, weaver and runtime. Knowledge is no longer added directly into KiePackage, but instead into an encapsulated knowledge package for that domain, and that is then added to KiePackage. The assembler stage is used when parsing and assembling the knowledge definitions. The weaving stage is when weaving those knowledge definitions into an existing KieBase. Finally the runtime encapsulates and provides the runtime for the knowledge.

drools-beliefs contains the Bayesian integration and a good starting point to see how this works:
https://github.com/droolsjbpm/drools/tree/beliefs/drools-beliefs/

For this to work you and a META-INF/kie.conf file and it will be discovered and made available:
https://github.com/droolsjbpm/drools/blob/beliefs/drools-beliefs/src/main/resources/META-INF/kie.conf

The file uses the MVEL syntax and specifies one or more services:
[
'assemblers' : [ new org.drools.beliefs.bayes.assembler.BayesAssemblerService() ],
'weavers' : [ new org.drools.beliefs.bayes.weaver.BayesWeaverService() ],
'runtimes' : [ new org.drools.beliefs.bayes.runtime.BayesRuntimeService() ]
]

Github links to the package and service implementations:
Bayes Package
Assembler Service
Weaver Service
Runtime Service


Here is a quick unit test showing things working end to end, notice how the runtime can be looked up and accessed. It's using the old api in the test, but will work fine with the declarative kmodule.xml stuff too. The only bit that is still hard coded is the ResourceType.Bayes. As ResourceTypes is an enum. We will probably refactor that to be a standard Class instead, so that it's not hard coded.

The code to lookup the runtime:
StatefulKnowledgeSessionImpl ksession = (StatefulKnowledgeSessionImpl) kbase.newStatefulKnowledgeSession();
BayesRuntime bayesRuntime = ksession.getKieRuntime(BayesRuntime.class);

The unit test:
KnowledgeBuilder kbuilder = new KnowledgeBuilderImpl();
kbuilder.add( ResourceFactory.newClassPathResource("Garden.xmlbif", AssemblerTest.class), ResourceType.BAYES );

KnowledgeBase kbase = getKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

StatefulKnowledgeSessionImpl ksession = (StatefulKnowledgeSessionImpl) kbase.newStatefulKnowledgeSession();

BayesRuntime bayesRuntime = ksession.getKieRuntime(BayesRuntime.class);
BayesInstance instance = bayesRuntime.getInstance( Garden.class );
assertNotNull(  instance );

jBPM is already refactored out from core and compiler, although it uses it's own interfaces for this. We plan to port the existing jBPM way to this and actually all the Drools stuff will eventually be done this way too. This will create a clean KIE core and compiler with rules, processes, bayes or any other user knowledge type are all added as plugins.

A community person is also already working on a new type declaration system, that will utilise these extensions. Here is an example of what this new type system will look like:
https://github.com/sotty/metaprocessor/blob/master/deklare/src/test/resources/test1.ktd

Share/Bookmark

Monday, August 25, 2014

Drools - Bayesian Belief Network Integration Part 4

This follows my earlier Part 3 posting in May.

I have integrated the Bayesian System into the Truth Maintenance System, with a first end to end test. It's still very raw, but it demonstrates how the TMS can be used to provide evidence via logical insertions. 

The BBN variables are mapped to fields on the Garden class. Evidence is applied as a logical insert, using a property reference - indicating it's evidence for the variable mapped to that property.  If there is conflict evidence for the same field, then the fact becomes undecided. 

The rules are added via a String, while the BBN is added from a file. This code uses the new pluggable knowledge types, which allow pluggable parsers, builders and runtimes. This is how the Bayesian stuff is added cleanly, without touching the core - but I'll blog about those another time.

String drlString = "package org.drools.bayes; " +
             "import " + Garden.class.getCanonicalName() + "; \n"  +
             "import " + PropertyReference.class.getCanonicalName() + "; \n"  +
             "global " +  BayesBeliefFactory.class.getCanonicalName() + " bsFactory; \n" +
             "dialect 'mvel'; \n" +
             " " +
             "rule rule1 when " +
             "        String( this == 'rule1') \n" +
             "    g : Garden()" +
             "then " +
              "    System.out.println(\"rule 1\"); \n" +
             "    insertLogical( new PropertyReference(g, 'cloudy'), bsFactory.create( new double[] {1.0,0.0} ) ); \n " +
             "end " +

             "rule rule2 when " +
             "        String( this == 'rule2') \n" +
             "    g : Garden()" +
             "then " +
             "    System.out.println(\"rule2\"); \n" +
             "    insertLogical( new PropertyReference(g, 'sprinkler'), bsFactory.create( new double[] {1.0,0.0} ) ); \n " +
             "end " +

             "rule rule3 when " +
             "        String( this == 'rule3') \n" +
             "    g : Garden()" +
             "then " +
             "    System.out.println(\"rule3\"); \n" +
             "    insertLogical( new PropertyReference(g, 'sprinkler'), bsFactory.create( new double[] {1.0,0.0} ) ); \n " +
             "end " +


             "rule rule4 when " +
             "        String( this == 'rule4') \n" +
             "    g : Garden()" +
             "then " +
             "    System.out.println(\"rule4\"); \n" +
             "    insertLogical( new PropertyReference(g, 'sprinkler'), bsFactory.create( new double[] {0.0,1.0} ) ); \n " +
             "end " +
             "\n";

KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kBuilder.add( ResourceFactory.newByteArrayResource(drlString.getBytes()),
              ResourceType.DRL );
kBuilder.add( ResourceFactory.newClassPathResource("Garden.xmlbif", AssemblerTest.class), ResourceType.BAYES );

KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();
kBase.addKnowledgePackages( kBuilder.getKnowledgePackages() );

StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession();

NamedEntryPoint ep = (NamedEntryPoint) ksession.getEntryPoint(EntryPointId.DEFAULT.getEntryPointId());

BayesBeliefSystem bayesBeliefSystem = new BayesBeliefSystem( ep, ep.getTruthMaintenanceSystem());

BayesBeliefFactoryImpl bayesBeliefValueFactory = new BayesBeliefFactoryImpl(bayesBeliefSystem);

ksession.setGlobal( "bsFactory", bayesBeliefValueFactory);

BayesRuntime bayesRuntime = ksession.getKieRuntime(BayesRuntime.class);
BayesInstance<Garden> instance = bayesRuntime.createInstance(Garden.class);
assertNotNull(  instance );

assertTrue(instance.isDecided());
instance.globalUpdate();
Garden garden = instance.marginalize();
assertTrue( garden.isWetGrass() );

FactHandle fh = ksession.insert( garden );
FactHandle fh1 = ksession.insert( "rule1" );
ksession.fireAllRules();
assertTrue(instance.isDecided());
instance.globalUpdate(); // rule1 has added evidence, update the bayes network
garden = instance.marginalize();
assertTrue(garden.isWetGrass());  // grass was wet before rule1 and continues to be wet


FactHandle fh2 = ksession.insert( "rule2" ); // applies 2 logical insertions
ksession.fireAllRules();
assertTrue(instance.isDecided());
instance.globalUpdate();
garden = instance.marginalize();
assertFalse(garden.isWetGrass() );  // new evidence means grass is no longer wet

FactHandle fh3 = ksession.insert( "rule3" ); // adds an additional support for the sprinkler, belief set of 2
ksession.fireAllRules();
assertTrue(instance.isDecided());
instance.globalUpdate();
garden = instance.marginalize();
assertFalse(garden.isWetGrass() ); // nothing has changed

FactHandle fh4 = ksession.insert( "rule4" ); // rule4 introduces a conflict, and the BayesFact becomes undecided
ksession.fireAllRules();

assertFalse(instance.isDecided());
try {
    instance.globalUpdate();
    fail( "The BayesFact is undecided, it should throw an exception, as it cannot be updated." );
} catch ( Exception e ) {
    // this should fail
}

ksession.delete( fh4 ); // the conflict is resolved, so it should be decided again
ksession.fireAllRules();
assertTrue(instance.isDecided());
instance.globalUpdate();
garden = instance.marginalize();
assertFalse(garden.isWetGrass() );// back to grass is not wet


ksession.delete( fh2 ); // takes the sprinkler belief set back to 1
ksession.fireAllRules();
instance.globalUpdate();
garden = instance.marginalize();
assertFalse(garden.isWetGrass() ); // still grass is not wet

ksession.delete( fh3 ); // no sprinkler support now
ksession.fireAllRules();
instance.globalUpdate();
garden = instance.marginalize();
assertTrue(garden.isWetGrass()); // grass is wet again

Share/Bookmark

Tuesday, August 19, 2014

Drools Mailing List migration to Google Groups

Drools community member,

The Drools team are moving the rules-usesrs and rules-dev list to Google Groups. This will allow users to have a combined email and web access to the group.
New Forum Information : http://drools.org/community/forum.html (click link to view)

The rules-users mailing list has become high volume and it seems natural to split the group into those asking for help with setup, configuration, installation and administration and those who are asking for help with authoring and executing of rules. For this reason rules-users will be split into two groups - drools-setup and drools-usage.  

Drools Setup - https://groups.google.com/forum/#!forum/drools-setup (click link to subscribe)
Drools Usage - https://groups.google.com/forum/#!forum/drools-usage (click link to subscribe)

The rules-dev mailing list will move to drools-development. 

Drools Development - https://groups.google.com/forum/#!forum/drools-development (click link to subscribe)

Google Groups limits the number of invitations, so we were unable to send invitations. For this reason you will need to manually subscribe. 

The Drools Team

Share/Bookmark

Friday, August 15, 2014

Drools Execution Server demo (6.2.0.Beta1)

As some of you know already, we are introducing a new Drools Execution Server in version 6.2.0.

I prepared a quick video demo showing what we have done so far (version 6.2.0.Beta1). Make sure you select "Settings -> 720p" and watch it in full screen.



Share/Bookmark

Monday, August 11, 2014

JUDCon 2014 Brazil: Call for Papers

The International JBoss Users and Developer Conference, and premier JBoss developer event “By Developers, For Developers,” is pleased to announce that the call for papers for JUDCon: 2014 Brazil, which will be held in São Paulo on September 26th, is now open! Got Something to Say? Say it at JUDCon: 2014 Brazil! Call for papers ends at 5 PM on August 22nd, 2014 São Paulo time, and selected speakers will be notified by August 29th, so don't delay!

http://www.jboss.org/events/JUDCon/2014/brazil/cfp
Share/Bookmark