I have recently looked into Knowledge Agent and I don't think that this will
update the
Knowledge Base of an existing Stateful Knowledge Session.
For a Stateful KS you do a kAgent.getKnowledgeBase() to get the new KBase
and start a new KS from it.
For a Stateless KS that has been created with
kAgent.newStatelessKnowledgeSession(), the KBase is updated automatically
and the next kSession.execute() will reflect the new KBase.
If this is not correct, I'd appreciate pointers where it is documented
otherwise.
I haven't tested this exhaustively, but what I did test did not contradict
the above.
-W
2011/4/19 Esteban Aliverti <esteban.aliverti(a)gmail.com>
There is no need to update your kbase in the listener. The agent will
apply
all the changes to the provided kbase. If you already have a stateful
ksession from that kbase, then the changes in the kbase should be
reflected immediately.
Could you please post the log output of the kagent?
Best Regards,
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Esteban Aliverti
- Developer @
http://www.plugtree.com
- Blog @
http://ilesteban.wordpress.com
On Tue, Apr 19, 2011 at 4:24 AM, Mattias Avelin <
mattias.avelin(a)netlight.se> wrote:
> Hi!
>
> Yes, I have already implemented a KnowledgeAgentEventListener acts on
> KnowledgeBaseUpdatedEvent and ResourceCompilationFailedEvent. I use this to
> update my knowledgebase reference in my class that wraps the KnowledgeBase
> and KnowledgeAgent. Below is the code for this class
> ("DynamicDecisionService"). I suspect that I have missed something vital
> since I'm actually not getting my knowledgebase to update itself either but
> I "do it myself" in the listener when I receive a
KnowledgeBaseUpdatedEvent.
>
> Here is the code that handles the KnowledgeAgent and KnowledgeBase (I have
> stripped out some labels and comments since this belongs to the client).
>
> Best regards
>
> Mattias Avelin
>
> package com.x.service;
>
> import java.util.ArrayList;
> import org.apache.log4j.Logger;
> import org.drools.KnowledgeBase;
> import org.drools.KnowledgeBaseConfiguration;
> import org.drools.KnowledgeBaseFactory;
> import org.drools.agent.KnowledgeAgent;
> import org.drools.agent.KnowledgeAgentConfiguration;
> import org.drools.agent.KnowledgeAgentFactory;
> import org.drools.builder.KnowledgeBuilderError;
> import org.drools.builder.KnowledgeBuilderErrors;
> import org.drools.conf.EventProcessingOption;
> import org.drools.event.knowledgeagent.KnowledgeBaseUpdatedEvent;
> import org.drools.event.knowledgeagent.ResourceCompilationFailedEvent;
> import org.drools.event.rule.DefaultKnowledgeAgentEventListener;
> import org.drools.io.ResourceChangeScannerConfiguration;
> import org.drools.io.ResourceFactory;
>
> /**
> * {@inheritDoc}
> * <p>
> * This implementation of DecisionService updates the knowledgebase
> dynamically
> * when the underlying rules (drl-files) are updated. Therefore each call
> to the
> * createSession() method will return a session based on the most resent
> version
> * of the rules (allowing for some lag due to the intervals of the
> * resource scanner).
> * </p>
> * <p>
> * For statefull sessions the session needs to be updated "manually" when
> the
> * KnowledgeBase has been updated.
> * </P>
> * @author Mattias Avelin - mattias.avelin(a)netlight.se
> */
> public class DynamicDecisionService implements DecisionService
> {
> private static Logger LOG =
> Logger.getLogger(DynamicDecisionService.class);
>
> // Repository of all the application's knowledge definitions
> private KnowledgeBase kBase;
> // The agent that monitores the rule files (resources) for changes
> private KnowledgeAgent kAgent;
> // Decision service type
> private DecisionSessionType type;
> // When the current knowledgebase was created
> private long kbaseLastUpdated;
>
> /**
> * Create a DynamicDecisionService using a ChangeSet.
> *
> * @param changeSet - The ChangeSet referencing the rule-files to use
> * for this service. Expects a classpath reference
> *
> * @throws IllegalArgumentException if changeSet is not a valid
> ChangeSet.
> */
> public DynamicDecisionService(
> String changeSet,
> DecisionSessionType type)
> {
> this.kBase = createKnowledgeBase(type);
> // the method could reference kBase itself but I thought it
> // more more "clear" if I actually supply it in the method
> invocation
> this.kAgent = createKnowledgeAgent(changeSet, this.kBase);
> // This should not be neccesary according to all sources I've found
> // but without re-assigning the reference it doesn't work!?!?
> this.kBase = kAgent.getKnowledgeBase();
> this.kbaseLastUpdated = System.currentTimeMillis();
> }
>
>
> /**
> * {@inheritDoc}
> */
> public DecisionSession createSession ()
> {
> return new DecisionSession(kBase.newStatefulKnowledgeSession());
> }
>
>
> /**
> * {@inheritDoc}
> */
> public DecisionSession updateSession (DecisionSession oldSession)
> {
> // Create a new session from the current KnowledgeBase
> DecisionSession newSession =
> new DecisionSession(kBase.newStatefulKnowledgeSession());
>
> if(oldSession != null)
> {
> // "Clean" the old session of all stateless facts before update
> oldSession.removeAllStatelessKnowledge();
> // Copy all remaining facts to the new session
> newSession.uploadKnowledge(new
> ArrayList(oldSession.getAllFacts()));
> }
> return newSession;
> }
>
>
> /**
> * {@inheritDoc}
> */
> public boolean isSessionStale(DecisionSession decisionSession)
> {
> if(decisionSession.getCreationTime() < this.kbaseLastUpdated)
> {
> return true;
> }
> else
> {
> return false;
> }
> }
>
>
> /**
> * Create a KnowledgeBuilder from a ChangeSet.
> *
> * @param changeSet - The ChangeSet
> * @return A KnowledgeBuilder
> * @throws IllegalArgumentException if changeSet is not a valid
> ChangeSet.
> */
> private KnowledgeAgent createKnowledgeAgent(
> String changeSet,
> KnowledgeBase kbase)
> {
> // Configure KnowledgeAgentFactory
> configureAgentFactory();
> // Create the knowledge agent
> KnowledgeAgent agent = KnowledgeAgentFactory.newKnowledgeAgent(
> "classificationAgent",
> kbase);
>
> agent.applyChangeSet(ResourceFactory.newClassPathResource(changeSet));
> // Add actionListener for detecting rule updates
> agent.addEventListener(new xKnowledgeAgentEventListener());
> // Start the monitoring...
> ResourceFactory.getResourceChangeNotifierService().start();
> ResourceFactory.getResourceChangeScannerService().start();
> return agent;
> }
>
>
> /**
> * Configure the agentFactory.
> */
> private void configureAgentFactory()
> {
> // Enable incremental knowledge base build - false means that the
> // old knowledge base is "reused" and updated when there are
> // updated rules. True means that the old base is discarded and a
> new
> // one is created
> KnowledgeAgentConfiguration kagentConf =
> KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
> kagentConf.setProperty("drools.agent.newInstance",
"false");
>
> // Configure the scanning interval - default is 60 sec.
> // (Scanning resources for changes...)
> ResourceChangeScannerConfiguration sconf =
>
>
ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
> sconf.setProperty("drools.resource.scanner.interval",
"30");
> ResourceFactory.getResourceChangeScannerService().configure(sconf);
> }
>
>
> /**
> * Create a KnowledgeBase. For CEP (Drools Fusion) decision service
> * use type = STATE_FULL otherwise use STATE_LESS.
> *
> * @param type - The type KnowledgeBase, state full or state less
> *
> * @return A KnowledgeBase
> */
> private KnowledgeBase createKnowledgeBase(DecisionSessionType type)
> {
> KnowledgeBase kbase;
> if(type.equals(DecisionSessionType.STATE_FULL)){
> KnowledgeBaseConfiguration config =
> KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
> config.setOption( EventProcessingOption.STREAM );
> kbase = KnowledgeBaseFactory.newKnowledgeBase( config );
> }
> else
> {
> kbase = KnowledgeBaseFactory.newKnowledgeBase();
> }
> return kbase;
> }
>
>
> /**
> * Get the ServiceType of this Service.
> *
> * @return The ServiceType of this service (STATE_FULL or STATE_LESS)
> */
> public DecisionSessionType getType ()
> {
> return type;
> }
>
>
> /**
> * When was the KnowledgeBase last updated.
> *
> * @return The timestamp (ms) for last update of KnowledgeBase
> */
> public long getLastUpdated()
> {
> return this.kbaseLastUpdated;
> }
>
>
> /**
> * Custom event listener for acting on events such as rule updates and
> * rule loading errors.
> */
> private class xKnowledgeAgentEventListener
> extends DefaultKnowledgeAgentEventListener
> {
>
> /**
> * Update the working copy of the KnowledgeBase when detecting
> * a updated one.
> *
> * @param event - The event signalling that the rule base has been
> updated
> */
> @Override
> public void knowledgeBaseUpdated (
> KnowledgeBaseUpdatedEvent event)
> {
> LOG.info("Detected updated rules! Rebuilding knowledgeBase!");
> long startTime = System.currentTimeMillis();
> kBase = kAgent.getKnowledgeBase();
> long endTime = System.currentTimeMillis();
> // Update the timestamp for when the knowledgeBase was updated
> kbaseLastUpdated = endTime;
> LOG.info("Rebuilding knowledgebase took " +
> (endTime - startTime) + "ms...");
> }
>
>
> /**
> * Log errors when problems updating the knowledge base.
> *
> * @param event - the Event signalling failure to load updated
> rules
> */
> @Override
> public void resourceCompilationFailed (
> ResourceCompilationFailedEvent event)
> {
> KnowledgeBuilderErrors errors =
> event.getKnowledgeBuilder().getErrors();
>
> if (errors.size() > 0)
> {
> LOG.error("Errors loading knowledge.");
> for (KnowledgeBuilderError error : errors)
> {
> LOG.error(error);
> }
> }
> }
> }
> }
>
>
>
>
>
> ________________________________________
> From: rules-users-bounces(a)lists.jboss.org [
> rules-users-bounces(a)lists.jboss.org] On Behalf Of Esteban Aliverti [
> esteban.aliverti(a)gmail.com]
> Sent: Monday, April 18, 2011 19:18
> To: Rules Users List
> Subject: Re: [rules-users] Dynamic updates of stateful sessions
>
> Maybe the new rules fail to compile. You can add an
> KnowledgeAgentEventListener to the agent to check for compilation errors.
> Could you post some code snippet showing how are you creating the kagent,
> the kbase, etc.
>
> You can take a look at some tests using newInstence=false here:
>
>
https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test...
>
> Best Regards,
>
> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>
> Esteban Aliverti
> - Developer @
http://www.plugtree.com
> - Blog @
http://ilesteban.wordpress.com
>
>
> On Mon, Apr 18, 2011 at 1:31 PM, Mattias Avelin <
> mattias.avelin@netlight.se<mailto:mattias.avelin@netlight.se>> wrote:
> Thanks for the swift reply!
>
> I have configured my Knowledge Agent to reuse the same KnowledgeBase (set
> drools.agent.newInstance property to "false" in my
> KnowledgeAgentConfiguration) as described in the Expert documentation. But
> my stateful session keeps using the old rules event though I can see from
> the log output that the Knowledgebase has been updated.
>
> /Mattias
> ________
> From: rules-users-bounces(a)lists.jboss.org<mailto:
> rules-users-bounces(a)lists.jboss.org> [rules-users-bounces(a)lists.jboss.org
> <mailto:rules-users-bounces@lists.jboss.org>] On Behalf Of Esteban
> Aliverti [esteban.aliverti@gmail.com<mailto:esteban.aliverti@gmail.com>]
> Sent: Monday, April 18, 2011 16:49
> To: Rules Users List
> Subject: Re: [rules-users] Dynamic updates of stateful sessions
>
> By default, the Knowledge Agent creates a new kbase when changes in the
> monitored resources are detected. So the stateful sessions you had are not
> going to "see" the changes because they belong to a different kbase.
> If you want the agent to apply the changes to the current kbase, you need
> to set drools.agent.newInstance property to "false" in knowledge agent
> configuration.
> You can read about this here:
>
http://ilesteban.wordpress.com/2010/03/25/knowledge-agent-incremental-cha...
>
> If you are defining the kagent using spring, you can use the "newInstence"
> attribute of <kagent> bean.
>
> Best Regards,
>
> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>
> Esteban Aliverti
> - Developer @
http://www.plugtree.com
> - Blog @
http://ilesteban.wordpress.com
>
>
> On Mon, Apr 18, 2011 at 11:41 AM, Mattias Avelin <
> mattias.avelin@netlight.se<mailto:mattias.avelin@netlight.se><mailto:
> mattias.avelin@netlight.se<mailto:mattias.avelin@netlight.se>>> wrote:
> We have a application in which we have both stateless & stateful sessions
> running. We're using the KnowledgeAgent and ChangeSets to automatically
> update our knowledge bases when the rules are changed.
> This works fine for our stateless sessions for which we are creating a new
> session for each request and if the rules have been updated this is
> reflected in next session we create.
>
> But for stateful sessions I'm not quite as sure on how to get it working.
> I
> can see in the logs that the KnowledgeBase is re-built when the
> KnowledgeAgent detects the updated rule files. But my "long running"
> session
> is does not reflect these changes (which it shouldn't right?). But how do
> we
> apply these changes to the stateful session without loosing all the facts
> I
> accumulated?
>
> The way I've solved it now is to keep a "last updated" timestamp for
the
> knowledgeBase and a "created" timestamp for the session and then compare
> these before using the session. If the knowledgeBase's "update
timestamp"
> is
> later that the sessions "creation timestamp" I create a new Session and
> then
> "manually" copy all facts from the former to the latter.
>
> Is this the way you would do this or is there a better way?
>
> Best Regards
>
> Mattias Avelin
>
>
> _______________________________________________
> rules-users mailing list
> rules-users@lists.jboss.org<mailto:rules-users@lists.jboss.org><mailto:
> rules-users@lists.jboss.org<mailto:rules-users@lists.jboss.org>>
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit
http://www.messagelabs.com/email
> ______________________________________________________________________
>
>
>
> _______________________________________________
> rules-users mailing list
> rules-users@lists.jboss.org<mailto:rules-users@lists.jboss.org>
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit
http://www.messagelabs.com/email
> ______________________________________________________________________
>
>
>
> _______________________________________________
> rules-users mailing list
> rules-users(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
_______________________________________________
rules-users mailing list
rules-users(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users