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

com.bigdata.rdf.sparql.ast.optimizers.TestASTSimpleOptionalOptimizer Maven / Gradle / Ivy

There is a newer version: 2.1.4
Show newest version
/**

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 Sep 15, 2011
 */

package com.bigdata.rdf.sparql.ast.optimizers;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.algebra.StatementPattern.Scope;

import com.bigdata.bop.BOpUtility;
import com.bigdata.bop.Constant;
import com.bigdata.rdf.model.BigdataURI;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.model.BigdataValueFactory;
import com.bigdata.rdf.sail.sparql.Bigdata2ASTSPARQLParser;
import com.bigdata.rdf.sparql.ast.ASTContainer;
import com.bigdata.rdf.sparql.ast.AbstractASTEvaluationTestCase;
import com.bigdata.rdf.sparql.ast.ConstantNode;
import com.bigdata.rdf.sparql.ast.FilterNode;
import com.bigdata.rdf.sparql.ast.FunctionNode;
import com.bigdata.rdf.sparql.ast.FunctionRegistry;
import com.bigdata.rdf.sparql.ast.GlobalAnnotations;
import com.bigdata.rdf.sparql.ast.GraphPatternGroup;
import com.bigdata.rdf.sparql.ast.IGroupMemberNode;
import com.bigdata.rdf.sparql.ast.JoinGroupNode;
import com.bigdata.rdf.sparql.ast.QueryNodeWithBindingSet;
import com.bigdata.rdf.sparql.ast.QueryRoot;
import com.bigdata.rdf.sparql.ast.StatementPatternNode;
import com.bigdata.rdf.sparql.ast.ValueExpressionNode;
import com.bigdata.rdf.sparql.ast.VarNode;
import com.bigdata.rdf.sparql.ast.eval.AST2BOpContext;
import com.bigdata.rdf.sparql.ast.eval.AST2BOpUtility;
import com.bigdata.rdf.sparql.ast.eval.ASTDeferredIVResolution;

/**
 * Test suite for {@link ASTSimpleOptionalOptimizer}.
 * 
 * @author Bryan Thompson
 * @version $Id$
 */
public class TestASTSimpleOptionalOptimizer extends
        AbstractASTEvaluationTestCase {

    public TestASTSimpleOptionalOptimizer() {
        super();
    }

    public TestASTSimpleOptionalOptimizer(final String name) {
        super(name);
    }

    /**
     * Unit test for recognizing a "simple optional" and lifting it into the
     * parent join group.
     * 
     * TODO Unit test for a variation where there are FILTERS or other things in
     * the optional which mean that we can not lift out the statement pattern.
     */
    public void test_simpleOptional() throws MalformedQueryException {

        final String queryStr = "" + //
                "PREFIX rdf:  \n"+//
                "PREFIX dc:  \n"+//
                "PREFIX p1:  \n"+//
                "SELECT * \n" + //
                "WHERE { \n" + //
                "  ?_var1 rdf:type . \n" + //
                "  ?_var1 p1:genre ?_var8.  \n" + //
                "  ?_var8 dc:title ?_var9.  \n" + //
                "  FILTER ((?_var9 in(\"Folk\", \"Hip-Hop\"))) . \n" + //
                "  OPTIONAL { \n" + //
                "    ?_var1 dc:title ?_var10 \n" + //
                "  }.  \n" + //
                "  OPTIONAL { \n" + //
                "    ?_var1 p1:mainArtist ?_var12. \n" + //
                "    ?_var12 dc:title ?_var11 \n" + //
                "  } \n" + //
                "}";

        final ASTContainer astContainer = new Bigdata2ASTSPARQLParser()
                .parseQuery2(queryStr, baseURI);

        final AST2BOpContext context = new AST2BOpContext(astContainer,store);

        QueryRoot queryRoot = astContainer.getOriginalAST();

        queryRoot = (QueryRoot) new ASTWildcardProjectionOptimizer().optimize(
                context, new QueryNodeWithBindingSet(queryRoot, null))
                .getQueryNode();

        queryRoot = (QueryRoot) new ASTSimpleOptionalOptimizer().optimize(
                context, new QueryNodeWithBindingSet(queryRoot, null))
                .getQueryNode();

        final GraphPatternGroup whereClause = queryRoot.getWhereClause();

        // Verify that we lifted out the simple optional statement pattern.
        {
            int nstmts = 0;
            for(IGroupMemberNode child : whereClause) {
                if(child instanceof StatementPatternNode) {
                    nstmts++;
                }
            }
            assertEquals("#statements", 4, nstmts);
        }
        
        /*
         * Verify that there is one optional remaining, and that it is the one
         * with two statement patterns.
         */
        {
            final Iterator itr = BOpUtility.visitAll(
                    whereClause, JoinGroupNode.class);
            int ngroups = 0;
            int noptionalGroups = 0;
            while (itr.hasNext()) {
                final JoinGroupNode tmp = itr.next();
                ngroups++;
                if(tmp.isOptional())
                    noptionalGroups++;
            }
            assertEquals("#ngroups", 2, ngroups);
            assertEquals("#optionalGroups", 1, noptionalGroups);
        }

    }

    /**
     * Test effective boolean value - optional.
     * 
     * 
     * PREFIX  xsd: 
     * PREFIX  : 
     * SELECT  ?a
     * WHERE
     *     { ?a :p ?v . 
     *       OPTIONAL
     *         { ?a :q ?w } . 
     *       FILTER (?w) .
     *     }
     * 
* * Note: This TCK query will fail if we do not lift the simple optional * correctly. * * @see ASTSimpleOptionalOptimizer */ @SuppressWarnings({ "rawtypes", "unchecked" }) public void test_sparql_bev_5() throws Exception { final String queryStr = "" + // "PREFIX xsd: \n" + // "PREFIX : " + // "SELECT ?a \n" + // "WHERE" + // " { ?a :p ?v . \n" + // " OPTIONAL \n" + // " { ?a :q ?w } . \n" + // " FILTER (?w) . \n" + // " }\n" // ; /* * Add the Values used in the query to the lexicon. This makes it * possible for us to explicitly construct the expected AST and * the verify it using equals(). */ final BigdataValueFactory f = store.getValueFactory(); final BigdataURI p = f.createURI("http://example.org/ns#p"); final BigdataURI q = f.createURI("http://example.org/ns#q"); final BigdataValue[] values = new BigdataValue[] { p, q }; store.getLexiconRelation() .addTerms(values, values.length, false/* readOnly */); final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); ASTDeferredIVResolution.resolveQuery(store, astContainer); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); queryRoot = (QueryRoot) new ASTSimpleOptionalOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)) .getQueryNode(); /* * Create the expected AST. */ final JoinGroupNode expectedClause = new JoinGroupNode(); { // :x3 :q ?w expectedClause.addChild(new StatementPatternNode(// new VarNode("a"),// s new ConstantNode(new Constant(p.getIV())),// p new VarNode("v"),// o null,// c Scope.DEFAULT_CONTEXTS// )); // :x3 :q ?w final StatementPatternNode liftedSp = new StatementPatternNode(// new VarNode("a"),// s new ConstantNode(new Constant(q.getIV())),// p new VarNode("w"),// o null,// c Scope.DEFAULT_CONTEXTS// ); expectedClause.addChild(liftedSp); liftedSp.setOptional(true); // The filter stays in place (it is in the outer group). expectedClause.addChild(new FilterNode(new VarNode("w"))); } assertSameAST(expectedClause, queryRoot.getWhereClause()); } /** * A variant of the TCK test where the filter is in the optional group and * uses BOUND() to wrap the variable. This filter does not have any * materialization requirements. Both it and the statement pattern should be * lifted out of the optional group. The filter should be attached to the * statement pattern. * * @throws Exception */ @SuppressWarnings({ "rawtypes", "unchecked" }) public void test_sparql_bev_5_withFilterInOptionalGroup() throws Exception { final String queryStr = "" + // "PREFIX xsd: \n" + // "PREFIX : " + // "SELECT ?a \n" + // "WHERE" + // " { ?a :p ?v . \n" + // " OPTIONAL \n" + // " { ?a :q ?w ." + " FILTER (BOUND(?w)) \n" + " } \n" + // " }\n" // ; /* * Add the Values used in the query to the lexicon. This makes it * possible for us to explicitly construct the expected AST and * the verify it using equals(). */ final BigdataValueFactory f = store.getValueFactory(); final BigdataURI p = f.createURI("http://example.org/ns#p"); final BigdataURI q = f.createURI("http://example.org/ns#q"); final BigdataValue[] values = new BigdataValue[] { p, q }; store.getLexiconRelation() .addTerms(values, values.length, false/* readOnly */); final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); ASTDeferredIVResolution.resolveQuery(store, astContainer); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); queryRoot = BOpUtility.deepCopy(queryRoot); queryRoot = (QueryRoot) new ASTSimpleOptionalOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); /* * Create the expected AST. */ final JoinGroupNode expectedClause = new JoinGroupNode(); { // :x3 :q ?w expectedClause.addChild(new StatementPatternNode(// new VarNode("a"),// s new ConstantNode(new Constant(p.getIV())),// p new VarNode("v"),// o null,// c Scope.DEFAULT_CONTEXTS// )); // :x3 :q ?w final StatementPatternNode liftedSp = new StatementPatternNode(// new VarNode("a"),// s new ConstantNode(new Constant(q.getIV())),// p new VarNode("w"),// o null,// c Scope.DEFAULT_CONTEXTS// ); expectedClause.addChild(liftedSp); liftedSp.setOptional(true); final List filters = new LinkedList(); final FilterNode filterNode = new FilterNode(// new FunctionNode(FunctionRegistry.BOUND, null,// scalarValues new ValueExpressionNode[] {// new VarNode("w")// }// )); final GlobalAnnotations globals = new GlobalAnnotations( context.getLexiconNamespace(), context.getTimestamp() ); AST2BOpUtility.toVE(getBOpContext(), globals, filterNode.getValueExpressionNode()); filters.add(filterNode); liftedSp.setAttachedJoinFilters(filters); } assertSameAST(expectedClause, queryRoot.getWhereClause()); } /* * Note: I have taken out the code path since we are not trying to lift the * filter in this case. */ // /** // * A variant of the TCK test where the filter is in the optional group and // * uses a variable which is "incoming bound" to the optional group (hence // * definitely bound in the parent group). // *

// * This filter does not have any materialization requirements on variables // * bound by the optional statement pattern. Both it and the statement // * pattern should be lifted out of the optional group. The filter should be // * attached to the statement pattern. // * // * @see TestTCK#test_opt_filter_1(), which will fail if the materialization // * requirements are not properly imposed on the parent. // * // * @throws Exception // */ // @SuppressWarnings({ "rawtypes", "unchecked" }) // public void test_sparql_bev_5_withFilterInOptionalGroup2() throws Exception { // // final String queryStr = "" + // // "PREFIX xsd: \n" + // // "PREFIX : " + // // "SELECT ?a \n" + // // "WHERE" + // // " { ?a :p ?v . \n" + // // " OPTIONAL \n" + // // " { ?a :q ?w ." + // " FILTER (?v) \n" + // " } \n" + // // " }\n" // // ; // // /* // * Add the Values used in the query to the lexicon. This makes it // * possible for us to explicitly construct the expected AST and // * the verify it using equals(). // */ // final BigdataValueFactory f = store.getValueFactory(); // final BigdataURI p = f.createURI("http://example.org/ns#p"); // final BigdataURI q = f.createURI("http://example.org/ns#q"); // final BigdataValue[] values = new BigdataValue[] { p, q }; // store.getLexiconRelation() // .addTerms(values, values.length, false/* readOnly */); // // final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() // .parseQuery2(queryStr, baseURI); // // final AST2BOpContext context = new AST2BOpContext(astContainer, store); // // QueryRoot queryRoot = astContainer.getOriginalAST(); // // queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer().optimize( // context, queryRoot, null/* bindingSets */); // // queryRoot = BOpUtility.deepCopy(queryRoot); // // queryRoot = (QueryRoot) new ASTSimpleOptionalOptimizer().optimize( // context, queryRoot, null/* bindingSets */); // // /* // * Create the expected AST. // */ // final JoinGroupNode expectedClause = new JoinGroupNode(); // { // // // :x3 :q ?w // expectedClause.addChild(new StatementPatternNode(// // new VarNode("a"),// s // new ConstantNode(new Constant(p.getIV())),// p // new VarNode("v"),// o // null,// c // Scope.DEFAULT_CONTEXTS// // )); // // // :x3 :q ?w // final StatementPatternNode liftedSp = new StatementPatternNode(// // new VarNode("a"),// s // new ConstantNode(new Constant(q.getIV())),// p // new VarNode("w"),// o // null,// c // Scope.DEFAULT_CONTEXTS// // ); // // expectedClause.addChild(liftedSp); // // liftedSp.setSimpleOptional(true); // // final List filters = new LinkedList(); // // final FilterNode filterNode = new FilterNode(new VarNode("v")); // //// AST2BOpUtility.toVE(context.getLexiconNamespace(), //// filterNode.getValueExpressionNode()); // // filters.add(filterNode); // // liftedSp.setFilters(filters); // // /* // * The mock filter is used to impose the appropriate materialization // * requirements onto the parent. // */ // // expectedClause.addChild(new MockFilterNode(filterNode // .getValueExpressionNode(), filterNode // .getMaterializationRequirement())); // // } // // /* // * Note: This is failing because I am having difficulties getting the // * materialization pipeline to work correctly when a statement pattern // * with a filter having some materialization requirements is lifted into // * the parent group. See the code in ASTSimpleOptionalOptimizer. // */ // assertSameAST(expectedClause, queryRoot.getWhereClause()); // // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy