/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
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
*/
package com.bigdata.rdf.spo;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import com.bigdata.bop.BOp;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.IVariableOrConstant;
import com.bigdata.bop.Var;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.IVUtility;
import com.bigdata.relation.rule.IStarJoin;
/**
* Implementation of a star join for SPOs. See {@link IStarJoin}.
*
* @author <a href="mailto:mrpersonick@users.sourceforge.net">Mike Personick</a>
*/
public class SPOStarJoin extends SPOPredicate
implements IStarJoin<ISPO>, Serializable {
/**
* generated serial version UID
*/
private static final long serialVersionUID = 981603459301801862L;
public interface Annotations extends SPOPredicate.Annotations {
}
/**
* The star constraints for this star join.
*
* @todo {@link IStarConstraint} should probably be a {@link BOp} and this
* should probably be an annotation.
*/
private final Collection<IStarConstraint<ISPO>> starConstraints = new LinkedList<IStarConstraint<ISPO>>();
/**
* Required shallow copy constructor.
*/
public SPOStarJoin(final BOp[] values, final Map<String, Object> annotations) {
super(values, annotations);
}
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public SPOStarJoin(final SPOStarJoin op) {
super(op);
}
/**
* Construct an SPO star join from a normal SPO predicate. The star join
* will have a triple pattern of (S,?,?) instead of the (S,P,O) from the
* original SPO predicate. This way all SPOs for the common subject are
* considered. SPO star constraints must be added later to make this
* star join selective.
*
* @param pred
* the normal SPO predicate from which to pull the S
*/
public SPOStarJoin(final SPOPredicate pred) {
super(pred.arity() == 3 ? new BOp[] { pred.s(), Var.var(), Var.var() }
: new BOp[] { pred.s(), Var.var(), Var.var(), pred.c() },
deepCopy(pred.annotations()));
// this(new String[] { pred.getOnlyRelationName() }, pred.getPartitionId(),
// pred.s(), // s
// (IVariableOrConstant<IV>) Var.var(), // p
// (IVariableOrConstant<IV>) Var.var(), // o
// pred.c(), // c
// pred.isOptional(), pred.getConstraint(),
// pred.getSolutionExpander());
}
// /**
// * Create an SPO star join over the given relation for the given subject.
// *
// * @param relationName
// * the name of the SPO relation to use
// * @param s
// * the subject of this star join
// */
// public SPOStarJoin(final String relationName,
// final IVariableOrConstant<IV> s) {
//
// super(new BOp[] { s, Var.var(), Var.var(), null /* c */}, NV
// .asMap(new NV[] { new NV(Annotations.RELATION_NAME,
// relationName) }));
//// this(new String[] { relationName }, -1/* partitionId */,
//// s,
//// (IVariableOrConstant<IV>) Var.var(), // p
//// (IVariableOrConstant<IV>) Var.var(), // o
//// null, // c
//// false/* optional */, null/* constraint */, null/* expander */);
//
// }
// /**
// * Fully specified ctor.
// *
// * @param relationName
// * @param partitionId
// * @param s
// * @param p
// * @param o
// * @param c
// * MAY be <code>null</code>.
// * @param optional
// * @param constraint
// * MAY be <code>null</code>.
// * @param expander
// * MAY be <code>null</code>.
// */
// public SPOStarJoin(final String[] relationName, //
// final int partitionId, //
// final IVariableOrConstant<IV> s,//
// final IVariableOrConstant<IV> p,//
// final IVariableOrConstant<IV> o,//
// final IVariableOrConstant<IV> c,//
// final boolean optional, //
// final IElementFilter<ISPO> constraint,//
// final ISolutionExpander<ISPO> expander//
// ) {
//
// super(relationName, partitionId, s, p, o, c, optional, constraint,
// expander);
//
// }
/**
* Add an SPO star constraint to this star join.
*/
public void addStarConstraint(IStarConstraint<ISPO> constraint) {
starConstraints.add(constraint);
}
/**
* Return an iterator over the SPO star constraints for this star join.
*/
public Iterator<IStarConstraint<ISPO>> getStarConstraints() {
return starConstraints.iterator();
}
/**
* Return the number of star constraints for this star join.
*/
public int getNumStarConstraints() {
return starConstraints.size();
}
/**
* Return an iterator over the constraint variables for this star join.
*/
public Iterator<IVariable> getConstraintVariables() {
final Set<IVariable> vars = new HashSet<IVariable>();
for (IStarConstraint constraint : starConstraints) {
if (((SPOStarConstraint) constraint).p.isVar()) {
vars.add((IVariable) ((SPOStarConstraint) constraint).p);
}
if (((SPOStarConstraint) constraint).o.isVar()) {
vars.add((IVariable) ((SPOStarConstraint) constraint).o);
}
}
return vars.iterator();
}
/**
* Return an as-bound version of this star join and its star contraints
* using the supplied binding set.
*/
@Override
public SPOPredicate asBound(IBindingSet bindingSet) {
final SPOStarJoin starJoin = (SPOStarJoin) super.asBound(bindingSet);
for (IStarConstraint starConstraint : starConstraints) {
starJoin.addStarConstraint(starConstraint.asBound(bindingSet));
}
return starJoin;
}
@Override
public String toString(final IBindingSet bindingSet) {
final StringBuilder sb = new StringBuilder(super.toString(bindingSet));
if (starConstraints.size() > 0) {
sb.append("star[");
for (IStarConstraint sc : starConstraints) {
sb.append(sc);
sb.append(",");
}
sb.setCharAt(sb.length()-1, ']');
}
return sb.toString();
}
/**
* Implementation of a star constraint for SPOs. Constraint will specify
* a P and O (variable or constant) and whether the constraint is optional
* or non-optional.
*/
public static class SPOStarConstraint implements IStarConstraint<ISPO>,
Serializable {
/**
* generated serial version UID
*/
private static final long serialVersionUID = 997244773880938817L;
/**
* Variable or constant P for the constraint.
*/
protected final IVariableOrConstant<IV> p;
/**
* Variable or constant O for the constraint.
*/
protected final IVariableOrConstant<IV> o;
/**
* Is the constraint optional or non-optional.
*/
protected final boolean optional;
/**
* Construct a non-optional SPO star constraint using the supplied P and
* O.
*
* @param p
* @param o
*/
public SPOStarConstraint(final IVariableOrConstant<IV> p,
final IVariableOrConstant<IV> o) {
this(p, o, false /* optional */);
}
/**
* Fully specified ctor.
*
* @param p
* @param o
* @param optional
*/
public SPOStarConstraint(final IVariableOrConstant<IV> p,
final IVariableOrConstant<IV> o, final boolean optional) {
this.p = p;
this.o = o;
this.optional = optional;
}
final public IVariableOrConstant<IV> p() {
return p;
}
final public IVariableOrConstant<IV> o() {
return o;
}
final public boolean isOptional() {
return optional;
}
final public int getNumVars() {
return (p.isVar() ? 1 : 0) + (o.isVar() ? 1 : 0);
}
/**
* Tests the P and O of the supplied SPO against the constraint. Return
* true for a match.
*/
final public boolean isMatch(ISPO spo) {
return ((p.isVar() || IVUtility.equals(p.get(), spo.p())) &&
(o.isVar() || IVUtility.equals(o.get(), spo.o())));
}
/**
* Use the supplied SPO to create variable bindings for supplied
* binding set.
*/
final public void bind(IBindingSet bs, ISPO spo) {
if (p.isVar()) {
bs.set((IVariable) p,
new Constant<IV>(spo.p()));
}
if (o.isVar()) {
bs.set((IVariable) o,
new Constant<IV>(spo.o()));
}
}
/**
* Return an as-bound version of this SPO star constraint for the
* supplied binding set.
*/
public IStarConstraint<ISPO> asBound(IBindingSet bindingSet) {
final IVariableOrConstant<IV> p;
{
if (this.p.isVar() && bindingSet.isBound((IVariable)this.p)) {
p = bindingSet.get((IVariable) this.p);
} else {
p = this.p;
}
}
final IVariableOrConstant<IV> o;
{
if (this.o.isVar() && bindingSet.isBound((IVariable) this.o)) {
o = bindingSet.get((IVariable) this.o);
} else {
o = this.o;
}
}
return new SPOStarConstraint(p, o, optional);
}
public String toString() {
return toString(null);
}
public String toString(final IBindingSet bindingSet) {
final StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(p.isConstant() || bindingSet == null
|| !bindingSet.isBound((IVariable) p) ? p.toString()
: bindingSet.get((IVariable) p));
sb.append(", ");
sb.append(o.isConstant() || bindingSet == null
|| !bindingSet.isBound((IVariable) o) ? o.toString()
: bindingSet.get((IVariable) o));
sb.append(")");
if (optional) {
/*
* Something special, so do all this stuff.
*/
sb.append("[");
if(optional) {
sb.append("optional");
}
sb.append("]");
}
return sb.toString();
}
}
}