/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.sparql.algebra.optimize; import org.apache.jena.atlas.lib.StrUtils ; import org.apache.jena.query.ARQ ; import org.apache.jena.sparql.algebra.Op ; import org.apache.jena.sparql.algebra.op.OpAssign ; import org.apache.jena.sparql.algebra.op.OpExtend ; import org.apache.jena.sparql.algebra.op.OpTable ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.core.VarExprList ; import org.apache.jena.sparql.expr.ExprVar ; import org.apache.jena.sparql.expr.nodevalue.NodeValueInteger ; import org.apache.jena.sparql.sse.SSE ; import org.junit.Test ; public class TestOptimizer extends AbstractTestTransform { // These test call the whole optimzier. // A lot of the optimizer is tested by using the scripted queries. // Theer are many tests of individual transforms. @Test public void slice_order_to_topn_01() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 42" ; String opExpectedString = "(top (42 ?p ?o)\n" + " (bgp (triple ?s ?p ?o)))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_02() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 4242" ; String opExpectedString = "(slice _ 4242\n" + " (order (?p ?o)\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_03() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT * { ?s ?p ?o } ORDER BY ?p ?o OFFSET 4242 LIMIT 10" ; String opExpectedString = "(slice 4242 10\n" + " (order (?p ?o)\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_04() { try { ARQ.setFalse(ARQ.optTopNSorting) ; assertTrue(ARQ.isFalse(ARQ.optTopNSorting)) ; String queryString = "SELECT * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 42" ; String opExpectedString = "(slice _ 42\n" + " (order (?p ?o)\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } finally { ARQ.unset(ARQ.optTopNSorting) ; } } @Test public void slice_order_to_topn_05() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT DISTINCT * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 42" ; String opExpectedString = "(top (42 ?p ?o)\n" + " (distinct\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_06() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT DISTINCT * { ?s ?p ?o } ORDER BY ?p ?o OFFSET 24 LIMIT 42" ; String opExpectedString = "(slice 24 _\n" + " (top (66 ?p ?o)\n" + " (distinct\n" + " (bgp (triple ?s ?p ?o)))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_07() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT REDUCED * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 42" ; String opExpectedString = "(top (42 ?p ?o)\n" + " (distinct\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_08() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT DISTINCT * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 4242" ; String opExpectedString = "(slice _ 4242\n" + " (distinct\n" + " (order (?p ?o)\n" + " (bgp (triple ?s ?p ?o)))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_09() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT REDUCED * { ?s ?p ?o } ORDER BY ?p ?o LIMIT 4242" ; String opExpectedString = "(slice _ 4242\n" + " (reduced\n" + " (order (?p ?o)\n" + " (bgp (triple ?s ?p ?o)))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_10() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT * { ?s ?p ?o } ORDER BY ?p ?o OFFSET 1 LIMIT 5" ; String opExpectedString = "(slice 1 _\n" + " (top (6 ?p ?o)\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_11() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT ?s { ?s ?p ?o } ORDER BY ?p ?o OFFSET 1 LIMIT 5" ; String opExpectedString = "(slice 1 _\n" + " (project (?s)\n" + " (top (6 ?p ?o)\n" + " (bgp (triple ?s ?p ?o)))))" ; check(queryString, opExpectedString) ; } @Test public void slice_order_to_topn_12() { assertTrue(ARQ.isTrueOrUndef(ARQ.optTopNSorting)) ; String queryString = "SELECT ?s { ?s ?p ?o } ORDER BY ?p ?o LIMIT 42" ; String opExpectedString = "(project (?s)\n" + " (top (42 ?p ?o)\n" + " (bgp (triple ?s ?p ?o))))" ; check(queryString, opExpectedString) ; } @Test public void subQueryProject_01() { String qs = StrUtils.strjoinNL ( "SELECT *" , "WHERE {" , " ?test ?p1 ?X." , " { SELECT ?s1 ?test { ?test ?p2 ?o2 } }" , "}") ; String ops = StrUtils.strjoinNL ("(sequence" ," (bgp (triple ?test ?p1 ?X))" ," (project (?s1 ?test)" ," (bgp (triple ?test ?/p2 ?/o2))))" ) ; check(qs, ops) ; } @Test public void subQueryProject_02() { String qs = StrUtils.strjoinNL ( "SELECT *" , "WHERE {" , " ?test ?p1 ?X." , " { SELECT ?s1 { ?test ?p2 ?o2 } }" , "}") ; String ops = StrUtils.strjoinNL ("(sequence" ," (bgp (triple ?test ?p1 ?X))" ," (project (?s1)" ," (bgp (triple ?/test ?/p2 ?/o2))))" ) ; check(qs, ops) ; } @Test public void optimize_01() { String queryString = "SELECT * { { ?s ?p ?x } UNION { ?s1 ?p1 ?x } FILTER(?x = <urn:x1> || ?x = <urn:x2>) }" ; String opExpectedString = StrUtils.strjoinNL( "(disjunction", " (assign ((?x <urn:x1>))" , " (union" , " (bgp (triple ?s ?p <urn:x1>))" , " (bgp (triple ?s1 ?p1 <urn:x1>))))" , " (assign ((?x <urn:x2>))" , " (union" , " (bgp (triple ?s ?p <urn:x2>))" , " (bgp (triple ?s1 ?p1 <urn:x2>)))))" ) ; check(queryString, opExpectedString) ; } // JENA-1235 @Test public void optimize_02() { String in = StrUtils.strjoinNL ( "(filter (exprlist (|| (= ?var3 'ABC') (= ?var3 'XYZ')) (&& (regex ?var4 'pat1') (!= ?VAR 123)))" ," (bgp" ," (triple ?var2 :p1 ?var4)" ," (triple ?var2 :p2 ?var3)" ," ))") ; String out = StrUtils.strjoinNL ("(filter (!= ?VAR 123)" ," (disjunction" ," (assign ((?var3 'ABC'))" ," (sequence" ," (filter (regex ?var4 'pat1')" ," (bgp (triple ?var2 :p1 ?var4)))" ," (bgp (triple ?var2 :p2 'ABC'))))" ," (assign ((?var3 'XYZ'))" ," (sequence" ," (filter (regex ?var4 'pat1')" ," (bgp (triple ?var2 :p1 ?var4)))" ," (bgp (triple ?var2 :p2 'XYZ'))))))" ) ; checkAlgebra(in, out) ; } @Test public void combine_extend_01() { Op extend = OpExtend.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); extend = OpExtend.create(extend, new VarExprList(Var.alloc("y"), new NodeValueInteger(2))); String opExpectedString = StrUtils.strjoinNL( "(extend ((?x 1) (?y 2))", " (table unit))"); check(extend, new TransformExtendCombine(), opExpectedString); } @Test public void combine_extend_02() { Op extend = OpExtend.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); extend = OpExtend.create(extend, new VarExprList(Var.alloc("y"), new ExprVar("x"))); String opExpectedString = StrUtils.strjoinNL( "(extend ((?x 1) (?y ?x))", " (table unit))"); check(extend, new TransformExtendCombine(), opExpectedString); } @Test public void combine_extend_03() { // Technically illegal SPARQL here but useful to validate that the optimizer doesn't do the wrong thing Op extend = OpExtend.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); extend = OpExtend.create(extend, new VarExprList(Var.alloc("x"), new NodeValueInteger(2))); String opExpectedString = StrUtils.strjoinNL( "(extend ((?x 2))", " (extend ((?x 1))", " (table unit)))"); check(extend, new TransformExtendCombine(), opExpectedString); } @Test public void combine_extend_04() { String opString = StrUtils.strjoinNL ("(extend ((?x 2))" ," (extend ((?y 3))" ," (distinct" ," (extend ((?a 'A') (?b 'B'))" ," (extend ((?c 'C'))" ," (table unit)" ," )))))" ); String opExpectedString = StrUtils.strjoinNL ("(extend ((?y 3) (?x 2))" ," (distinct" ," (extend ((?c 'C') (?a 'A') (?b 'B'))" ," (table unit))))"); Op op = SSE.parseOp(opString) ; check(op, new TransformExtendCombine(), opExpectedString); } @Test public void combine_extend_05() { // JENA-809 : check no changes to input. String x = "(project (?x) (extend ((?bar 2)) (extend ((?foo 1)) (table unit))))" ; String y = "(project (?x) (extend ((?foo 1) (?bar 2)) (table unit)))" ; checkAlgebra(x, new TransformExtendCombine(), y); } @Test public void combine_assign_01() { Op assign = OpAssign.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); assign = OpAssign.create(assign, new VarExprList(Var.alloc("y"), new NodeValueInteger(2))); String opExpectedString = StrUtils.strjoinNL( "(assign ((?x 1) (?y 2))", " (table unit))"); check(assign, new TransformExtendCombine(), opExpectedString); } @Test public void combine_assign_02() { Op assign = OpAssign.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); assign = OpAssign.create(assign, new VarExprList(Var.alloc("y"), new ExprVar("x"))); String opExpectedString = StrUtils.strjoinNL( "(assign ((?x 1) (?y ?x))", " (table unit))"); check(assign, new TransformExtendCombine(), opExpectedString); } @Test public void combine_assign_03() { Op assign = OpAssign.create(OpTable.unit(), new VarExprList(Var.alloc("x"), new NodeValueInteger(1))); assign = OpAssign.create(assign, new VarExprList(Var.alloc("x"), new NodeValueInteger(2))); String opExpectedString = StrUtils.strjoinNL( "(assign ((?x 2))", " (assign ((?x 1))", " (table unit)))"); check(assign, new TransformExtendCombine(), opExpectedString); } @Test public void combine_assign_04() { String opString = StrUtils.strjoinNL ("(assign ((?x 2))" ," (assign ((?y 3))" ," (distinct" ," (assign ((?a 'A') (?b 'B'))" ," (assign ((?c 'C'))" ," (table unit)" ," )))))" ); String opExpectedString = StrUtils.strjoinNL ("(assign ((?y 3) (?x 2))" ," (distinct" ," (assign ((?c 'C') (?a 'A') (?b 'B'))" ," (table unit))))"); Op op = SSE.parseOp(opString) ; check(op, new TransformExtendCombine(), opExpectedString); } @Test public void combine_assign_05() { // JENA-809 : check no changes to input. String x = "(project (?x) (assign ((?bar 2)) (assign ((?foo 1)) (table unit))))" ; String y = "(project (?x) (assign ((?foo 1) (?bar 2)) (table unit)))" ; AbstractTestTransform.checkAlgebra(x, new TransformExtendCombine(), y); } // Nested /* * String qs = StrUtils.strjoinNL ("select *", "where {", " { select * { ?id ?p ?label } order by ?label limit 5 }", " OPTIONAL { OPTIONAL { ?s ?p ?label }}", "}" ); */ // Derived from JENA-1041 (inner TopN) @Test public void subselect_01() { String qs = StrUtils.strjoinNL ("select *", "where {", " { select * { ?id ?p ?label } order by ?label limit 5 }", " ?s ?p ?label", "}" ); String expected = StrUtils.strjoinNL ("(sequence" ," (top (5 ?label)" ," (bgp (triple ?id ?p ?label)))" ," (bgp (triple ?s ?p ?label)))") ; check(qs, expected) ; } // Derived from JENA-1041 (inner TopN) @Test public void subselect_02() { // Has a blocking optional pattern for the join strategy. String qs = StrUtils.strjoinNL ("select *", "where {", " { select * { ?id ?p ?label } order by ?label limit 5 }", " OPTIONAL { OPTIONAL { ?s ?p ?label }}", "}" ); String expected = StrUtils.strjoinNL ("(leftjoin" ," (top (5 ?label)" ," (bgp (triple ?id ?p ?label)))" ," (conditional" ," (table unit)" ," (bgp (triple ?s ?p ?label))))") ; check(qs, expected) ; } }