All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.inf.OwlSameAsPropertiesExpandingIterator Maven / Gradle / Ivy

package com.bigdata.rdf.inf;

import java.util.Arrays;

import org.apache.log4j.Logger;

import com.bigdata.bop.BOp;
import com.bigdata.bop.BOpBase;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstant;
import com.bigdata.bop.IConstraint;
import com.bigdata.bop.IPredicate;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.IVariableOrConstant;
import com.bigdata.bop.Var;
import com.bigdata.bop.constraint.BooleanValueExpression;
import com.bigdata.bop.constraint.Constraint;
import com.bigdata.bop.joinGraph.IEvaluationPlan;
import com.bigdata.bop.joinGraph.IEvaluationPlanFactory;
import com.bigdata.bop.joinGraph.fast.DefaultEvaluationPlanFactory2;
import com.bigdata.btree.IIndex;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.IVUtility;
import com.bigdata.rdf.rules.RuleContextEnum;
import com.bigdata.rdf.spo.ISPO;
import com.bigdata.rdf.spo.SPO;
import com.bigdata.rdf.spo.SPOKeyOrder;
import com.bigdata.rdf.spo.SPOPredicate;
import com.bigdata.rdf.store.AbstractTripleStore;
import com.bigdata.relation.accesspath.IAccessPath;
import com.bigdata.relation.rule.IAccessPathExpander;
import com.bigdata.relation.rule.IRule;
import com.bigdata.relation.rule.QueryOptions;
import com.bigdata.relation.rule.Rule;
import com.bigdata.relation.rule.eval.ActionEnum;
import com.bigdata.relation.rule.eval.IJoinNexus;
import com.bigdata.relation.rule.eval.IJoinNexusFactory;
import com.bigdata.relation.rule.eval.ISolution;
import com.bigdata.striterator.ChunkedArrayIterator;
import com.bigdata.striterator.IChunkedOrderedIterator;
import com.bigdata.striterator.IKeyOrder;

public class OwlSameAsPropertiesExpandingIterator implements
        IChunkedOrderedIterator {
    protected final static Logger log =
            Logger.getLogger(OwlSameAsPropertiesExpandingIterator.class);

    private final IChunkedOrderedIterator src;

    private final IKeyOrder keyOrder;

    private final IV s, p, o;

    private final AbstractTripleStore db;

    private final IV sameAs;

    private IChunkedOrderedIterator solutions;

    private IAccessPathExpander sameAsSelfExpander;

    public OwlSameAsPropertiesExpandingIterator(IV s, IV p, IV o,
            AbstractTripleStore db, final IV sameAs,
            final IKeyOrder keyOrder) {
        this.db = db;
        this.s = s;
        this.p = p;
        this.o = o;
        this.sameAs = sameAs;
        this.keyOrder = keyOrder;
        this.sameAsSelfExpander = new SameAsSelfExpander();
        if (p == sameAs) {
            // we don't need to run the expander when the predicate is
            // owl:sameAs, the forward chainer takes care of that case
            this.src = db.getAccessPath(s, p, o).iterator();
        } else {
            this.src = null;
            try {
                if (s != null && o != null) {
                    accessSPO();
                } else if (s != null && o == null) {
                    accessSP();
                } else if (s == null && o != null) {
                    accessPO();
                } else if (s == null && o == null) {
                    accessP();
                } else
                    throw new AssertionError();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    private void accessSPO() throws Exception {
        /*
         construct S ?p O
         where {
         ?sameS sameAs S .
         ?sameO sameAs O .
         ?sameS ?p ?sameO
         }
         */
        final String SPO = db.getSPORelation().getNamespace();
        final IVariable _sameS = Var.var("sameS");
        final IVariable _sameO = Var.var("sameO");
        final IConstant sameAs = new Constant(this.sameAs);
        final IConstant s = new Constant(this.s);
        final IConstant o = new Constant(this.o);
        final IVariableOrConstant _p =
                this.p != null ? new Constant(this.p) : Var.var("p");
        final SPOPredicate head = new SPOPredicate(SPO, s, _p, o);
        final IRule rule =
                new Rule("sameAsSPO", head, new IPredicate[] {
                        new SPOPredicate(SPO, _sameS, sameAs, s,
                                sameAsSelfExpander),
                        new SPOPredicate(SPO, _sameO, sameAs, o,
                                sameAsSelfExpander),
                        new SPOPredicate(SPO, _sameS, _p, _sameO) },
                        QueryOptions.DISTINCT, // distinct
                        // constraints on the rule.
                        new IConstraint[] { Constraint.wrap(new RejectSameAsSelf(head.s(), head
                                .p(), head.o())) });
        runQuery(rule);
    }

    private void accessSP() throws Exception {
        /*
         construct S ?p ?sameO
         where {
         ?sameS sameAs S .
         ?sameS ?p ?o .
         ?o sameAs ?sameO
         }
         */
        final String SPO = db.getSPORelation().getNamespace();
        final IVariable _sameS = Var.var("sameS");
        final IVariable _sameO = Var.var("sameO");
        final IConstant sameAs = new Constant(this.sameAs);
        final IConstant s = new Constant(this.s);
        final IVariable _o = Var.var("o");
        final IVariableOrConstant _p =
                this.p != null ? new Constant(this.p) : Var.var("p");
        final SPOPredicate head = new SPOPredicate(SPO, s, _p, _sameO);
        final IRule rule =
                new Rule("sameAsSP", head, new IPredicate[] {
                        new SPOPredicate(SPO, _sameS, sameAs, s,
                                sameAsSelfExpander), // ?s sameAs y
                        new SPOPredicate(SPO, _sameS, _p, _o), // ?s b ?o  -> y b w
                        new SPOPredicate(SPO, _o, sameAs, _sameO, true,
                                sameAsSelfExpander) },
                        QueryOptions.DISTINCT, // distinct
                        // constraints on the rule.
                        new IConstraint[] { Constraint.wrap(new RejectSameAsSelf(head.s(), head
                                .p(), head.o())) });
        runQuery(rule);
    }

    private void accessPO() throws Exception {
        /*
         construct ?sameS ?p O
         where {
         ?sameO sameAs O .
         ?s ?p ?sameO .
         ?s sameAs ?sameS
         }
         */
        final String SPO = db.getSPORelation().getNamespace();
        final IVariable _sameS = Var.var("sameS");
        final IVariable _sameO = Var.var("sameO");
        final IConstant sameAs = new Constant(this.sameAs);
        final IVariable _s = Var.var("s");
        final IConstant o = new Constant(this.o);
        final IVariableOrConstant _p =
                this.p != null ? new Constant(this.p) : Var.var("p");
        final SPOPredicate head = new SPOPredicate(SPO, _sameS, _p, o);
        final IRule rule =
                new Rule("sameAsPO", head, new IPredicate[] {
                        new SPOPredicate(SPO, _sameO, sameAs, o,
                                sameAsSelfExpander),
                        new SPOPredicate(SPO, _s, _p, _sameO),
                        new SPOPredicate(SPO, _s, sameAs, _sameS, true,
                                sameAsSelfExpander) }, 
                        QueryOptions.DISTINCT, // distinct
                        // constraints on the rule.
                        new IConstraint[] { Constraint.wrap(new RejectSameAsSelf(head.s(), head
                                .p(), head.o())) });
        runQuery(rule);
    }

    private void accessP() throws Exception {
        /*
         construct ?sameS ?p ?sameO
         where {
         ?s sameAs ?sameS .
         ?o sameAs ?sameO .
         ?s ?p ?o
         }
         */
        final String SPO = db.getSPORelation().getNamespace();
        final IVariable _sameS = Var.var("sameS");
        final IVariable _sameO = Var.var("sameO");
        final IConstant sameAs = new Constant(this.sameAs);
        final IVariable _s = Var.var("s");
        final IVariable _o = Var.var("o");
        final IVariableOrConstant _p =
                this.p != null ? new Constant(this.p) : Var.var("p");
        final SPOPredicate head = new SPOPredicate(SPO, _sameS, _p, _sameO);
        final IRule rule =
                new Rule("sameAsP", head, new IPredicate[] {
                        new SPOPredicate(SPO, _sameS, sameAs, _s, true, 
                                sameAsSelfExpander),
                        new SPOPredicate(SPO, _sameO, sameAs, _o, true,
                                sameAsSelfExpander),
                        new SPOPredicate(SPO, _s, _p, _o) }, 
                        QueryOptions.DISTINCT, // distinct
                        // constraints on the rule.
                        new IConstraint[] { Constraint.wrap(new RejectSameAsSelf(head.s(), head
                                .p(), head.o())) });
        runQuery(rule);
    }

    private void runQuery(IRule rule)
            throws Exception {
        // run the query as a native rule.
        final IEvaluationPlanFactory planFactory =
                DefaultEvaluationPlanFactory2.INSTANCE;
        final IJoinNexusFactory joinNexusFactory =
                db.newJoinNexusFactory(RuleContextEnum.HighLevelQuery,
                        ActionEnum.Query, IJoinNexus.ELEMENT, null, // filter
                        false, // justify 
                        false, // backchain
                        planFactory);
        final IJoinNexus joinNexus =
                joinNexusFactory.newInstance(db.getIndexManager());
        if (log.isInfoEnabled()) {
            final IEvaluationPlan plan = planFactory.newPlan(joinNexus, rule);
            StringBuilder sb = new StringBuilder();
            int order[] = plan.getOrder();
            for (int i = 0; i < order.length; i++) {
                sb.append(order[i]);
                if (i < order.length - 1) {
                    sb.append(",");
                }
            }
            log.info("order: [" + sb.toString() + "]");
        }
        this.solutions = joinNexus.runQuery(rule);
        // this.resolverator = resolverator;
    }

    public IKeyOrder getKeyOrder() {
        if (src != null) {
            return src.getKeyOrder();
        }
        return keyOrder;
    }

    private ISPO[] chunk;

    private int i = 0;

    public ISPO[] nextChunk() {
        if (src != null) {
            return src.nextChunk();
        }
        final int chunkSize = 10000;
        ISPO[] s = new ISPO[chunkSize];
        int n = 0;
        while (hasNext() && n < chunkSize) {
            ISolution solution = solutions.next();
            // s[n++] = resolverator.resolve(solution);
            ISPO spo = solution.get();
            spo = new SPO(spo.s(), spo.p(), spo.o());
            s[n++] = spo;
        }
        
        // copy so that stmts[] is dense.
        ISPO[] stmts = new ISPO[n];
        System.arraycopy(s, 0, stmts, 0, n);
        
        // fill in the explicit/inferred information, sort by SPO key order
        // since we will use the SPO index to do the value completion
        stmts = db.bulkCompleteStatements(stmts);
        
        // resort into desired order
        Arrays.sort(stmts, 0, n, this.keyOrder.getComparator());
        
        return stmts;
    }

    public ISPO[] nextChunk(IKeyOrder keyOrder) {
        if (src != null) {
            return src.nextChunk(keyOrder);
        }
        if (keyOrder == null)
            throw new IllegalArgumentException();
        ISPO[] stmts = nextChunk();
        if (this.keyOrder != keyOrder) {
            // sort into the required order.
            Arrays.sort(stmts, 0, stmts.length, keyOrder.getComparator());
        }
        return stmts;
    }

    public ISPO next() {
        if (src != null) {
            return src.next();
        }
        if (chunk == null || i == chunk.length) {
            chunk = nextChunk();
            i = 0;
            if (log.isInfoEnabled()) 
                log.info("got a chunk, length = " + chunk.length);
        }
        return chunk[i++];
    }

    public void remove() {
        if (src != null) {
            src.remove();
            return;
        }
        throw new UnsupportedOperationException();
    }

    public void close() {
        if (src != null) {
            src.close();
            return;
        }
        if (solutions != null) {
            solutions.close();
        }
    }

    public boolean hasNext() {
        if (src != null) {
            return src.hasNext();
        }
        if (chunk != null) {
            return i < chunk.length;
        }
        if (solutions != null) {
            return solutions.hasNext();
        }
        return false;
    }

    private class SameAsSelfExpander implements IAccessPathExpander {
        public boolean backchain() {
            return false;
        }
        public boolean runFirst() {
            return false;
        }
        public IAccessPath getAccessPath(
                final IAccessPath accessPath) {
            return new SameAsSelfAccessPath(accessPath);
        }
    };

    private class SameAsSelfAccessPath implements IAccessPath {
        private IAccessPath accessPath;

        private SPO spo;

        public SameAsSelfAccessPath(IAccessPath accessPath) {
            this.accessPath = accessPath;
            final IVariableOrConstant p =
                    accessPath.getPredicate().get(1);
            if (!p.isConstant() || !IVUtility.equals(p.get(), sameAs)) {
                throw new UnsupportedOperationException("p must be owl:sameAs");
            }
        }

        private IChunkedOrderedIterator getAppender() {
            final IVariableOrConstant s =
                    accessPath.getPredicate().get(0);
            final IVariableOrConstant o =
                    accessPath.getPredicate().get(2);
            if (s.isVar() && o.isVar()) {
                throw new UnsupportedOperationException(
                        "s and o cannot both be variables");
            }
            if (s.isConstant() && o.isConstant()
                    && s.get().equals(o.get()) == false) {
                /*
                 * if s and o are both constants, then there is nothing for this
                 * appender to append, unless they are equal to each other, in
                 * which case we can append that solution
                 */
                this.spo = null;
            } else {
                final IV constant = s.isConstant() ? s.get() : o.get();
                this.spo =
                        s.isConstant() ? new SPO(s.get(), sameAs, constant)
                                : new SPO(constant, sameAs, o.get());
                if (log.isInfoEnabled()) 
                    log.info("appending SPO: " + spo.toString(db));
            }
            if (spo != null) {
                return new ChunkedArrayIterator(1, new SPO[] { spo },
                        SPOKeyOrder.SPO);
            } else {
                return null;
            }
        }

        @Override
        public IIndex getIndex() {
            return accessPath.getIndex();
        }

        @Override
        public IKeyOrder getKeyOrder() {
            return accessPath.getKeyOrder();
        }

        @Override
        public IPredicate getPredicate() {
            return accessPath.getPredicate();
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public IChunkedOrderedIterator iterator() {
            final IChunkedOrderedIterator appender = getAppender();
            final IChunkedOrderedIterator delegate =
                    accessPath.iterator();
            if (appender == null) {
                return delegate;
            }
            return new IChunkedOrderedIterator() {
                public ISPO next() {
                    if (delegate.hasNext()) {
                        return delegate.next();
                    } else {
                        return appender.next();
                    }
                }

                public ISPO[] nextChunk() {
                    if (delegate.hasNext()) {
                        return delegate.nextChunk();
                    } else {
                        return appender.nextChunk();
                    }
                }

                public void remove() {
                    throw new UnsupportedOperationException();
                }

                public boolean hasNext() {
                    return delegate.hasNext() || appender.hasNext();
                }

                public IKeyOrder getKeyOrder() {
                    return delegate.getKeyOrder();
                }

                public ISPO[] nextChunk(IKeyOrder keyOrder) {
                    if (delegate.hasNext()) {
                        return delegate.nextChunk(keyOrder);
                    } else {
                        return appender.nextChunk(keyOrder);
                    }
                }

                public void close() {
                    delegate.close();
                    appender.close();
                }
            };
        }

//        public IChunkedOrderedIterator iterator(int limit, int capacity) {
//            throw new UnsupportedOperationException();
//        }

        @Override
        public IChunkedOrderedIterator iterator(long offset, long limit, int capacity) {
            throw new UnsupportedOperationException();
        }

        @Override
        public long rangeCount(boolean exact) {
            return accessPath.rangeCount(exact) + 1;
        }

//        @Override
//        public ITupleIterator rangeIterator() {
//            throw new UnsupportedOperationException();
//        }

        @Override
        public long removeAll() {
            throw new UnsupportedOperationException();
        }
    };

    private class RejectSameAsSelf extends BOpBase implements BooleanValueExpression {

        /**
		 * 
		 */
		private static final long serialVersionUID = -7877904606067597254L;

		public RejectSameAsSelf(final IVariableOrConstant _s,
                final IVariableOrConstant _p,
                final IVariableOrConstant _o) {

            super(new BOp[] { _s, _p, _o }, null/*annotations*/);
            
        }

        public Boolean get(final IBindingSet bindings) {
            final IV sVal = getValue((IVariableOrConstant)get(0/*_s*/), bindings);
            final IV pVal = getValue((IVariableOrConstant)get(1/*_p*/), bindings);
            final IV oVal = getValue((IVariableOrConstant)get(2/*_o*/), bindings);
            // not fully bound yet, just ignore for now
            if (sVal == null || pVal == null || oVal == null) {
                return true;
            }
            if (IVUtility.equals(pVal, sameAs) && IVUtility.equals(sVal, oVal)) {
                return false;
            }
            return true;
        }
        
        private IV getValue(final IVariableOrConstant _x,
                final IBindingSet bindings) {
            final IV val;
            if (_x.isConstant()) {
                val = _x.get();
            } else {
                final IConstant bound = bindings.get((IVariable) _x);
                val = bound != null ? bound.get() : null;
            }
            return val;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy