Fetching fact from stateful session of drools

时光总嘲笑我的痴心妄想 提交于 2019-12-08 11:08:30

问题


I'm trying to get the new inserted fact from the rules:

import com.neu.als.thesis.db.beans.FLTBean
import com.neu.als.thesis.db.beans.StudentBean

rule "Excellent"
    no-loop

    when
        $m: FLTBean ( listeningScore > 85 && listeningScore < 101 )
    then
        StudentBean studentBean = new StudentBean();
        studentBean.setKnowledgeLevel( "Excellent" );
        insert( studentBean );
end

To get something from the stateful session I should do this:

protected Collection<Object> findFacts( final StatefulKnowledgeSession session, final String factClass )
{
    ObjectFilter filter = new ObjectFilter()
    {
        @Override
        public boolean accept( Object object )
        {
            return object.getClass().equals( factClass );
        }
    };
    Collection<Object> results = session.getObjects( filter );
    return results;
}

Given the fact that I already set the code to read the rules the next step I did is this:

protected void processFacts( KnowledgeBase aKnowledgeBase, Object aBean )
{
    StatefulKnowledgeSession ksession = aKnowledgeBase.newStatefulKnowledgeSession();

    ksession.insert( aBean );
    ksession.fireAllRules();

    Collection<Object> result = findFacts( ksession, "StudentBean" );

    ksession.dispose();

    for( Object test : result )
    {
        System.out.println( test == null );
        System.out.println( test );
    }
}

Why I don't get any response from the object? It doesn't print anything. No stacktrace, no error. I even check it if its null. But still no response. What am I doing wrong?

Update:

This is the method that read the .drl file.

protected KnowledgeBase readKnowledgeBase( String aRuleFileName ) throws Exception
{
     KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
     kbuilder.add( ResourceFactory.newClassPathResource( aRuleFileName, getClass() ), ResourceType.DRL );
     KnowledgeBuilderErrors errors = kbuilder.getErrors();

     if( errors.size() > 0 )
     {
        for( KnowledgeBuilderError error : errors )
        {
            System.err.println( error );
        }
            throw new IllegalArgumentException( "Could not parse knowledge." );
     }

   KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
   kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
   return kbase;
}

The one that calls the processFacts method is this

public String evaluateConceptKnowledgeLevel( double FLTmark )
{
   String knowledgeLevel = null;

   // test
   InferenceEngine ie = new InferenceEngine();
   KnowledgeBase kbase;
   try
   {
       kbase = ie.readKnowledgeBase( "KnowledgeLevel.drl" );
       FLTBean bean = new FLTBean();
       bean.setListeningScore( FLTmark );

       ie.processFacts( kbase, bean );
   }
   catch( Exception e )
   {
       e.printStackTrace();
   }
   // up to here

   return knowledgeLevel;
}

回答1:


A few options...

Pass in the simple name instead of the full class name.

Change

Collection<Object> result = findFacts( ksession, "com.neu.als.thesis.db.beans.StudentBean" );

to

Collection<Object> result = findFacts( ksession, "StudentBean" );

Change the 'accept' method to compare the full class name.

Change

     public boolean accept( Object object ) {
         return object.getClass().getSimpleName().equals( factClass );
     }

to

     public boolean accept( Object object ) {
         return object.getClass().getName().equals( factClass );
     }

Change the findFacts method to take the actual class as an argument and compare to that.

Change

protected Collection<Object> findFacts( 
        final StatefulKnowledgeSession session, 
        final String factClass ) {
    ObjectFilter filter = new ObjectFilter() {
    @Override
        public boolean accept( Object object ) {
            return object.getClass().getSimpleName().equals( factClass );
        }
    };

    Collection<Object> results = session.getObjects( filter );
    return results;
}

to

protected Collection<Object> findFacts( 
        final StatefulKnowledgeSession session, 
        final Class factClass ) {
    ObjectFilter filter = new ObjectFilter() {
    @Override
        public boolean accept( Object object ) {
            return object.getClass().equals( factClass );
        }
    };

    Collection<Object> results = session.getObjects( filter );
    return results;
}

Assuming that your facts are all Java classes, then the 3rd option of comparing the class is a better option. If you use declared types, then the simple name is useful, as you are unlikely to have a reference to the actual class that Drools generates.

An additional note for when you're testing these things, the Drools API also provides the session.getObjects() method with no arguments. By calling that you will get a reference to all facts that are in working memory, no matter what they are. When writing filters, it's not a bad idea to use that to prove to yourself that the expected facts are in working memory, and then to add filtering, so that you can pick out specific facts according to their class and their properties.



来源:https://stackoverflow.com/questions/19884847/fetching-fact-from-stateful-session-of-drools

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!