lboullo0
lboullo0

Reputation: 772

How to use Drools backward chaining to list what initial facts are needed to satisfy a goal?

I'm trying to use Drools backward chaining to find out which facts are needed to get an object inserted in the working memory. In the following example, I expect to get the fact "go2".

rule "ins a"
when
    String( this == "go2" )
then 
    insert(new A());
end


rule "Run"
when
then
    insert(new String("go1"));
end

rule "Test isThereAnyA"
    when
        String( this == "go1" )
        isThereAnyA(a;)
    then
        System.out.println( "you can get " + a );   
end

query isThereAnyA (A a)
    a := A()
end

I've been looking at examples in the official documentation http://docs.jboss.org/drools/release/6.1.0.Final/drools-docs/html_single/index.html#d0e21289 but they show a different situation (the rules in those examples doesn't creates new fact)

From the chart http://docs.jboss.org/drools/release/6.1.0.Final/drools-docs/html_single/index.html#d0e21240 I think it should work but I haven't found a way to specify a query that gives me the expected results.

Thank you in advance.

Upvotes: 4

Views: 2971

Answers (1)

Davide Sottara
Davide Sottara

Reputation: 221

Short answer:

Unfortunately backward chaining can not be used for this purpose. It will not give you "go2" in this case.

Long answer:

In Drools, Backward chaining (BC) is a way to query the WM in a goal-driven fashion, not a way to trace back the derivation graph of a normal forward chaining inference process.

BC allows rule "Test" to retrieve As through the query "isThereAnyA", and possibly invoke other queries, but will not allow to find the "production" link between "A" and "go2". The reason is that "when..then..insert.." does not create any link between the triggering facts and the asserted conclusion, and backward chaining will not change it.

What you could do with BC is this:

query isThereAnyA_InPresenceOfA_String( A a )
   isThereAnyString( $s ; )       
   a := A()
end 
query isThereAnyString( String $s )
   $s := String( this == "go2" )
end

This will pick up As only if a String "go2" is (still) present. However you'll notice that the connection between a particular instance of A and a the particular String which led to its assertion is still missing.

To know exactly which objects led to the assertion of another object you may need a different approach. Options include:

  • make the connection explicit : new A( $s ) // $s bound to "go2"
  • use "insertLogical" to establish a dependency between "go2" and A, then query the TruthMaintenanceSystem

The TMS-based one would be my tentative choice, but it also depends on your exact requirements.

This use case is common, there may be other options, including a few which are experimental as they are being developed in 6.3, but I'd rather ask a few questions first. That is: when do you need exactly to discover the facts - during the execution of the rules, or "offline"? Is it purely for auditing purposes, or does it impact your business logic? Can you have multiple rules asserting the "same" object?

Hope this helps Davide

Upvotes: 3

Related Questions