/// <summary> /// Creates a new Slice modifier which uses a specific LIMIT and OFFSET. /// </summary> /// <param name="pattern">Pattern.</param> /// <param name="limit">Limit.</param> /// <param name="offset">Offset.</param> public Slice(ISparqlAlgebra pattern, int limit, int offset) : this(pattern) { _limit = Math.Max(-1, limit); _offset = Math.Max(0, offset); _detectSettings = false; }
public void FullTextOptimiserComplex4() { SparqlQuery q = this.TestOptimisation("SELECT * WHERE { (?s ?score) pf:textMatch 'value' . BIND(STR(?s) AS ?str) }"); ISparqlAlgebra algebra = q.ToAlgebra(); Assert.DoesNotContain("PropertyFunction(Extend(", algebra.ToString()); }
/// <summary> /// Optimises an Algebra to a form that uses <see cref="LazyBgp">LazyBgp</see> where possible /// </summary> /// <param name="algebra">Algebra</param> /// <param name="depth">Depth</param> /// <returns></returns> /// <remarks> /// <para> /// By transforming a query to use <see cref="LazyBgp">LazyBgp</see> we can achieve much more efficient processing of some forms of queries /// </para> /// </remarks> protected override ISparqlAlgebra OptimiseInternal(ISparqlAlgebra algebra, int depth) { try { ISparqlAlgebra temp; //Note this first test is specifically for the default BGP implementation since other optimisers //may run before us and replace with other BGP implementations which we don't want to replace hence //why we don't check for IBgp here if (algebra is Bgp) { temp = new LazyBgp(((Bgp)algebra).TriplePatterns); } //else if (algebra is ILeftJoin) //{ // ILeftJoin join = (ILeftJoin)algebra; // temp = new LeftJoin(this.OptimiseInternal(join.Lhs, depth + 1), join.Rhs, ((LeftJoin)algebra).Filter); //} else if (algebra is IUnion) { IUnion join = (IUnion)algebra; temp = new LazyUnion(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); } else if (algebra is IJoin) { IJoin join = (IJoin)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { //If the sides of the Join are disjoint then can fully transform the join since we only need to find the requisite number of //solutions on either side to guarantee a product which meets/exceeds the required results //temp = new Join(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.Transform(this); } else { //If the sides are not disjoint then the LHS must be fully evaluated but the RHS need only produce enough //solutions that match //temp = new Join(join.Lhs, this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.TransformRhs(this); } } else if (algebra is Algebra.Graph) { //Algebra.Graph g = (Algebra.Graph)algebra; //temp = new Algebra.Graph(this.OptimiseInternal(g.InnerAlgebra, depth + 1), g.GraphSpecifier); IUnaryOperator op = (IUnaryOperator)algebra; temp = op.Transform(this); } else { temp = algebra; } return temp; } catch { //If the Optimise fails return the current algebra return algebra; } }
public void SparqlSequenceUpdateThenQuery2() { InMemoryDataset dataset = new InMemoryDataset(); LeviathanUpdateProcessor updateProcessor = new LeviathanUpdateProcessor(dataset); LeviathanQueryProcessor queryProcessor = new LeviathanQueryProcessor(dataset); Assert.Single(dataset.Graphs); SparqlUpdateCommandSet updates = this._updateParser.ParseFromFile("resources\\sparql\\protocol\\update_dataset_default_graphs.ru"); updateProcessor.ProcessCommandSet(updates); Assert.Equal(5, dataset.Graphs.Count()); Assert.Equal(2, dataset[UriFactory.Create("http://example.org/protocol-update-dataset-graphs-test/")].Triples.Count()); SparqlQuery query = this._queryParser.ParseFromFile("resources\\sparql\\protocol\\update_dataset_default_graphs.rq"); ISparqlAlgebra algebra = query.ToAlgebra(); Console.WriteLine(algebra.ToString()); SparqlResultSet results = queryProcessor.ProcessQuery(query) as SparqlResultSet; Assert.NotNull(results); Assert.Equal(SparqlResultsType.Boolean, results.ResultsType); Assert.True(results.Result); }
/// <summary> /// Tries to substitute variables within primary expressions /// </summary> /// <param name="expr">Expression</param> /// <returns></returns> protected override ISparqlExpression SubstitutePrimaryExpression(ISparqlExpression expr) { if (expr is VariableTerm) { if (expr.Variables.First().Equals(_findVar)) { return(_replaceExpr); } else { return(expr); } } else if (expr is GraphPatternTerm) { GraphPatternTerm gp = (GraphPatternTerm)expr; ISparqlAlgebra alg = gp.Pattern.ToAlgebra(); alg = Optimise(alg); return(new GraphPatternTerm(alg.ToGraphPattern())); } else { return(expr); } }
public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { ISparqlAlgebra optimised; var bgp = algebra as Bgp; if (bgp != null) { return(OptimiseBgp(bgp, out optimised) ? optimised : bgp); } var filter = algebra as IFilter; if (filter != null) { return(OptimiseFilter(filter, out optimised) ? optimised : filter); } var abstractJoin = algebra as IAbstractJoin; if (abstractJoin != null) { return(abstractJoin.Transform(this)); } var unaryOperator = algebra as IUnaryOperator; if (unaryOperator != null) { return(unaryOperator.Transform(this)); } return(algebra); } catch { return(algebra); } }
public void SparqlGraphPatternToAlgebra8() { GraphPattern gp = new GraphPattern(); gp.IsGraph = true; gp.GraphSpecifier = new VariableToken("g", 0, 0, 1); ISparqlAlgebra algebra = gp.ToAlgebra(); Assert.IsType <Graph>(algebra); Graph g = (Graph)algebra; Assert.IsAssignableFrom <IBgp>(g.InnerAlgebra); // Nest in another graph pattern with different specifier GraphPattern parent = new GraphPattern(); parent.IsGraph = true; parent.GraphSpecifier = new UriToken("<http://example.org>", 0, 0, 0); parent.AddGraphPattern(gp); // Resulting algebra must nest the graph clauses algebra = parent.ToAlgebra(); Assert.IsType <Graph>(algebra); g = (Graph)algebra; Assert.Equal(parent.GraphSpecifier.Value, g.GraphSpecifier.Value); Assert.IsType <Graph>(g.InnerAlgebra); g = (Graph)g.InnerAlgebra; Assert.Equal(gp.GraphSpecifier.Value, g.GraphSpecifier.Value); Assert.IsAssignableFrom <IBgp>(g.InnerAlgebra); }
public void SparqlGraphPatternToAlgebra2() { GraphPattern up = new GraphPattern(); up.IsUnion = true; GraphPattern gp = new GraphPattern(); gp.IsGraph = true; gp.GraphSpecifier = new VariableToken("g", 0, 0, 1); up.AddGraphPattern(gp); GraphPattern empty = new GraphPattern(); up.AddGraphPattern(empty); ISparqlAlgebra algebra = up.ToAlgebra(); Assert.IsType(typeof(Union), algebra); Union u = (Union)algebra; Assert.IsType(typeof(Graph), u.Lhs); Graph g = (Graph)u.Lhs; Assert.IsAssignableFrom(typeof(IBgp), g.InnerAlgebra); Assert.IsAssignableFrom(typeof(IBgp), u.Rhs); }
public void SparqlGraphPatternToAlgebra4() { GraphPattern up = new GraphPattern(); up.IsUnion = true; GraphPattern gp = new GraphPattern(); gp.IsService = true; gp.GraphSpecifier = new VariableToken("g", 0, 0, 1); up.AddGraphPattern(gp); GraphPattern empty = new GraphPattern(); up.AddGraphPattern(empty); ISparqlAlgebra algebra = up.ToAlgebra(); Assert.IsInstanceOf(typeof(Union), algebra); Union u = (Union)algebra; Assert.IsInstanceOf(typeof(Service), u.Lhs); Assert.IsInstanceOf(typeof(IBgp), u.Rhs); }
/// <summary> /// Optimises the algebra to use parallelised variants of <see cref="Join">Join</see> and <see cref="Union">Union</see> where possible /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { if (algebra is Join) { Join join = (Join)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { return new ParallelJoin(this.Optimise(join.Lhs), this.Optimise(join.Rhs)); } else { return join.Transform(this); } } else if (algebra is Union) { Union u = (Union)algebra; return new ParallelUnion(this.Optimise(u.Lhs), this.Optimise(u.Rhs)); } else { return ((IAbstractJoin)algebra).Transform(this); } } else if (algebra is IUnaryOperator) { return ((IUnaryOperator)algebra).Transform(this); } else { return algebra; } }
public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { ISparqlAlgebra optimised; var bgp = algebra as Bgp; if (bgp != null) { return OptimiseBgp(bgp, out optimised) ? optimised : bgp; } var filter = algebra as IFilter; if (filter != null) { return OptimiseFilter(filter, out optimised) ? optimised : filter; } var abstractJoin = algebra as IAbstractJoin; if (abstractJoin != null) { return abstractJoin.Transform(this); } var unaryOperator = algebra as IUnaryOperator; if (unaryOperator != null) { return unaryOperator.Transform(this); } return algebra; } catch { return algebra; } }
public void SparqlGraphPatternToAlgebra4() { GraphPattern up = new GraphPattern(); up.IsUnion = true; GraphPattern gp = new GraphPattern(); gp.IsService = true; gp.GraphSpecifier = new VariableToken("g", 0, 0, 1); up.AddGraphPattern(gp); GraphPattern empty = new GraphPattern(); up.AddGraphPattern(empty); ISparqlAlgebra algebra = up.ToAlgebra(); Assert.IsType <Union>(algebra); Union u = (Union)algebra; Assert.IsType <Service>(u.Lhs); Assert.IsAssignableFrom <IBgp>(u.Rhs); }
private void TestClassification(ISparqlAlgebra algebra, List <String> expectedFixed, List <String> expectedFloating) { expectedFixed.Sort(); expectedFloating.Sort(); List <String> actualFixed = algebra.FixedVariables.ToList(); actualFixed.Sort(); List <String> actualFloating = algebra.FloatingVariables.ToList(); actualFloating.Sort(); Console.WriteLine("Expected Fixed: " + String.Join(",", expectedFixed)); Console.WriteLine("Actual Fixed: " + String.Join(",", actualFixed)); Console.WriteLine("Expected Floating: " + String.Join(",", expectedFloating)); Console.WriteLine("Actual Floating: " + String.Join(",", actualFloating)); Console.WriteLine(); // Check fixed and floating are correct Assert.AreEqual(expectedFixed, actualFixed); Assert.AreEqual(expectedFloating, actualFloating); // A variable can't be both fixed and floating Assert.IsTrue(actualFixed.All(v => !actualFloating.Contains(v))); Assert.IsTrue(actualFloating.All(v => !actualFixed.Contains(v))); }
/// <summary> /// Creates a new Join /// </summary> /// <param name="lhs">Left Hand Side</param> /// <param name="rhs">Right Hand Side</param> public ParallelJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs) { if (!lhs.Variables.IsDisjoint(rhs.Variables)) throw new RdfQueryException("Cannot create a ParallelJoin between two algebra operators which are not distinct"); this._lhs = lhs; this._rhs = rhs; this._d = new ParallelEvaluateDelegate(this.ParallelEvaluate); }
internal ISparqlAlgebra ApplyAlgebraOptimisers(ISparqlAlgebra algebra) { try { //Apply Local Optimisers foreach (IAlgebraOptimiser opt in this._optimisers.Where(o => o.IsApplicable(this))) { try { algebra = opt.Optimise(algebra); } catch { //Ignore errors - if an optimiser errors then we leave the algebra unchanged } } //Apply Global Optimisers foreach (IAlgebraOptimiser opt in SparqlOptimiser.AlgebraOptimisers.Where(o => o.IsApplicable(this))) { try { algebra = opt.Optimise(algebra); } catch { //Ignore errors - if an optimiser errors then we leave the algebra unchanged } } return(algebra); } catch { return(algebra); } }
/// <summary> /// Explains the end of evaluating some algebra operator /// </summary> /// <param name="algebra">Algebra</param> /// <param name="context">Context</param> private void ExplainEvaluationEnd(ISparqlAlgebra algebra, SparqlEvaluationContext context) { if (this._level == ExplanationLevel.None) { return; } this._depthCounter.Value--; StringBuilder output = new StringBuilder(); if (this.HasFlag(ExplanationLevel.ShowThreadID)) { output.Append("[Thread ID " + Thread.CurrentThread.ManagedThreadId + "] "); } if (this.HasFlag(ExplanationLevel.ShowDepth)) { output.Append("Depth " + this._depthCounter.Value + " "); } if (this.HasFlag(ExplanationLevel.ShowOperator)) { output.Append(algebra.GetType().FullName + " "); } if (this.HasFlag(ExplanationLevel.ShowAction)) { output.Append("End"); } this.PrintExplanations(output); }
public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { var j = algebra as IJoin; if (j != null) { var bgp = j.Lhs as IBgp; if (bgp != null) { var leftBgp = bgp; if (leftBgp.TriplePatterns.All(x => x.IsAcceptAll)) { if (bgp.FixedVariables.Any(x => j.Rhs.FixedVariables.Contains(x))) { if (bgp.FloatingVariables.All(floater => j.Rhs.FixedVariables.Contains(floater))) { return new LeftJoin(j.Rhs, j.Lhs); } } } } } return algebra; } catch { return algebra; } }
/// <summary> /// Optimises the algebra to use parallelised variants of <see cref="Join">Join</see> and <see cref="Union">Union</see> where possible /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { if (algebra is Join) { Join join = (Join)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { return(new ParallelJoin(this.Optimise(join.Lhs), this.Optimise(join.Rhs))); } else { return(join.Transform(this)); } } else if (algebra is Union) { Union u = (Union)algebra; return(new ParallelUnion(this.Optimise(u.Lhs), this.Optimise(u.Rhs))); } else { return(((IAbstractJoin)algebra).Transform(this)); } } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else { return(algebra); } }
public void SparqlGraphPatternToAlgebra7() { GraphPattern gp = new GraphPattern(); gp.IsGraph = true; gp.GraphSpecifier = new VariableToken("g", 0, 0, 1); ISparqlAlgebra algebra = gp.ToAlgebra(); Assert.IsType <Graph>(algebra); Graph g = (Graph)algebra; Assert.IsAssignableFrom <IBgp>(g.InnerAlgebra); // Nest in another graph pattern with same specifier GraphPattern parent = new GraphPattern(); parent.IsGraph = true; parent.GraphSpecifier = gp.GraphSpecifier; parent.AddGraphPattern(gp); // Resulting algebra will collapse the two graph clauses into a single one algebra = parent.ToAlgebra(); Assert.IsType <Graph>(algebra); g = (Graph)algebra; Assert.IsAssignableFrom <IBgp>(g.InnerAlgebra); }
private void RunTest(ISparqlPath path, IEnumerable <String> expectedOperators) { VariablePattern x = new VariablePattern("?x"); VariablePattern y = new VariablePattern("?y"); PathTransformContext context = new PathTransformContext(x, y); Console.WriteLine("Path: " + path.ToString()); ISparqlAlgebra algebra = path.ToAlgebra(context); String result = algebra.ToString(); Console.WriteLine("Algebra: " + result); try { GraphPattern gp = algebra.ToGraphPattern(); Console.WriteLine("GraphPattern:"); Console.WriteLine(this._formatter.Format(gp)); Console.WriteLine(); } catch { Console.WriteLine("Algebra not translatable to a GraphPattern"); } foreach (String op in expectedOperators) { if (result.Contains(op)) { continue; } Console.WriteLine("Expected Operator '" + op + "' missing"); Assert.True(false, "Expected Operator '" + op + "' missing"); } }
/// <summary> /// Creates a new Slice modifier which uses a specific LIMIT and OFFSET /// </summary> /// <param name="pattern">Pattern</param> /// <param name="limit">Limit</param> /// <param name="offset">Offset</param> public Slice(ISparqlAlgebra pattern, int limit, int offset) : this(pattern) { this._limit = Math.Max(-1, limit); this._offset = Math.Max(0, offset); this._detectSettings = false; }
/// <summary> /// Optimises an Algebra to a form that uses <see cref="LazyBgp">LazyBgp</see> where possible /// </summary> /// <param name="algebra">Algebra</param> /// <param name="depth">Depth</param> /// <returns></returns> /// <remarks> /// <para> /// By transforming a query to use <see cref="LazyBgp">LazyBgp</see> we can achieve much more efficient processing of some forms of queries /// </para> /// </remarks> protected override ISparqlAlgebra OptimiseInternal(ISparqlAlgebra algebra, int depth) { try { ISparqlAlgebra temp; //Note this first test is specifically for the default BGP implementation since other optimisers //may run before us and replace with other BGP implementations which we don't want to replace hence //why we don't check for IBgp here if (algebra is Bgp) { temp = new LazyBgp(((Bgp)algebra).TriplePatterns); } //else if (algebra is ILeftJoin) //{ // ILeftJoin join = (ILeftJoin)algebra; // temp = new LeftJoin(this.OptimiseInternal(join.Lhs, depth + 1), join.Rhs, ((LeftJoin)algebra).Filter); //} else if (algebra is IUnion) { IUnion join = (IUnion)algebra; temp = new LazyUnion(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); } else if (algebra is IJoin) { IJoin join = (IJoin)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { //If the sides of the Join are disjoint then can fully transform the join since we only need to find the requisite number of //solutions on either side to guarantee a product which meets/exceeds the required results //temp = new Join(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.Transform(this); } else { //If the sides are not disjoint then the LHS must be fully evaluated but the RHS need only produce enough //solutions that match //temp = new Join(join.Lhs, this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.TransformRhs(this); } } else if (algebra is Algebra.Graph) { //Algebra.Graph g = (Algebra.Graph)algebra; //temp = new Algebra.Graph(this.OptimiseInternal(g.InnerAlgebra, depth + 1), g.GraphSpecifier); IUnaryOperator op = (IUnaryOperator)algebra; temp = op.Transform(this); } else { temp = algebra; } return(temp); } catch { //If the Optimise fails return the current algebra return(algebra); } }
public void FullTextOptimiserComplex3() { SparqlQuery q = this.TestOptimisation("SELECT * WHERE { ?s pf:textMatch 'value' . BIND(STR(?s) AS ?str) }"); ISparqlAlgebra algebra = q.ToAlgebra(); Assert.False(algebra.ToString().Contains("PropertyFunction(Extend(")); }
/// <summary> /// Processes a Unknown Operator /// </summary> /// <param name="algebra">Unknown Operator</param> /// <param name="context">SPARQL Evaluation Context</param> public virtual BaseMultiset ProcessUnknownOperator(ISparqlAlgebra algebra, SparqlEvaluationContext context) { if (context == null) { context = this.GetContext(); } return(algebra.Evaluate(context)); }
/// <summary> /// Optimises the Algebra for evaluation against an ADO Store /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { foreach (IAlgebraOptimiser opt in this._optimisers) { algebra = opt.Optimise(algebra); } return(algebra); }
/// <summary> /// Converts a Path into its Algebra Form /// </summary> /// <param name="context">Path Transformation Context</param> /// <returns></returns> public override ISparqlAlgebra ToAlgebra(PathTransformContext context) { PathTransformContext lhsContext = new PathTransformContext(context); PathTransformContext rhsContext = new PathTransformContext(context); ISparqlAlgebra lhs = this._lhs.ToAlgebra(lhsContext); ISparqlAlgebra rhs = this._rhs.ToAlgebra(rhsContext); return(new Union(lhs, rhs)); }
/// <summary> /// Converts a Path into its Algebra Form /// </summary> /// <param name="context">Path Transformation Context</param> /// <returns></returns> public override ISparqlAlgebra ToAlgebra(PathTransformContext context) { PathTransformContext lhsContext = new PathTransformContext(context); PathTransformContext rhsContext = new PathTransformContext(context); ISparqlAlgebra lhs = new ZeroLengthPath(lhsContext.Subject, lhsContext.Object, this._path); ISparqlAlgebra rhs = this._path.ToAlgebra(rhsContext); return(new Distinct(new Union(lhs, rhs))); }
/// <summary> /// Evaluates the subquery in the given context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Use the same algebra optimisers as the parent query (if any) if (context.Query != null) { this._subquery.AlgebraOptimisers = context.Query.AlgebraOptimisers; } if (context.InputMultiset is NullMultiset) { context.OutputMultiset = context.InputMultiset; } else if (context.InputMultiset.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { SparqlEvaluationContext subcontext = new SparqlEvaluationContext(this._subquery, context.Data, context.Processor); subcontext.InputMultiset = context.InputMultiset; //Add any Named Graphs to the subquery if (context.Query != null) { foreach (Uri u in context.Query.NamedGraphs) { this._subquery.AddNamedGraph(u); } } ISparqlAlgebra query = this._subquery.ToAlgebra(); try { //Evaluate the Subquery context.OutputMultiset = subcontext.Evaluate(query); //If the Subquery contains a GROUP BY it may return a Group Multiset in which case we must flatten this to a Multiset if (context.OutputMultiset is GroupMultiset) { context.OutputMultiset = new Multiset((GroupMultiset)context.OutputMultiset); } //Strip out any Named Graphs from the subquery if (this._subquery.NamedGraphs.Any()) { this._subquery.ClearNamedGraphs(); } } catch (RdfQueryException queryEx) { throw new RdfQueryException("Query failed due to a failure in Subquery Execution:\n" + queryEx.Message, queryEx); } } return(context.OutputMultiset); }
/// <summary> /// Creates a new Full Text Operator /// </summary> /// <param name="provider">Search Provider</param> /// <param name="algebra">Inner Algebra</param> /// <param name="matchVar">Match Variable</param> /// <param name="scoreVar">Score Variable</param> /// <param name="searchTerm">Search Term</param> /// <param name="limit">Limit</param> /// <param name="scoreThreshold">Score Threshold</param> public BaseFullTextOperator(IFullTextSearchProvider provider, ISparqlAlgebra algebra, PatternItem matchVar, PatternItem scoreVar, PatternItem searchTerm, int limit, double scoreThreshold) { this._provider = provider; this.InnerAlgebra = algebra; this._matchVar = matchVar; this._scoreVar = scoreVar; this._searchTerm = searchTerm; this._limit = limit; this._scoreThreshold = scoreThreshold; }
/// <summary> /// Creates a new Join /// </summary> /// <param name="lhs">Left Hand Side</param> /// <param name="rhs">Right Hand Side</param> public ParallelJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs) { if (!lhs.Variables.IsDisjoint(rhs.Variables)) { throw new RdfQueryException("Cannot create a ParallelJoin between two algebra operators which are not distinct"); } this._lhs = lhs; this._rhs = rhs; this._d = new ParallelEvaluateDelegate(this.ParallelEvaluate); }
/// <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> /// Prints Analysis /// </summary> /// <param name="algebra">Algebra</param> private void PrintAnalysis(ISparqlAlgebra algebra) { if (algebra is IBgp) { this.PrintBgpAnalysis((IBgp)algebra); } else if (algebra is IAbstractJoin) { this.PrintJoinAnalysis((IAbstractJoin)algebra); } }
public void SparqlGraphPatternToAlgebra3() { GraphPattern gp = new GraphPattern(); gp.IsService = true; gp.GraphSpecifier = new UriToken("<http://example.org/sparql>", 0, 0, 0); ISparqlAlgebra algebra = gp.ToAlgebra(); Assert.IsType <Service>(algebra); }
/// <summary> /// Evalutes an Algebra Operator in this Context using the current Query Processor (if any) or the default <see cref="ISparqlAlgebra.Evaluate">Evaluate()</see> method. /// </summary> /// <param name="algebra">Algebra.</param> /// <returns></returns> public BaseMultiset Evaluate(ISparqlAlgebra algebra) { if (_processor == null) { return(algebra.Evaluate(this)); } else { return(_processor.ProcessAlgebra(algebra, this)); } }
/// <summary> /// Creates a new Extend operator /// </summary> /// <param name="pattern">Pattern</param> /// <param name="expr">Expression</param> /// <param name="var">Variable to bind to</param> public Extend(ISparqlAlgebra pattern, ISparqlExpression expr, String var) { this._inner = pattern; this._expr = expr; this._var = var; if (this._inner.Variables.Contains(this._var)) { throw new RdfQueryException("Cannot create an Extend() operator which extends the results of the inner algebra with a variable that is already used in the inner algebra"); } }
/// <summary> /// Creates a new Extend operator. /// </summary> /// <param name="pattern">Pattern.</param> /// <param name="expr">Expression.</param> /// <param name="var">Variable to bind to.</param> public Extend(ISparqlAlgebra pattern, ISparqlExpression expr, String var) { _inner = pattern; _expr = expr; _var = var; if (_inner.Variables.Contains(_var)) { throw new RdfQueryException("Cannot create an Extend() operator which extends the results of the inner algebra with a variable that is already used in the inner algebra"); } }
/// <summary> /// Evaluates a property path pattern /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlEvaluationContext context) { // Try and generate an Algebra expression // Make sure we don't generate clashing temporary variable IDs over the life of the // Evaluation PathTransformContext transformContext = new PathTransformContext(_subj, _obj); if (context["PathTransformID"] != null) { transformContext.NextID = (int)context["PathTransformID"]; } ISparqlAlgebra algebra = _path.ToAlgebra(transformContext); context["PathTransformID"] = transformContext.NextID + 1; // Now we can evaluate the resulting algebra BaseMultiset initialInput = context.InputMultiset; bool trimMode = context.TrimTemporaryVariables; bool rigMode = Options.RigorousEvaluation; try { // Must enable rigorous evaluation or we get incorrect interactions between property and non-property path patterns Options.RigorousEvaluation = true; // Note: We may need to preserve Blank Node variables across evaluations // which we usually don't do BUT because of the way we translate only part of the path // into an algebra at a time and may need to do further nested translate calls we do // need to do this here context.TrimTemporaryVariables = false; BaseMultiset result = context.Evaluate(algebra);//algebra.Evaluate(context); // Also note that we don't trim temporary variables here even if we've set the setting back // to enabled since a Trim will be done at the end of whatever BGP we are being evaluated in // Once we have our results can join then into our input if (result is NullMultiset) { context.OutputMultiset = new NullMultiset(); } else { context.OutputMultiset = initialInput.Join(result); } // If we reach here we've successfully evaluated the simple pattern and can return return; } finally { context.TrimTemporaryVariables = trimMode; Options.RigorousEvaluation = rigMode; } }
/// <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)) { if (equals) { return new IdentityFilter(this.Optimise(f.InnerAlgebra), var, new NodeExpressionTerm(term)); } else { return new SameTermFilter(this.Optimise(f.InnerAlgebra), var, new NodeExpressionTerm(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 BGPs in the Algebra to use Filter() and Extend() rather than the embedded FILTER and BIND /// </summary> /// <param name="algebra">Algebra to optimise</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return ((IAbstractJoin)algebra).Transform(this); } else if (algebra is IUnaryOperator) { return ((IUnaryOperator)algebra).Transform(this); } else if (algebra is IBgp) { //Don't integerfer with other optimisers which have added custom BGP implementations if (!(algebra is Bgp)) return algebra; IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return current; } else { ISparqlAlgebra result = new Bgp(); List<ITriplePattern> patterns = new List<ITriplePattern>(); List<ITriplePattern> ps = new List<ITriplePattern>(current.TriplePatterns.ToList()); for (int i = 0; i < current.PatternCount; i++) { //Can't split the BGP if there are Blank Nodes present if (!ps[i].HasNoBlankVariables) return current; if (!(ps[i] is TriplePattern)) { //First ensure that if we've found any other Triple Patterns up to this point //we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } //Then generate the appropriate strict algebra operator if (ps[i] is FilterPattern) { result = new Filter(result, ((FilterPattern)ps[i]).Filter); } else if (ps[i] is BindPattern) { BindPattern bind = (BindPattern)ps[i]; result = new Extend(result, bind.AssignExpression, bind.VariableName); } else if (ps[i] is LetPattern) { LetPattern let = (LetPattern)ps[i]; result = new Extend(result, let.AssignExpression, let.VariableName); } else if (ps[i] is SubQueryPattern) { SubQueryPattern sq = (SubQueryPattern)ps[i]; result = Join.CreateJoin(result, new SubQuery(sq.SubQuery)); } else if (ps[i] is PropertyPathPattern) { PropertyPathPattern pp = (PropertyPathPattern)ps[i]; result = Join.CreateJoin(result, new PropertyPath(pp.Subject, pp.Path, pp.Object)); } } else { patterns.Add(ps[i]); } } if (patterns.Count == current.PatternCount) { //If count of remaining patterns same as original pattern count there was no optimisation //to do so return as is return current; } else if (patterns.Count > 0) { //If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return result; } else { return result; } } } else if (algebra is ITerminalOperator) { return algebra; } else { return algebra; } }
/// <summary> /// Creates a new ASK /// </summary> /// <param name="pattern">Inner Pattern</param> public Ask(ISparqlAlgebra pattern) { this._pattern = pattern; }
/// <summary> /// Creates a new Filter /// </summary> /// <param name="pattern">Algebra the Filter applies over</param> /// <param name="filter">Filter to apply</param> public Filter(ISparqlAlgebra pattern, ISparqlFilter filter) { this._pattern = pattern; this._filter = filter; }
/// <summary> /// Evalutes an Algebra Operator in this Context using the current Query Processor (if any) or the default <see cref="ISparqlAlgebra.Evaluate">Evaluate()</see> method /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public BaseMultiset Evaluate(ISparqlAlgebra algebra) { if (this._processor == null) { return algebra.Evaluate(this); } else { return this._processor.ProcessAlgebra(algebra, this); } }
/// <summary> /// Creates a new Graph clause /// </summary> /// <param name="pattern">Pattern</param> /// <param name="graphSpecifier">Graph Specifier</param> public Graph(ISparqlAlgebra pattern, IToken graphSpecifier) { this._pattern = pattern; this._graphSpecifier = graphSpecifier; }
/// <summary> /// Creates a new Projection /// </summary> /// <param name="pattern">Inner pattern</param> /// <param name="variables">Variables that should be Projected</param> public Project(ISparqlAlgebra pattern, IEnumerable<SparqlVariable> variables) { this._pattern = pattern; this._variables.AddRange(variables); }
/// <summary> /// Creates a new Having Clause /// </summary> /// <param name="pattern">Pattern</param> /// <param name="having">Having Clause</param> public Having(ISparqlAlgebra pattern, ISparqlFilter having) { this._pattern = pattern; this._having = having; }
/// <summary> /// Creates a new Distinct Modifier /// </summary> /// <param name="pattern">Pattern</param> public Distinct(ISparqlAlgebra pattern) { this._pattern = pattern; }
/// <summary> /// Creates a new Exists Join /// </summary> /// <param name="lhs">LHS Pattern</param> /// <param name="rhs">RHS Pattern</param> /// <param name="mustExist">Whether a joinable set must exist on the RHS for the LHS set to be preserved</param> public ExistsJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs, bool mustExist) { this._lhs = lhs; this._rhs = rhs; this._mustExist = mustExist; }
/// <summary> /// Creates a new Union /// </summary> /// <param name="lhs">LHS Pattern</param> /// <param name="rhs">RHS Pattern</param> public Union(ISparqlAlgebra lhs, ISparqlAlgebra rhs) { this._lhs = lhs; this._rhs = rhs; }
/// <summary> /// Creates either a Join or returns just one of the sides of the Join if one side is the empty BGP /// </summary> /// <param name="lhs">Left Hand Side</param> /// <param name="rhs">Right Hand Side</param> /// <returns></returns> public static ISparqlAlgebra CreateJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs) { if (lhs is Bgp) { if (((Bgp)lhs).IsEmpty) { return rhs; } else if (rhs is Bgp) { if (((Bgp)rhs).IsEmpty) { return lhs; } else { return new Join(lhs, rhs); } } else { return new Join(lhs, rhs); } } else if (rhs is Bgp) { if (((Bgp)rhs).IsEmpty) { return lhs; } else { return new Join(lhs, rhs); } } else { return new Join(lhs, rhs); } }
/// <summary> /// Creates a new LeftJoin where there is a Filter over the join /// </summary> /// <param name="lhs">LHS Pattern</param> /// <param name="rhs">RHS Pattern</param> /// <param name="filter">Filter to decide which RHS solutions are valid</param> public LeftJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs, ISparqlFilter filter) { this._lhs = lhs; this._rhs = rhs; this._filter = filter; }
/// <summary> /// Creates a new LeftJoin where there is no Filter over the join /// </summary> /// <param name="lhs">LHS Pattern</param> /// <param name="rhs">RHS Pattern</param> public LeftJoin(ISparqlAlgebra lhs, ISparqlAlgebra rhs) { this._lhs = lhs; this._rhs = rhs; }
/// <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> /// Creates a new Group By /// </summary> /// <param name="pattern">Pattern</param> /// <param name="grouping">Grouping to use</param> public GroupBy(ISparqlAlgebra pattern, ISparqlGroupBy grouping) { this._pattern = pattern; this._grouping = grouping; }
/// <summary> /// Creates a new Slice modifier which will detect LIMIT and OFFSET from the query /// </summary> /// <param name="pattern">Pattern</param> public Slice(ISparqlAlgebra pattern) { this._pattern = pattern; }
internal ISparqlAlgebra ApplyAlgebraOptimisers(ISparqlAlgebra algebra) { try { //Apply Local Optimisers foreach (IAlgebraOptimiser opt in this._optimisers.Where(o => o.IsApplicable(this))) { try { algebra = opt.Optimise(algebra); } catch { //Ignore errors - if an optimiser errors then we leave the algebra unchanged } } //Apply Global Optimisers foreach (IAlgebraOptimiser opt in SparqlOptimiser.AlgebraOptimisers.Where(o => o.IsApplicable(this))) { try { algebra = opt.Optimise(algebra); } catch { //Ignore errors - if an optimiser errors then we leave the algebra unchanged } } return algebra; } catch { return algebra; } }
/// <summary> /// Attempts to optimise an Algebra to another more optimal form /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public virtual ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { return this.OptimiseInternal(algebra, 0); }
private BaseMultiset ParallelEvaluate(ISparqlAlgebra algebra, SparqlEvaluationContext context, IGraph activeGraph, IGraph defGraph) { bool activeGraphOk = false, defaultGraphOk = false; try { //Set the Active Graph if (activeGraph != null) { context.Data.SetActiveGraph(activeGraph); activeGraphOk = true; } //Set the Default Graph if (defGraph != null) { context.Data.SetDefaultGraph(defGraph); defaultGraphOk = true; } //Evaluate the algebra and return the result return context.Evaluate(algebra); } catch { throw; } finally { if (defaultGraphOk) { try { context.Data.ResetDefaultGraph(); } catch { //Ignore reset exceptions } } if (activeGraphOk) { try { context.Data.ResetActiveGraph(); } catch { //Ignore reset exceptions } } } }
/// <summary> /// Transforms the Algebra to another form tracking the depth in the Algebra tree /// </summary> /// <param name="algebra">Algebra</param> /// <param name="depth">Depth</param> /// <returns></returns> protected abstract ISparqlAlgebra OptimiseInternal(ISparqlAlgebra algebra, int depth);
/// <summary> /// Optimises the Algebra so that BGPs containing relevant patterns are converted to use the <see cref="FullTextMatch">FullTextMatch</see> operator /// </summary> /// <param name="algebra">Algebra to optimise</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return ((IAbstractJoin)algebra).Transform(this); } else if (algebra is IUnaryOperator) { return ((IUnaryOperator)algebra).Transform(this); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return current; } else { ISparqlAlgebra result = new Bgp(); List<FullTextPattern> fps = FullTextHelper.ExtractPatterns(current.TriplePatterns); if (fps.Count == 0) return algebra; List<ITriplePattern> ps = current.TriplePatterns.ToList(); //First we want to find where each FullTextPattern is located in the original triple patterns Dictionary<int, int> locations = new Dictionary<int, int>(); for (int i = 0; i < fps.Count; i++) { locations.Add(i, -1); ITriplePattern first = fps[i].OriginalPatterns.First(); for (int j = 0; j < ps.Count; j++) { if (first.Equals(ps[j])) { locations[i] = j; break; } } //If we fail to locate this we've failed to optimise here so must abort if (locations[i] == -1) return algebra; } //Knowing this we can then start splitting the BGP into several BGPs int locBase = 0; foreach (int i in Enumerable.Range(0, fps.Count).OrderBy(x => locations[x]).ToList()) { //Wrap everything up to that point in a BGP excluding any patterns relevant to any FullTextPattern result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Take(locations[i]).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp))))); locBase = locations[i] + 1; //Then apply the FullTextMatch operator over it FullTextPattern ftp = fps[i]; result = new FullTextMatch(this._provider, result, ftp.MatchVariable, ftp.ScoreVariable, ftp.SearchTerm, ftp.Limit, ftp.ScoreThreshold); } //If there are any patterns left over remember to include them if (locBase < ps.Count) { result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp))))); } return result; //List<ITriplePattern> patterns = new List<ITriplePattern>(); //List<ITriplePattern> ps = new List<ITriplePattern>(current.TriplePatterns.ToList()); //for (int i = 0; i < current.PatternCount; i++) //{ // if (!(ps[i] is TriplePattern)) // { // patterns.Add(ps[i]); // } // else // { // //Check to see if the Predicate of the Pattern match the Full Text Match Predicate URI // TriplePattern tp = (TriplePattern)ps[i]; // PatternItem pred = tp.Predicate; // if (pred is NodeMatchPattern) // { // INode predNode = ((NodeMatchPattern)pred).Node; // if (predNode.NodeType == NodeType.Uri) // { // String predUri = ((IUriNode)predNode).Uri.ToString(); // if (predUri.Equals(FullTextHelper.FullTextMatchPredicateUri)) // { // if (patterns.Count > 0) result = Join.CreateJoin(result, new Bgp(patterns)); // result = new FullTextMatch(this._provider, result, tp.Subject, tp.Object); // patterns.Clear(); // } // else // { // patterns.Add(ps[i]); // } // } // else // { // patterns.Add(ps[i]); // } // } // else // { // patterns.Add(ps[i]); // } // } //} //if (patterns.Count == current.PatternCount) //{ // //If count of remaining patterns same as original pattern count there was no optimisation // //to do so return as is // return current; //} //else if (patterns.Count > 0) //{ // //If any patterns left at end join as a BGP with result so far // result = Join.CreateJoin(result, new Bgp(patterns)); // return result; //} //else //{ // return result; //} } } else if (algebra is ITerminalOperator) { return algebra; } else { return algebra; } }