private void TestSubstitution(SparqlQuery q, String findVar, INode replaceTerm, IEnumerable <String> expected, IEnumerable <String> notExpected) { Console.WriteLine("Input Query:"); Console.WriteLine(this._formatter.Format(q)); Console.WriteLine(); ISparqlAlgebra algebra = q.ToAlgebra(); VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(findVar, replaceTerm); try { ISparqlAlgebra resAlgebra = transformer.Optimise(algebra); algebra = resAlgebra; } catch (Exception ex) { //Ignore errors Console.WriteLine("Error Transforming - " + ex.Message); Console.WriteLine(ex.StackTrace); Console.WriteLine(); } SparqlQuery resQuery = algebra.ToQuery(); String resText = this._formatter.Format(resQuery); Console.WriteLine("Resulting Query:"); Console.WriteLine(resText); Console.WriteLine(); foreach (String x in expected) { Assert.IsTrue(resText.Contains(x), "Expected Transformed Query to contain string '" + x + "'"); } foreach (String x in notExpected) { Assert.IsFalse(resText.Contains(x), "Transformed Query contained string '" + x + "' which was not expected"); } }
/// <summary> /// Runs the optimisation against a Filter algebra /// </summary> /// <param name="filter">The Filter algebra to optimise</param> /// <param name="optimisedAlgebra">Receives the optimised algebra if optimisation was performed or the input algebra otherwise</param> /// <returns>True if an optimisation was performed, false otherwise</returns> /// <remarks> /// <para>This implementation currently handles the simple case of a Filter applied to a BGP where the filter /// expression is either a single EqualsExpression or SameTermExpression or an AndExpression containing one or more /// EqualsExpression or SameTermExpression arguments. The implementation ensures that the replaced variable is still /// available to the outer algebra by inserting a BindPattern into the BGP. If the filter expression is a single /// EqualsExpression or SameTermExpression, the optimiser will also strip this out of the algebra, but with an /// AndExpression it will leave the full filter expression untouched.</para> /// <para>The implementation will replace only URI and PlainLiteral types</para> /// TODO: It should be possible to remove EqualsExpression and SameTermExpression instances from the AndExpression arguments and then either strip it out (if it has no remaining arguments), or optimise it to a single expression (if it has one remaining argument) /// </remarks> private bool OptimiseFilter(IFilter filter, out ISparqlAlgebra optimisedAlgebra) { if (!(filter.InnerAlgebra is Bgp)) { // Need a BGP to be able to insert BindPatterns for replaced variables optimisedAlgebra = filter; return(false); } var filterExpression = filter.SparqlFilter.Expression; var replacementTerms = new Dictionary <string, INode>(); string var; INode term; bool equals; // Currently only handle the simple filter cases of a single identity expression // or an AND of expressions if (IsIdentityExpression(filterExpression, out var, out term, out equals)) { if (CanOptimize(term)) { replacementTerms.Add(var, term); } } else if (filterExpression is AndExpression) { foreach (var arg in filterExpression.Arguments) { if (IsIdentityExpression(arg, out var, out term, out equals) && CanOptimize(term)) { replacementTerms.Add(var, term); } else { foreach (var variable in arg.Variables) { // Cannot guarantee that the argument doesn't imply some other possible binding for the variables replacementTerms.Remove(variable); } } } } if (replacementTerms.Any()) { var optimisedInner = filter.InnerAlgebra as Bgp; foreach (var replacementEntry in replacementTerms) { try { // Replace the variable with a constant term wherever it appears and then add a Bind pattern // to ensure that the variable is bound for use in the outer algebra var t = new VariableSubstitutionTransformer(replacementEntry.Key, replacementEntry.Value); optimisedInner = t.Optimise(optimisedInner) as Bgp; optimisedInner = new Bgp( optimisedInner.TriplePatterns.Concat(new[] { new BindPattern(replacementEntry.Key, new ConstantTerm(replacementEntry.Value)) })); } catch (RdfQueryException) { // Could not perform this replacement. } } if (filterExpression is AndExpression) { // Keep the filter as it may contain other necessary expressions // TODO: Could try to remove the identity expressions here ? optimisedAlgebra = new Filter(optimisedInner, filter.SparqlFilter); } else { // Can optimise away the filter entirely optimisedAlgebra = optimisedInner; } return(true); } optimisedAlgebra = filter; return(false); }