/// <summary> /// Optimises the Algebra to use Identity Filters where applicable /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Filter) { Filter f = (Filter)algebra; String var; INode term; bool equals = false; if (IsIdentityExpression(f.SparqlFilter.Expression, out var, out term, out equals)) { try { // Try to use the extend style optimization VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(var, term); ISparqlAlgebra extAlgebra = transformer.Optimise(f.InnerAlgebra); return(new Extend(extAlgebra, new ConstantTerm(term), var)); } catch { // Fall back to simpler Identity Filter if (equals) { return(new IdentityFilter(Optimise(f.InnerAlgebra), var, new ConstantTerm(term))); } else { return(new SameTermFilter(Optimise(f.InnerAlgebra), var, new ConstantTerm(term))); } } } else { return(f.Transform(this)); } } else if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else { return(algebra); } } catch { return(algebra); } }
/// <summary> /// Optimises the Algebra to use implict joins where applicable /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Filter) { Filter f = (Filter)algebra; String lhsVar, rhsVar; bool equals; if (this.IsImplicitJoinExpression(f.SparqlFilter.Expression, out lhsVar, out rhsVar, out equals)) { //We must ensure that both variables are in scope List <String> vars = f.InnerAlgebra.Variables.ToList(); if (vars.Contains(lhsVar) && vars.Contains(rhsVar)) { //Try to use the extend style optimization VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(rhsVar, lhsVar); if (!equals) { transformer.CanReplaceObjects = true; } ISparqlAlgebra extAlgebra = transformer.Optimise(f.InnerAlgebra); return(new Extend(extAlgebra, new VariableTerm(lhsVar), rhsVar)); } else { return(f.Transform(this)); } } else { return(f.Transform(this)); } } else if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else { return(algebra); } } catch { return(algebra); } }
/// <summary> /// Optimises the Algebra to use implict joins where applicable /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Filter) { Filter f = (Filter)algebra; String lhsVar, rhsVar; bool equals; if (IsImplicitJoinExpression(f.SparqlFilter.Expression, out lhsVar, out rhsVar, out equals)) { // We must ensure that both variables are in scope List <String> vars = f.InnerAlgebra.Variables.ToList(); if (vars.Contains(lhsVar) && vars.Contains(rhsVar)) { try { // Try to use the extend style optimization VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(rhsVar, lhsVar); if (!equals || Options.UnsafeOptimisation) { transformer.CanReplaceObjects = true; } ISparqlAlgebra extAlgebra = transformer.Optimise(f.InnerAlgebra); return(new Extend(extAlgebra, new VariableTerm(lhsVar), rhsVar)); } catch { // See if the Filtered Product style optimization applies instead int splitPoint = -1; if (IsDisjointOperation(f.InnerAlgebra, lhsVar, rhsVar, out splitPoint)) { if (splitPoint > -1) { // Means the inner algebra is a BGP we can split into two parts IBgp bgp = (IBgp)f.InnerAlgebra; return(new FilteredProduct(new Bgp(bgp.TriplePatterns.Take(splitPoint)), new Bgp(bgp.TriplePatterns.Skip(splitPoint)), f.SparqlFilter.Expression)); } else { // Means that the inner algebra is a Join where the sides are disjoint IJoin join = (IJoin)f.InnerAlgebra; return(new FilteredProduct(join.Lhs, join.Rhs, f.SparqlFilter.Expression)); } } else { return(f.Transform(this)); } } } else { return(f.Transform(this)); } } else { return(f.Transform(this)); } } else if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else { return(algebra); } } catch { return(algebra); } }
/// <summary> /// Optimises the Algebra to use Identity Filters where applicable /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Filter) { Filter f = (Filter)algebra; String var; INode term; bool equals = false; if (this.IsIdentityExpression(f.SparqlFilter.Expression, out var, out term, out equals)) { try { //Try to use the extend style optimization VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(var, term); ISparqlAlgebra extAlgebra = transformer.Optimise(f.InnerAlgebra); return new Extend(extAlgebra, new ConstantTerm(term), var); } catch { //Fall back to simpler Identity Filter if (equals) { return new IdentityFilter(this.Optimise(f.InnerAlgebra), var, new ConstantTerm(term)); } else { return new SameTermFilter(this.Optimise(f.InnerAlgebra), var, new ConstantTerm(term)); } } } else { return f.Transform(this); } } else if (algebra is IAbstractJoin) { return ((IAbstractJoin)algebra).Transform(this); } else if (algebra is IUnaryOperator) { return ((IUnaryOperator)algebra).Transform(this); } else { return algebra; } } catch { return algebra; } }
/// <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; }
/// <summary> /// Optimises the Algebra to use implict joins where applicable /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Filter) { Filter f = (Filter)algebra; String lhsVar, rhsVar; bool equals; if (this.IsImplicitJoinExpression(f.SparqlFilter.Expression, out lhsVar, out rhsVar, out equals)) { //We must ensure that both variables are in scope List<String> vars = f.InnerAlgebra.Variables.ToList(); if (vars.Contains(lhsVar) && vars.Contains(rhsVar)) { //Try to use the extend style optimization VariableSubstitutionTransformer transformer = new VariableSubstitutionTransformer(rhsVar, lhsVar); if (!equals) transformer.CanReplaceObjects = true; ISparqlAlgebra extAlgebra = transformer.Optimise(f.InnerAlgebra); return new Extend(extAlgebra, new VariableTerm(lhsVar), rhsVar); } else { return f.Transform(this); } } else { return f.Transform(this); } } else if (algebra is IAbstractJoin) { return ((IAbstractJoin)algebra).Transform(this); } else if (algebra is IUnaryOperator) { return ((IUnaryOperator)algebra).Transform(this); } else { return algebra; } } catch { return algebra; } }