📄 fruleengine.java
字号:
/******************************************************************
* File: FRuleEngine.java
* Created by: Dave Reynolds
* Created on: 28-May-2003
*
* (c) Copyright 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development Company, LP
* [See end of file]
* $Id: FRuleEngine.java,v 1.27 2007/01/02 11:48:41 andy_seaborne Exp $
*****************************************************************/
package com.hp.hpl.jena.reasoner.rulesys.impl;
import com.hp.hpl.jena.reasoner.*;
import com.hp.hpl.jena.reasoner.rulesys.*;
import com.hp.hpl.jena.graph.*;
import java.util.*;
import com.hp.hpl.jena.util.OneToManyMap;
import com.hp.hpl.jena.util.PrintUtil;
import com.hp.hpl.jena.util.iterator.*;
import com.hp.hpl.jena.vocabulary.RDF;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The processing engine for forward production rules. It neeeds to reference
* an enclosing ForwardInfGraphI which holds the raw data and deductions.
*
* @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
* @version $Revision: 1.27 $ on $Date: 2007/01/02 11:48:41 $
*/
public class FRuleEngine implements FRuleEngineI {
/** The parent InfGraph which is employing this engine instance */
protected ForwardRuleInfGraphI infGraph;
/** Set of rules being used */
protected List rules;
/** Map from predicate node to rule + clause, Node_ANY is used for wildcard predicates */
protected OneToManyMap clauseIndex;
/** List of predicates used in rules to assist in fast data loading */
protected HashSet predicatesUsed;
/** Flag, if true then there is a wildcard predicate in the rule set so that selective insert is not useful */
protected boolean wildcardRule;
/** Set to true to flag that derivations should be logged */
protected boolean recordDerivations;
/** performance stats - number of rules passing initial trigger */
int nRulesTriggered = 0;
/** performance stats - number of rules fired */
long nRulesFired = 0;
/** performance stats - number of rules fired during axiom initialization */
long nAxiomRulesFired = -1;
/** True if we have processed the axioms in the rule set */
boolean processedAxioms = false;
protected static Log logger = LogFactory.getLog(FRuleEngine.class);
// =======================================================================
// Constructors
/**
* Constructor.
* @param parent the F or FB infGraph that it using this engine, the parent graph
* holds the deductions graph and source data.
* @param rules the rule set to be processed
*/
public FRuleEngine(ForwardRuleInfGraphI parent, List rules) {
infGraph = parent;
this.rules = rules;
}
/**
* Constructor. Build an empty engine to which rules must be added
* using setRuleStore().
* @param parent the F or FB infGraph that it using this engine, the parent graph
* holds the deductions graph and source data.
*/
public FRuleEngine(ForwardRuleInfGraphI parent) {
infGraph = parent;
}
// =======================================================================
// Control methods
/**
* Process all available data. This should be called once a deductions graph
* has be prepared and loaded with any precomputed deductions. It will process
* the rule axioms and all relevant existing exiting data entries.
* @param ignoreBrules set to true if rules written in backward notation should be ignored
* @param inserts the set of triples to be processed, normally this is the
* raw data graph but may include additional deductions made by preprocessing hooks
*/
public void init(boolean ignoreBrules, Finder inserts) {
if (clauseIndex == null) compile(rules, ignoreBrules);
findAndProcessAxioms();
nAxiomRulesFired = nRulesFired;
logger.debug("Axioms fired " + nAxiomRulesFired + " rules");
fastInit(inserts);
}
/**
* Process all available data. This version expects that all the axioms
* have already be preprocessed and the clause index already exists.
* @param inserts the set of triples to be processed, normally this is the
* raw data graph but may include additional deductions made by preprocessing hooks
*/
public void fastInit(Finder inserts) {
findAndProcessActions();
// Create the reasoning context
BFRuleContext context = new BFRuleContext(infGraph);
// Insert the data
if (wildcardRule) {
for (Iterator i = inserts.find(new TriplePattern(null, null, null)); i.hasNext(); ) {
context.addTriple((Triple)i.next());
}
} else {
for (Iterator p = predicatesUsed.iterator(); p.hasNext(); ) {
Node predicate = (Node)p.next();
for (Iterator i = inserts.find(new TriplePattern(null, predicate, null)); i.hasNext(); ) {
context.addTriple((Triple)i.next());
}
}
}
// Run the engine
addSet(context);
}
/**
* Add one triple to the data graph, run any rules triggered by
* the new data item, recursively adding any generated triples.
*/
public synchronized void add(Triple t) {
BFRuleContext context = new BFRuleContext(infGraph);
context.addTriple(t);
addSet(context);
}
/**
* Remove one triple to the data graph.
* @return true if the effects could be correctly propagated or
* false if not (in which case the entire engine should be restarted).
*/
public synchronized boolean delete(Triple t) {
// Incremental delete not supported
return false;
}
/**
* Return the number of rules fired since this rule engine instance
* was created and initialized
*/
public long getNRulesFired() {
return nRulesFired;
}
/**
* Return true if the internal engine state means that tracing is worthwhile.
* It will return false during the axiom bootstrap phase.
*/
public boolean shouldTrace() {
// return processedAxioms;
return true;
}
/**
* Set to true to enable derivation caching
*/
public void setDerivationLogging(boolean recordDerivations) {
this.recordDerivations = recordDerivations;
}
/**
* Access the precomputed internal rule form. Used when precomputing the
* internal axiom closures.
*/
public Object getRuleStore() {
return new RuleStore(clauseIndex, predicatesUsed, wildcardRule);
}
/**
* Set the internal rule from from a precomputed state.
*/
public void setRuleStore(Object ruleStore) {
RuleStore rs = (RuleStore)ruleStore;
clauseIndex = rs.clauseIndex;
predicatesUsed = rs.predicatesUsed;
wildcardRule = rs.wildcardRule;
}
// =======================================================================
// Internal methods
/**
* Add a set of new triple to the data graph, run any rules triggered by
* the new data item, recursively adding any generated triples.
* Technically the triples having been physically added to either the
* base or deduction graphs and the job of this function is just to
* process the stack of additions firing any relevant rules.
* @param context a context containing a set of new triples to be added
*/
public void addSet(BFRuleContext context) {
Triple t;
while ((t = context.getNextTriple()) != null) {
if (infGraph.shouldTrace()) {
logger.info("Processing: " + PrintUtil.print(t));
}
// Check for rule triggers
HashSet firedRules = new HashSet();
Iterator i1 = clauseIndex.getAll(t.getPredicate());
Iterator i2 = clauseIndex.getAll(Node.ANY);
Iterator i = new ConcatenatedIterator(i1, i2);
while (i.hasNext()) {
ClausePointer cp = (ClausePointer) i.next();
if (firedRules.contains(cp.rule)) continue;
context.resetEnv( cp.rule.getNumVars() );
TriplePattern trigger = (TriplePattern) cp.rule.getBodyElement(cp.index);
if (match(trigger, t, context.getEnvStack())) {
nRulesTriggered++;
context.setRule(cp.rule);
if (matchRuleBody(cp.index, context)) {
firedRules.add(cp.rule);
nRulesFired++;
}
}
}
}
}
/**
* Compile a list of rules into the internal rule store representation.
* @param rules the list of Rule objects
* @param ignoreBrules set to true if rules written in backward notation should be ignored
* @return an object that can be installed into the engine using setRuleStore.
*/
public void compile(List rules, boolean ignoreBrules) {
clauseIndex = new OneToManyMap();
predicatesUsed = new HashSet();
wildcardRule = false;
for (Iterator i = rules.iterator(); i.hasNext(); ) {
Rule r = (Rule)i.next();
if (ignoreBrules && r.isBackward()) continue;
Object[] body = r.getBody();
for (int j = 0; j < body.length; j++) {
if (body[j] instanceof TriplePattern) {
Node predicate = ((TriplePattern) body[j]).getPredicate();
ClausePointer cp = new ClausePointer(r, j);
if (predicate.isVariable()) {
clauseIndex.put(Node.ANY, cp);
wildcardRule = true;
} else {
clauseIndex.put(predicate, cp);
if (! wildcardRule) {
predicatesUsed.add(predicate);
}
}
}
}
}
if (wildcardRule) predicatesUsed = null;
}
/**
* Scan the rules for any axioms and insert those
*/
protected void findAndProcessAxioms() {
BFRuleContext context = new BFRuleContext(infGraph);
for (Iterator i = rules.iterator(); i.hasNext(); ) {
Rule r = (Rule)i.next();
if (r.bodyLength() == 0) {
// An axiom
for (int j = 0; j < r.headLength(); j++) {
Object head = r.getHeadElement(j);
if (head instanceof TriplePattern) {
TriplePattern h = (TriplePattern) head;
Triple t = new Triple(h.getSubject(), h.getPredicate(), h.getObject());
context.addTriple(t);
infGraph.getDeductionsGraph().add(t);
}
}
}
}
addSet(context);
processedAxioms = true;
}
/**
* Scan the rules for any actions and run those
*/
protected void findAndProcessActions() {
BFRuleContext context = new BFRuleContext(infGraph);
for (Iterator i = rules.iterator(); i.hasNext(); ) {
Rule r = (Rule)i.next();
if (r.bodyLength() == 0) {
// An axiom
for (int j = 0; j < r.headLength(); j++) {
Object head = r.getHeadElement(j);
if (head instanceof Functor) {
Functor f = (Functor)head;
Builtin imp = f.getImplementor();
if (imp != null) {
context.setRule(r);
imp.headAction(f.getArgs(), f.getArgLength(), context);
} else {
throw new ReasonerException("Invoking undefined Functor " + f.getName() +" in " + r.toShortString());
}
}
}
}
}
}
/**
* Match the rest of a set of rule clauses once an initial rule
* trigger has fired. Carries out any actions as a side effect.
* @param trigger the index of the clause which has already be successfully matched
* @param context a context containing a set of new triples to be added
* @return true if the rule actually fires
*/
private boolean matchRuleBody(int trigger, BFRuleContext context) {
Rule rule = context.getRule();
// Create an ordered list of body clauses to process, best at the end
Object[] body = rule.getBody();
int len = body.length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -