/*
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
*/
/*
* Created on Aug 19, 2008
*/
package com.bigdata.bop.joinGraph.fast;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import junit.framework.TestCase2;
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.IPredicate.Annotations;
import com.bigdata.bop.IVariableOrConstant;
import com.bigdata.bop.NV;
import com.bigdata.bop.Var;
import com.bigdata.bop.ap.Predicate;
import com.bigdata.bop.joinGraph.IEvaluationPlan;
import com.bigdata.bop.joinGraph.IEvaluationPlanFactory;
import com.bigdata.bop.joinGraph.IRangeCountFactory;
import com.bigdata.btree.keys.ISortKeyBuilder;
import com.bigdata.config.IValidator;
import com.bigdata.io.IStreamSerializer;
import com.bigdata.journal.IIndexManager;
import com.bigdata.journal.ITx;
import com.bigdata.mdi.PartitionLocator;
import com.bigdata.relation.IMutableRelation;
import com.bigdata.relation.IRelation;
import com.bigdata.relation.accesspath.IAccessPath;
import com.bigdata.relation.accesspath.IBlockingBuffer;
import com.bigdata.relation.accesspath.IBuffer;
import com.bigdata.relation.accesspath.IElementFilter;
import com.bigdata.relation.rule.IAccessPathExpander;
import com.bigdata.relation.rule.IRule;
import com.bigdata.relation.rule.IStep;
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.IRuleStatisticsFactory;
import com.bigdata.relation.rule.eval.IRuleTaskFactory;
import com.bigdata.relation.rule.eval.ISolution;
import com.bigdata.service.AbstractScaleOutFederation;
import com.bigdata.striterator.IChunkedOrderedIterator;
/**
* Test harness for {@link DefaultEvaluationPlan2}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestDefaultEvaluationPlan extends TestCase2 {
/**
*
*/
public TestDefaultEvaluationPlan() {
}
/**
* @param arg0
*/
public TestDefaultEvaluationPlan(String arg0) {
super(arg0);
}
/**
* Factory fixture for {@link IEvaluationPlan}s.
*
* @param joinNexus
* Per {@link IEvaluationPlanFactory}
* @param rule
* {@link IEvaluationPlanFactory}
*/
final IEvaluationPlan newPlan(IJoinNexus joinNexus, final IRule rule) {
// return new DefaultEvaluationPlan(joinNexus,rule);
return new DefaultEvaluationPlan2(joinNexus, rule);
};
/**
* Based on LUBM query#8 with the U1 dataset.
*/
public void test_lubmQuery8() {
final String relation = "spo";
final long timestamp = ITx.READ_COMMITTED;
final Constant<?> rdfType = new Constant<String>("rdfType");
final Constant<?> Department = new Constant<String>("Department");
final Constant<?> Student = new Constant<String>("Student");
final Constant<?> memberOf = new Constant<String>("memberOf");
final Constant<?> subOrganizationOf = new Constant<String>("subOrganizationOf");
final Constant<?> emailAddress = new Constant<String>("emailAddress");
final Constant<?> University0 = new Constant<String>("University0");
final IPredicate<?> pred0 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("y"), rdfType, Department },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred1 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("x"), rdfType, Student },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred2 = new Predicate( //
new IVariableOrConstant[] {//
Var.var("x"), memberOf, Var.var("y") },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred3 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("y"), subOrganizationOf, University0 },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred4 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("x"), emailAddress, Var.var("z") },
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IRule rule = new Rule(getName(), null/* head */,
new IPredicate[] { pred0, pred1, pred2, pred3, pred4 }, //
null// constraints
);
/*
* Range counts with the predicates as given based on the LUBM U1
* dataset.
*
* rangeCount=15, tailIndex=0, tail=([kb.spo.], y, 8, 204)
* rangeCount=6463, tailIndex=1, tail=([kb.spo.], x, 8, 368)
* rangeCount=8330, tailIndex=2, tail=([kb.spo.], x, 276, y)
* rangeCount=15, tailIndex=3, tail=([kb.spo.], y, 372, 6148)
* rangeCount=8330, tailIndex=4, tail=([kb.spo.], x, 216, z)
*/
// final long[] rangeCount = { 15, 6463, 8830, 15, 8330 };
final Map<IPredicate,Long> rangeCount = new HashMap<IPredicate,Long>();
{
rangeCount.put(pred0, 15L);
rangeCount.put(pred1, 6463L);
rangeCount.put(pred2, 8830L);
rangeCount.put(pred3, 15L);
rangeCount.put(pred4, 8830L);
}
final IEvaluationPlan plan = newPlan(new MockJoinNexus(
new MockRangeCountFactory(rangeCount)), rule);
assertFalse(plan.isEmpty());
final int[] expected = new int[] { 0, 3, 2, 1, 4 };
final int[] actual = plan.getOrder();
if (!Arrays.equals(expected, actual))
fail("evaluation order: expected=" + Arrays.toString(expected)
+ ", actual=" + Arrays.toString(actual));
// assertFalse("isFullyBound(0)", plan.isFullyBound(0));
// assertTrue( "isFullyBound(1)", plan.isFullyBound(1));
// assertFalse("isFullyBound(2)", plan.isFullyBound(2));
// assertTrue( "isFullyBound(3)", plan.isFullyBound(3));
// assertFalse("isFullyBound(4)", plan.isFullyBound(4));
//
// assertEquals("getVarCount(0)", 1, plan.getVariableCount(0));
// assertEquals("getVarCount(1)", 0, plan.getVariableCount(1));
// assertEquals("getVarCount(2)", 1, plan.getVariableCount(2));
// assertEquals("getVarCount(3)", 0, plan.getVariableCount(3));
// assertEquals("getVarCount(4)", 1, plan.getVariableCount(4));
}
// public void test_rdf01() {
//
// fail("write test");
//
// }
// /**
// * FIXME test all of these rules with some hard coded range counts based on
// * some fake data and make sure that we are producing good join orderings in
// * each case. Note that some data sets will not have anything for some of
// * these rules. In those cases, we should verify that the plan detects that
// * there will be no solutions AND also find a data set that can be used to
// * verify a plan that does have solutions for the rule.
// * <p>
// * RuleRdf01.java RuleRdfs03.java RuleRdfs04a.java RuleRdfs04b.java
// * RuleRdfs05.java RuleRdfs06.java RuleRdfs07.java RuleRdfs08.java
// * RuleRdfs09.java RuleRdfs10.java RuleRdfs11.java RuleRdfs12.java
// * RuleRdfs13.java
// * <p>
// * RuleFastClosure11.java RuleFastClosure13.java RuleFastClosure3.java
// * RuleFastClosure5.java RuleFastClosure6.java RuleFastClosure7.java
// * RuleFastClosure9.java
// * <P>
// * RuleOwlEquivalentClass.java RuleOwlEquivalentProperty.java
// * RuleOwlSameAs1.java RuleOwlSameAs1b.java RuleOwlSameAs2.java
// * RuleOwlSameAs3.java
// */
// public void test_rdfs02() {
//
// fail("write test");
//
// }
public void testRunFirstExpanders() {
final String relation = "spo";
final long timestamp = ITx.READ_COMMITTED;
/*
* ?l search Mike
* ?s ?p ?l
* ?s type Person
* ?p type Property
*/
final Constant<?> search = new Constant<String>("search");
final Constant<?> Mike = new Constant<String>("Mike");
final Constant<?> type = new Constant<String>("type");
final Constant<?> Person = new Constant<String>("Person");
final Constant<?> Property = new Constant<String>("Property");
final IAccessPathExpander expander = new IAccessPathExpander() {
// @Override
public IAccessPath getAccessPath(IAccessPath accessPath) {
throw new UnsupportedOperationException();
}
// @Override
public boolean backchain() {
return false;
}
// @Override
public boolean runFirst() {
return true;
}
};
final IPredicate<?> pred0 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("l"), search, Mike },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp),//
new NV(Predicate.Annotations.ACCESS_PATH_EXPANDER, expander)
);
final IPredicate<?> pred1 = new Predicate(//
new IVariableOrConstant[] {//
Var.var("s"), Var.var("p"), Var.var("l") },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred2 = new Predicate( //
new IVariableOrConstant[] {//
Var.var("s"), type, Person },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IPredicate<?> pred3 = new Predicate( //
new IVariableOrConstant[] {//
Var.var("p"), type, Property },//
new NV(Predicate.Annotations.RELATION_NAME,
new String[] { relation }),//
new NV(Annotations.TIMESTAMP,timestamp)//
);
final IRule rule = new Rule(getName(), null/* head */,
new IPredicate[] { pred0, pred1, pred2, pred3 }, //
null// constraints
);
final Map<IPredicate,Long> rangeCount = new HashMap<IPredicate,Long>();
{
rangeCount.put(pred0, 0L);
rangeCount.put(pred1, 1000000L);
rangeCount.put(pred2, 10000L);
rangeCount.put(pred3, 100L);
}
final IEvaluationPlan plan = newPlan(new MockJoinNexus(
new MockRangeCountFactory(rangeCount)), rule);
assertFalse(plan.isEmpty());
final int[] expected = new int[] { 0, 1, 3, 2 };
final int[] actual = plan.getOrder();
if (!Arrays.equals(expected, actual))
fail("evaluation order: expected=" + Arrays.toString(expected)
+ ", actual=" + Arrays.toString(actual));
// assertFalse("isFullyBound(0)", plan.isFullyBound(0));
// assertTrue( "isFullyBound(1)", plan.isFullyBound(1));
// assertFalse("isFullyBound(2)", plan.isFullyBound(2));
// assertTrue( "isFullyBound(3)", plan.isFullyBound(3));
// assertFalse("isFullyBound(4)", plan.isFullyBound(4));
//
// assertEquals("getVarCount(0)", 1, plan.getVariableCount(0));
// assertEquals("getVarCount(1)", 0, plan.getVariableCount(1));
// assertEquals("getVarCount(2)", 1, plan.getVariableCount(2));
// assertEquals("getVarCount(3)", 0, plan.getVariableCount(3));
// assertEquals("getVarCount(4)", 1, plan.getVariableCount(4));
}
/**
* Mock object.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
private static class MockJoinNexus implements IJoinNexus {
private final IRangeCountFactory rangeCountFactory;
public MockJoinNexus(IRangeCountFactory rangeCountFactory) {
this.rangeCountFactory = rangeCountFactory;
}
public boolean bind(final IRule rule, final int index, final Object e,
final IBindingSet bindings) {
return false;
}
public boolean bind(IPredicate<?> pred, IConstraint constraint[],
Object e, IBindingSet bindings) {
return false;
}
// public void copyValues(Object e, IPredicate predicate, IBindingSet bindingSet) {
//
// }
public boolean forceSerialExecution() {
return false;
}
public ActionEnum getAction() {
return null;
}
public IRelation getHeadRelationView(IPredicate pred) {
return null;
}
public IIndexManager getIndexManager() {
return null;
}
public IJoinNexusFactory getJoinNexusFactory() {
return null;
}
public IEvaluationPlanFactory getPlanFactory() {
return null;
}
public long getReadTimestamp(/*String relationName*/) {
return 0;
}
public IRuleTaskFactory getRuleTaskFactory(boolean parallel, IRule rule) {
return null;
}
public IAccessPath getTailAccessPath(IPredicate pred) {
return null;
}
public IAccessPath getTailAccessPath(IRelation rel, IPredicate pred) {
return null;
}
public IRelation getTailRelationView(IPredicate pred) {
return null;
}
public long getWriteTimestamp() {
return 0;
}
public IBindingSet newBindingSet(IRule rule) {
return null;
}
public IBuffer<ISolution[]> newDeleteBuffer(IMutableRelation relation) {
return null;
}
public IBuffer<ISolution[]> newInsertBuffer(IMutableRelation relation) {
return null;
}
public IBlockingBuffer<ISolution[]> newQueryBuffer() {
return null;
}
public ISolution newSolution(IRule rule, IBindingSet bindingSet) {
return null;
}
public long runMutation(IStep step) throws Exception {
return 0;
}
public IChunkedOrderedIterator<ISolution> runQuery(IStep step) throws Exception {
return null;
}
public int solutionFlags() {
return 0;
}
public IRangeCountFactory getRangeCountFactory() {
return rangeCountFactory;
}
public IRuleStatisticsFactory getRuleStatisticsFactory() {
return null;
}
public IConstant fakeBinding(IPredicate predicate, Var var) {
return null;
}
public int getMaxParallelSubqueries() {
return 0;
}
public int getChunkOfChunksCapacity() {
return 0;
}
public int getFullyBufferedReadThreshold() {
return 0;
}
public int getChunkCapacity() {
return 0;
}
public IElementFilter<ISolution> getSolutionFilter() {
return null;
}
public IBuffer<ISolution> newUnsynchronizedBuffer(IBuffer<ISolution[]> targetBuffer, int chunkCapacity) {
return null;
}
public IStreamSerializer<ISolution[]> getSolutionSerializer() {
return null;
}
public ISortKeyBuilder<IBindingSet> newBindingSetSortKeyBuilder(IRule rule) {
return null;
}
public Iterator<PartitionLocator> locatorScan(AbstractScaleOutFederation fed, IPredicate predicate) {
// TODO Auto-generated method stub
return null;
}
public IStreamSerializer<IBindingSet[]> getBindingSetSerializer() {
// TODO Auto-generated method stub
return null;
}
public String getProperty(String name, String defaultValue) {
// TODO Auto-generated method stub
return null;
}
public <T> T getProperty(String name, String defaultValue,
IValidator<T> validator) {
// TODO Auto-generated method stub
return null;
}
}
private static class MockRangeCountFactory implements IRangeCountFactory {
private final Map<IPredicate, Long> rangeCount;
public MockRangeCountFactory(Map<IPredicate, Long> rangeCount) {
this.rangeCount = rangeCount;
}
public long rangeCount(IPredicate pred) {
Long rangeCount = this.rangeCount.get(pred);
if (rangeCount == null)
throw new IllegalArgumentException();
if (log.isInfoEnabled())
log.info("rangeCount=" + rangeCount + ", pred=" + pred);
return rangeCount.longValue();
}
}
}