From: <tho...@us...> - 2010-10-01 20:37:27
|
Revision: 3717 http://bigdata.svn.sourceforge.net/bigdata/?rev=3717&view=rev Author: thompsonbry Date: 2010-10-01 20:37:19 +0000 (Fri, 01 Oct 2010) Log Message: ----------- Added the ContextAdvancer for default graph access paths. There is a unit test for this. It also tests the StripContextFilter as a side-effect. Provided coverage for some of the default graph decision tree. Modified Paths: -------------- branches/QUADS_QUERY_BRANCH/bigdata/src/architecture/query-cost-model.xls branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/ap/Predicate.java branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/engine/Rule2BOpUtility.java branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/bop/rdf/filter/StripContextFilter.java branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/DistinctMultiTermAdvancer.java branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestAll.java branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestDistinctTermScan.java Added Paths: ----------- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/ContextAdvancer.java branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestContextAdvancer.java Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/architecture/query-cost-model.xls =================================================================== (Binary files differ) Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/ap/Predicate.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/ap/Predicate.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/ap/Predicate.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -479,19 +479,20 @@ /* * Set the filter. */ - _setProperty(Annotations.INDEX_LOCAL_FILTER, filter); + _setProperty(name, filter); } else { /* * Wrap the filter. */ - _setProperty(Annotations.INDEX_LOCAL_FILTER, new FilterBase() { + _setProperty(name, new FilterBase() { @Override protected Iterator filterOnce(Iterator src, Object context) { return src; } + }.addFilter(current).addFilter(filter)); } Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/engine/Rule2BOpUtility.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/engine/Rule2BOpUtility.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/engine/Rule2BOpUtility.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -61,8 +61,10 @@ import com.bigdata.bop.ap.Predicate; import com.bigdata.bop.bset.StartOp; import com.bigdata.bop.join.PipelineJoin; +import com.bigdata.bop.rdf.filter.StripContextFilter; import com.bigdata.bop.rdf.join.DataSetJoin; import com.bigdata.bop.solutions.SliceOp; +import com.bigdata.btree.IRangeQuery; import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.internal.TermId; import com.bigdata.rdf.internal.VTE; @@ -70,6 +72,7 @@ import com.bigdata.rdf.model.BigdataURI; import com.bigdata.rdf.sail.BigdataEvaluationStrategyImpl; import com.bigdata.rdf.sail.BigdataSail; +import com.bigdata.rdf.spo.ContextAdvancer; import com.bigdata.rdf.spo.DefaultGraphSolutionExpander; import com.bigdata.rdf.spo.ISPO; import com.bigdata.rdf.spo.InGraphHashSetFilter; @@ -245,6 +248,9 @@ public static PipelineOp convert(final IRule rule, final int startId, final AbstractTripleStore db, final QueryEngine queryEngine) { + // true iff the database is in quads mode. + final boolean isQuadsQuery = db.isQuads(); + int bopId = startId; final PipelineOp startOp = new StartOp(new BOp[] {}, @@ -502,6 +508,15 @@ final List<NV> anns, Predicate pred, final Dataset dataset, final org.openrdf.query.algebra.Var cvar) { + /* + * @todo raise this into the caller and do one per rule rather than once + * per access path. + */ + final DataSetSummary summary = new DataSetSummary(dataset + .getNamedGraphs()); + + anns.add(new NV(Annotations.NKNOWN, summary.nknown)); + final boolean scaleOut = queryEngine.isScaleOut(); if (scaleOut) { anns.add(new NV(Predicate.Annotations.EVALUATION_CONTEXT, @@ -511,10 +526,6 @@ BOpEvaluationContext.ANY)); } - final DataSetSummary summary = new DataSetSummary(dataset.getNamedGraphs()); - - anns.add(new NV(Annotations.NKNOWN, summary.nknown)); - // true iff C is bound to a constant. final boolean isCBound = cvar.getValue() != null; @@ -688,23 +699,231 @@ */ private static PipelineOp defaultGraphJoin(final QueryEngine queryEngine, final BOpContextBase context, final PipelineOp left, - final List<NV> anns, final Predicate pred, final Dataset dataset, + final List<NV> anns, Predicate pred, final Dataset dataset, final org.openrdf.query.algebra.Var cvar) { - // @todo decision of local vs remote ap. + /* + * @todo raise this into the caller and do one per rule rather than once + * per access path. + */ + final DataSetSummary summary = new DataSetSummary(dataset + .getDefaultGraphs()); + + // true iff C is bound to a constant. + final boolean isCBound = cvar.getValue() != null; + final boolean scaleOut = queryEngine.isScaleOut(); - if (scaleOut) { - anns.add(new NV(Predicate.Annotations.EVALUATION_CONTEXT, - BOpEvaluationContext.SHARDED)); - } else { - anns.add(new NV(Predicate.Annotations.EVALUATION_CONTEXT, - BOpEvaluationContext.ANY)); + + if (summary.nknown == 0) { + + /* + * The data set is empty (no graphs). Return a join backed by an + * empty access path. + */ + + // force an empty access path for this predicate. + pred = (Predicate) pred.setUnboundProperty( + IPredicate.Annotations.ACCESS_PATH_EXPANDER, + EmptyAccessPathExpander.INSTANCE); + + return new PipelineJoin(new BOp[] { left, pred }, anns + .toArray(new NV[anns.size()])); + + } else if (summary.nknown == 1) { + + /* + * The dataset contains exactly one graph. Bind C. Add a filter to + * strip off the context position. + */ + + // bind C. + pred = pred.asBound((IVariable) pred.get(3), new Constant( + summary.firstContext)); + + pred = pred.addAccessPathFilter(StripContextFilter.INSTANCE); + + return new PipelineJoin(new BOp[] { left, pred }, anns + .toArray(new NV[anns.size()])); + + } else if (pred.getKeyOrder().getIndexName().endsWith("C")) { + + /* + * C is not bound. An advancer is imposed on the AP to skip to the + * next possible triple after each match. Impose filter on AP to + * strip off the context position. Distinct filter is not required + * since the advancer pattern used will not report duplicates. + */ + + // Set the CURSOR flag. + pred = (Predicate) pred.setProperty(IPredicate.Annotations.FLAGS, + pred.getProperty(IPredicate.Annotations.FLAGS, + IPredicate.Annotations.DEFAULT_FLAGS) + | IRangeQuery.CURSOR); + + // Set Advancer (runs at the index). + pred = pred.addIndexLocalFilter(new ContextAdvancer()); + + // Filter to strip off the context position. + pred = pred.addAccessPathFilter(StripContextFilter.INSTANCE); + + if(scaleOut) { + + /* + * When true, an ISimpleSplitHandler guarantees that no triple + * on that index spans more than one shard. + * + * @todo Implement the split handler and detect when it is being + * used. + */ + final boolean shardTripleConstraint = false; + + if (shardTripleConstraint) { + + // JOIN is SHARDED. + pred = (Predicate) pred.setProperty( + BOp.Annotations.EVALUATION_CONTEXT, + BOpEvaluationContext.SHARDED); + + // AP is LOCAL. + pred = (Predicate) pred.setProperty( + IPredicate.Annotations.REMOTE_ACCESS_PATH, false); + + } else { + + // JOIN is ANY. + pred = (Predicate) pred.setProperty( + BOp.Annotations.EVALUATION_CONTEXT, + BOpEvaluationContext.ANY); + + // AP is REMOTE. + pred = (Predicate) pred.setProperty( + IPredicate.Annotations.REMOTE_ACCESS_PATH, true); + + } + + } + return new PipelineJoin(new BOp[] { left, pred }, anns + .toArray(new NV[anns.size()])); + } - - /* - * FIXME implement the default graph decision tree. - */ + // FIXME Finish the default graph decision tree. throw new UnsupportedOperationException(); +// } else if (dataset == null) { +// +// /* +// * The dataset is all graphs. C is left unbound and the unmodified +// * access path is used. +// */ +// +// return new PipelineJoin(new BOp[] { left, pred }, anns +// .toArray(new NV[anns.size()])); +// +// } else { +// +// /* +// * Estimate cost of SCAN with C unbound. +// */ +// final double scanCost = queryEngine.estimateCost(context, pred); +// +// anns.add(new NV(Annotations.COST_SCAN, scanCost)); +// +// /* +// * Estimate cost of SUBQUERY with C bound (sampling). +// * +// * @todo This should randomly sample in case there is bias in the +// * order in which the URIs are presented here. However, the only +// * thing which would be likely to create a strong bias is if someone +// * sorted them on the IVs or if the URIs were in the same ordering +// * in which their IVs were assigned AND the data were somehow +// * correlated with that order. I rate the latter as pretty unlikely +// * and the former is not true, so this sampling approach should be +// * pretty good. +// * +// * @todo parameter for the #of samples to take. +// */ +// double subqueryCost = 0d; +// final int limit = 100; +// int nsamples = 0; +// for (URI uri : summary.graphs) { +// if (nsamples == limit) +// break; +// final IV graph = ((BigdataURI) uri).getIV(); +// subqueryCost += queryEngine.estimateCost(context, pred.asBound( +// (IVariable) pred.get(3), new Constant(graph))); +// nsamples++; +// } +// subqueryCost /= nsamples; +// +// anns.add(new NV(Annotations.COST_SUBQUERY, subqueryCost)); +// anns.add(new NV(Annotations.COST_SUBQUERY_SAMPLE_COUNT, nsamples)); +// +// if (scanCost < subqueryCost * summary.nknown) { +// +// /* +// * Scan and filter. C is left unbound. We do a range scan on the +// * index and filter using an IN constraint. +// */ +// +// // IN filter for the named graphs. +// final IElementFilter<ISPO> test = new InGraphHashSetFilter<ISPO>( +// summary.nknown, summary.graphs); +// +// // layer filter onto the predicate. +// pred = pred +// .addIndexLocalFilter(ElementFilter.newInstance(test)); +// +// return new PipelineJoin(new BOp[] { left, pred }, anns +// .toArray(new NV[anns.size()])); +// +// } else { +// +// /* +// * Parallel Subquery. +// */ +// +// /* +// * Setup the data set join. +// * +// * @todo When the #of named graphs is large we need to do +// * something special to avoid sending huge graph sets around +// * with the query. For example, we should create named data sets +// * and join against them rather than having an in-memory +// * DataSetJoin. +// * +// * @todo The historical approach performed parallel subquery +// * using an expander pattern rather than a data set join. The +// * data set join should have very much the same effect, but it +// * may need to emit multiple chunks to have good parallelism. +// */ +// +// // The variable to be bound. +// final IVariable var = (IVariable) pred.get(3); +// +// // The data set join. +// final DataSetJoin dataSetJoin = new DataSetJoin( +// new BOp[] { var }, NV.asMap(new NV[] { +// new NV(DataSetJoin.Annotations.VAR, var), +// new NV(DataSetJoin.Annotations.GRAPHS, summary +// .getGraphs()) })); +// +// if (scaleOut) { +// anns.add(new NV(Predicate.Annotations.EVALUATION_CONTEXT, +// BOpEvaluationContext.SHARDED)); +// anns.add(new NV(Predicate.Annotations.REMOTE_ACCESS_PATH, +// false)); +// } else { +// anns.add(new NV(Predicate.Annotations.EVALUATION_CONTEXT, +// BOpEvaluationContext.ANY)); +// anns.add(new NV(Predicate.Annotations.REMOTE_ACCESS_PATH, +// false)); +// } +// +// return new PipelineJoin(new BOp[] { left, pred }, anns +// .toArray(new NV[anns.size()])); +// +// } +// +// } } Modified: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/bop/rdf/filter/StripContextFilter.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/bop/rdf/filter/StripContextFilter.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/bop/rdf/filter/StripContextFilter.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -30,13 +30,16 @@ import java.util.Map; import com.bigdata.bop.BOp; +import com.bigdata.bop.BOpBase; +import com.bigdata.bop.IPredicate; import com.bigdata.bop.ap.filter.BOpResolver; import com.bigdata.rdf.spo.ISPO; import com.bigdata.rdf.spo.SPO; /** * Strips the context information from an {@link SPO}. This is used in default - * graph access paths. + * graph access paths. It operators on {@link ISPO}s so it must be applied using + * {@link IPredicate.Annotations#ACCESS_PATH_FILTER}. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ @@ -48,6 +51,12 @@ */ private static final long serialVersionUID = 1L; + /** + * A global instance. + */ + public static final transient StripContextFilter INSTANCE = new StripContextFilter( + BOpBase.NOARGS, BOpBase.NOANNS); + /** * @param op */ Added: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/ContextAdvancer.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/ContextAdvancer.java (rev 0) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/ContextAdvancer.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -0,0 +1,104 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +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 1, 2010 + */ + +package com.bigdata.rdf.spo; + +import com.bigdata.btree.IRangeQuery; +import com.bigdata.btree.ITuple; +import com.bigdata.btree.ITupleCursor; +import com.bigdata.btree.filter.Advancer; +import com.bigdata.btree.keys.IKeyBuilder; +import com.bigdata.btree.keys.KeyBuilder; +import com.bigdata.btree.keys.SuccessorUtil; +import com.bigdata.rdf.internal.IV; +import com.bigdata.rdf.internal.IVUtility; + +/** + * Advancer for a quads index whose last key component is the "context position + * (such as SPOC or SOPC). The advancer will skip to first possible key for the + * next distinct triple for each quad which it visits. This is a cheap way to + * impose a "DISTINCT" filter using an index scan and works well for both local + * and scale-out indices. + * <p> + * You have to use {@link IRangeQuery#CURSOR} to request an {@link ITupleCursor} + * when using an {@link Advancer} pattern. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id$ + */ +public class ContextAdvancer extends Advancer<SPO> { + + private static final long serialVersionUID = 1L; + + private transient IKeyBuilder keyBuilder; + + public ContextAdvancer() { + + } + + @Override + protected void advance(final ITuple<SPO> tuple) { + + if (keyBuilder == null) { + + /* + * Note: It appears that you can not set this either implicitly or + * explicitly during ctor initialization if you want it to exist + * during de-serialization. Hence it is initialized lazily here. + * This is Ok since the iterator pattern is single threaded. + */ + + keyBuilder = KeyBuilder.newInstance(); + + } + + // extract the key. + final byte[] key = tuple.getKey(); + + // decode the first three components of the key. + final IV[] terms = IVUtility.decode(key, 3/*nterms*/); + + // reset the buffer. + keyBuilder.reset(); + + // encode the first three components of the key. + IVUtility.encode(keyBuilder,terms[0]); + IVUtility.encode(keyBuilder,terms[1]); + IVUtility.encode(keyBuilder,terms[2]); + + // obtain the key. + final byte[] fromKey = keyBuilder.getKey(); + + // obtain the successor of the key. + final byte[] toKey = SuccessorUtil.successor(fromKey.clone()); + + // seek to that successor. + src.seek(toKey); + + } + +} Property changes on: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/ContextAdvancer.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/DistinctMultiTermAdvancer.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/DistinctMultiTermAdvancer.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/java/com/bigdata/rdf/spo/DistinctMultiTermAdvancer.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -47,7 +47,7 @@ * <p> * Note: This class only offers additional functionality over the * {@link DistinctTermAdvancer} for a quad store. For example, consider a triple - * store with 2-bound on the {@link SPOKeyOrder#SPO} index. SInce you are only + * store with 2-bound on the {@link SPOKeyOrder#SPO} index. Since you are only * going to visit the distinct Object values, the advancer will not "advance" * over anything and you might as well use a normal {@link IAccessPath} or * rangeIterator. Modified: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestAll.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestAll.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestAll.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -92,6 +92,9 @@ // test suite for distinct term scan suite.addTestSuite(TestDistinctTermScan.class); + // test suite for the ContextAdvancer. + suite.addTestSuite(TestContextAdvancer.class); + // test suite for rdf1. suite.addTestSuite(TestRuleRdf01.class); Added: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestContextAdvancer.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestContextAdvancer.java (rev 0) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestContextAdvancer.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -0,0 +1,203 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +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 1, 2010 + */ + +package com.bigdata.rdf.rules; + +import java.util.Properties; + +import junit.framework.TestCase2; + +import org.openrdf.model.vocabulary.RDF; + +import com.bigdata.bop.BOp; +import com.bigdata.bop.BOpContextBase; +import com.bigdata.bop.NV; +import com.bigdata.bop.Var; +import com.bigdata.bop.ap.Predicate; +import com.bigdata.bop.rdf.filter.StripContextFilter; +import com.bigdata.btree.IRangeQuery; +import com.bigdata.journal.BufferMode; +import com.bigdata.journal.ITx; +import com.bigdata.journal.Journal; +import com.bigdata.rdf.model.BigdataStatement; +import com.bigdata.rdf.model.BigdataURI; +import com.bigdata.rdf.model.BigdataValue; +import com.bigdata.rdf.model.BigdataValueFactory; +import com.bigdata.rdf.model.StatementEnum; +import com.bigdata.rdf.spo.ContextAdvancer; +import com.bigdata.rdf.spo.ISPO; +import com.bigdata.rdf.spo.SPOKeyOrder; +import com.bigdata.rdf.spo.SPOPredicate; +import com.bigdata.rdf.store.AbstractTestCase; +import com.bigdata.rdf.store.AbstractTripleStore; +import com.bigdata.rdf.store.LocalTripleStore; +import com.bigdata.relation.accesspath.IAccessPath; + +/** + * Test suite for the {@link ContextAdvancer}. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id$ + */ +public class TestContextAdvancer extends TestCase2 { + + /** + * + */ + public TestContextAdvancer() { + } + + public TestContextAdvancer(String name) { + super(name); + } + + /** + * Unit test verifies the {@link ContextAdvancer} against the + * {@link SPOKeyOrder#SPOC} index. + */ + public void test_contextAdvancer() { + + final Properties properties = new Properties(); + + properties.setProperty(AbstractTripleStore.Options.QUADS_MODE, "true"); + + properties.setProperty(Journal.Options.BUFFER_MODE, + BufferMode.Transient.toString()); + + final Journal store = new Journal(properties); + + try { + + final LocalTripleStore db = new LocalTripleStore(store, "test", + ITx.UNISOLATED, properties); + + db.create(); + +// final StatementBuffer<BigdataStatement> sb = new StatementBuffer<BigdataStatement>( +// db, 100/* capacity */); + + final BigdataValueFactory f = db.getValueFactory(); + + final BigdataURI u1 = f.createURI("http://www.bigdata.com/u1"); + final BigdataURI u2 = f.createURI("http://www.bigdata.com/u2"); + final BigdataURI v1 = f.createURI("http://www.bigdata.com/v1"); + final BigdataURI v2 = f.createURI("http://www.bigdata.com/v2"); + final BigdataURI c1 = f.createURI("http://www.bigdata.com/c1"); + final BigdataURI c2 = f.createURI("http://www.bigdata.com/c2"); + final BigdataURI rdfType = f.createURI(RDF.TYPE.stringValue()); + + final BigdataValue[] terms = new BigdataValue[] { + u1,u2,// + v1,v2,// + c1,c2,// + rdfType// + }; + + db.getLexiconRelation() + .addTerms(terms, terms.length, false/* readOnly */); + + final StatementEnum explicit = StatementEnum.Explicit; + final BigdataStatement[] stmts = new BigdataStatement[]{ + f.createStatement(u1, rdfType, v1, c1, explicit), + f.createStatement(u1, rdfType, v1, c2, explicit), + f.createStatement(u1, rdfType, v2, c1, explicit), + f.createStatement(u1, rdfType, v2, c2, explicit), + f.createStatement(u2, rdfType, v1, c1, explicit), + f.createStatement(u2, rdfType, v1, c2, explicit), + f.createStatement(u2, rdfType, v2, c1, explicit), + f.createStatement(u2, rdfType, v2, c2, explicit), + }; + + db.addStatements(stmts, stmts.length); + + db.commit(); + + System.err.println(db.dumpStore()); + + // The expected distinct statements w/o their context info. + final BigdataStatement[] expectedDistinct = new BigdataStatement[]{ + f.createStatement(u1, rdfType, v1), + f.createStatement(u1, rdfType, v2), + f.createStatement(u2, rdfType, v1), + f.createStatement(u2, rdfType, v2), + }; + + // predicate using the SPOC index. + Predicate<ISPO> pred = new SPOPredicate(new BOp[] { Var.var("s"), + Var.var("p"), Var.var("o"), Var.var("c") }, NV + .asMap(new NV[] {// + new NV(Predicate.Annotations.KEY_ORDER, + SPOKeyOrder.SPOC), // + new NV(Predicate.Annotations.TIMESTAMP, + ITx.UNISOLATED),// + })); + + final BOpContextBase context = new BOpContextBase(null/* fed */, + store/* indexManager */); + + // First verify assumptions without the advancer. + { + + final IAccessPath<ISPO> ap = context.getAccessPath(db + .getSPORelation(), pred); + + assertEquals(SPOKeyOrder.SPOC, ap.getKeyOrder()); + + assertEquals(stmts.length, ap.rangeCount(true/* exact */)); + + } + + // Now verify assumptions with the advancer. + { + + pred = (Predicate) pred.setProperty( + Predicate.Annotations.FLAGS, IRangeQuery.DEFAULT + | IRangeQuery.CURSOR); + + pred = pred.addIndexLocalFilter(new ContextAdvancer()); + + pred = pred.addAccessPathFilter(StripContextFilter.INSTANCE); + + final IAccessPath<ISPO> ap = context.getAccessPath(db + .getSPORelation(), pred); + + assertEquals(4, ap.rangeCount(true/* exact */)); + + AbstractTestCase.assertSameSPOsAnyOrder(db, expectedDistinct, + ap.iterator()); + + } + + } finally { + + store.destroy(); + + } + + } + +} Property changes on: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestContextAdvancer.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestDistinctTermScan.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestDistinctTermScan.java 2010-10-01 19:03:22 UTC (rev 3716) +++ branches/QUADS_QUERY_BRANCH/bigdata-rdf/src/test/com/bigdata/rdf/rules/TestDistinctTermScan.java 2010-10-01 20:37:19 UTC (rev 3717) @@ -55,10 +55,13 @@ import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.rio.IStatementBuffer; import com.bigdata.rdf.rio.StatementBuffer; +import com.bigdata.rdf.spo.DistinctTermAdvancer; import com.bigdata.rdf.spo.SPOKeyOrder; import com.bigdata.rdf.store.AbstractTripleStore; /** + * Test suite for the {@link DistinctTermAdvancer}. + * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |