com.bigdata.rdf.rules.AbstractRuleDistinctTermScan Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Oct 29, 2007
*/
package com.bigdata.rdf.rules;
import java.io.Serializable;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstraint;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.bindingSet.ListBindingSet;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.spo.SPOKeyOrder;
import com.bigdata.rdf.spo.SPOPredicate;
import com.bigdata.rdf.spo.SPORelation;
import com.bigdata.relation.accesspath.IBuffer;
import com.bigdata.relation.rule.IRule;
import com.bigdata.relation.rule.Rule;
import com.bigdata.relation.rule.eval.IJoinNexus;
import com.bigdata.relation.rule.eval.IRuleTaskFactory;
import com.bigdata.relation.rule.eval.ISolution;
import com.bigdata.relation.rule.eval.IStepTask;
import com.bigdata.relation.rule.eval.RuleStats;
import com.bigdata.striterator.IChunkedIterator;
/**
* Base class for rules having a single predicate that is none bound in the tail
* and a single variable in the head. These rules can be evaluated using a
* distinctTermScan rather than a full index scan. For example:
*
*
* rdf1: (?u ?a ?y) -> (?a rdf:type rdf:Property)
* rdfs4a: (?u ?a ?x) -> (?u rdf:type rdfs:Resource)
* rdfs4b: (?u ?a ?v) -> (?v rdf:type rdfs:Resource)
*
*
* @author Bryan Thompson
* @version $Id: AbstractRuleDistinctTermScan.java 3448 2010-08-18 20:55:58Z
* thompsonbry $
*/
abstract public class AbstractRuleDistinctTermScan extends Rule {
/**
* The sole unbound variable in the head of the rule.
*/
private final IVariable h;
/**
* The access path that corresponds to the position of the unbound variable
* reference from the head.
*/
private final SPOKeyOrder keyOrder;
private final IRuleTaskFactory taskFactory;
public AbstractRuleDistinctTermScan(String name, SPOPredicate head,
SPOPredicate[] body, IConstraint[] constraints) {
super(name, head, body, constraints);
// head must be one unbound; that variable will be bound by the scan.
assert head.getVariableCount() == 1;
// tail must have one predicate.
assert body.length == 1;
// the predicate in the tail must be "none" bound.
// assert body[0].getVariableCount() == IRawTripleStore.N;
assert body[0].getVariableCount() == body[0].arity();//head.arity();
// figure out which position in the head is the variable.
if(head.s().isVar()) {
h = (IVariable)head.s();
} else if( head.p().isVar() ) {
h = (IVariable)head.p();
} else if( head.o().isVar() ) {
h = (IVariable)head.o();
} else {
throw new AssertionError();
}
/*
* figure out which access path we need for the distinct term scan which
* will bind the variable in the head.
*/
if (body[0].s() == h) {
keyOrder = SPOKeyOrder.SPO;
} else if (body[0].p() == h) {
keyOrder = SPOKeyOrder.POS;
} else if (body[0].o() == h) {
keyOrder = SPOKeyOrder.OSP;
} else {
throw new AssertionError();
}
taskFactory = new DistinctTermScanRuleTaskFactory(h, keyOrder);
}
/**
* Factory for custom evaluation of the distinct term scan rule.
*
* @author Bryan Thompson
* @version $Id$
*/
private static class DistinctTermScanRuleTaskFactory implements
IRuleTaskFactory {
/**
*
*/
private static final long serialVersionUID = 3290328271137950004L;
/**
* The sole unbound variable in the head of the rule.
*/
private final IVariable h;
/**
* The access path that corresponds to the position of the unbound
* variable reference from the head.
*/
private final SPOKeyOrder keyOrder;
public DistinctTermScanRuleTaskFactory(IVariable h,
SPOKeyOrder keyOrder) {
this.h = h;
this.keyOrder = keyOrder;
}
public IStepTask newTask(IRule rule, IJoinNexus joinNexus,
IBuffer buffer) {
return new DistinctTermScan(rule, joinNexus, buffer, h,
keyOrder);
}
}
public IRuleTaskFactory getTaskFactory() {
return taskFactory;
}
/**
* Selects the distinct term identifiers, substituting their binding in the
* sole unbound variable in the head of the rule.
*/
protected static class DistinctTermScan implements IStepTask, Serializable {
/**
*
*/
private static final long serialVersionUID = -7570511260700545025L;
private final IJoinNexus joinNexus;
private final IBuffer buffer;
private final IRule rule;
/**
* The sole unbound variable in the head of the rule.
*/
private final IVariable h;
/**
* The access path that corresponds to the position of the unbound variable
* reference from the head.
*/
private final SPOKeyOrder keyOrder;
/**
*
* @param rule
* The rule (may have been specialized).
* @param joinNexus
* @param buffer
* The buffer on which the {@link ISolution}s will be
* written.
* @param h
* The sole unbound variable in the head of the rule.
* @param keyOrder
* The access path that corresponds to the position of the
* unbound variable reference from the head.
*/
public DistinctTermScan(final IRule rule, final IJoinNexus joinNexus,
final IBuffer buffer, final IVariable h,
final SPOKeyOrder keyOrder) {
if (rule == null)
throw new IllegalArgumentException();
if (joinNexus == null)
throw new IllegalArgumentException();
if (buffer == null)
throw new IllegalArgumentException();
if (h == null)
throw new IllegalArgumentException();
if (keyOrder == null)
throw new IllegalArgumentException();
this.rule = rule;
this.joinNexus = joinNexus;
this.buffer = buffer;
this.h = h;
this.keyOrder = keyOrder;
}
public RuleStats call() {
final long computeStart = System.currentTimeMillis();
/*
* Note: Since this task is always applied to a single tail rule,
* the {@link TMUtility} rewrite of the rule will always read from
* the focusStore alone. This makes the choice of the relation on
* which to read easy - just read on whichever relation is specified
* for tail[0].
*/
// final String relationName = rule.getHead().getOnlyRelationName();
//
// /*
// * find the distinct predicates in the KB (efficient op).
// */
// final long timestamp = joinNexus.getReadTimestamp(relationName);
//
// final SPORelation relation = (SPORelation) joinNexus
// .getIndexManager().getResourceLocator().locate(
// relationName, timestamp);
final SPORelation relation = (SPORelation) joinNexus
.getTailRelationView(rule.getTail(0));
// final SPOAccessPath accessPath = relation.getAccessPath(
// keyOrder, rule.getTail(0));
// IAccessPath accessPath = state.focusStore == null ? state.database
// .getAccessPath(keyOrder) : state.focusStore
// .getAccessPath(keyOrder);
final RuleStats ruleStats = joinNexus.getRuleStatisticsFactory().newInstance(rule);
// there is only a single unbound variable for this rule.
final IBindingSet bindingSet = new ListBindingSet(/*1 capacity*/);
final IChunkedIterator itr = relation.distinctTermScan(keyOrder);
try {
while (itr.hasNext()) {
// Note: chunks are in ascending order since using scan on SPO index.
final IV[] chunk = itr.nextChunk();
ruleStats.chunkCount[0]++;
ruleStats.elementCount[0] += chunk.length;
final IBuffer tmp = joinNexus
.newUnsynchronizedBuffer(buffer, chunk.length);
for (IV iv : chunk) {
// [id] is a distinct term identifier for the selected
// access path.
/*
* bind the unbound variable in the head of the rule.
*
* Note: This explicitly leaves the other variables in
* the head unbound so that the justifications will be
* wildcards for those variables.
*/
bindingSet.set(h, new Constant(iv));
if (rule.isConsistent(bindingSet)) {
tmp.add(joinNexus.newSolution(rule, bindingSet));
ruleStats.solutionCount.incrementAndGet();
}
}
// flush results onto the chunked solution buffer.
tmp.flush();
}
} finally {
itr.close();
ruleStats.elapsed += System.currentTimeMillis() - computeStart;
}
return ruleStats;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy