/// <summary> /// Evaluates the LeftJoin /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { // Need to be careful about whether we linearize (CORE-406) if (!CanLinearizeLhs(context)) { context.InputMultiset = new IdentityMultiset(); } BaseMultiset lhsResult = context.Evaluate(_lhs); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { // Only execute the RHS if the LHS had some results // Need to be careful about whether we linearize (CORE-406) context.InputMultiset = CanFlowResultsToRhs(context) && !IsCrossProduct ? lhsResult : new IdentityMultiset(); BaseMultiset rhsResult = context.Evaluate(_rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.LeftJoin(rhsResult, _filter.Expression); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Evaluates an ExistsJoin /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(_lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { // Only execute the RHS if the LHS had results context.InputMultiset = lhsResult; BaseMultiset rhsResult = context.Evaluate(_rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.ExistsJoin(rhsResult, _mustExist); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; if (_lhs is Extend || _rhs is Extend) { initialInput = new IdentityMultiset(); } context.InputMultiset = initialInput; BaseMultiset lhsResult = context.Evaluate(_lhs); context.CheckTimeout(); context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(_rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Evaluates the Lazy Union /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult.Count >= this._requiredResults || this._requiredResults == -1) { //Only evaluate the RHS if the LHS didn't yield sufficient results context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; } else { context.OutputMultiset = lhsResult; } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Ask Union /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; if (this._lhs is Extend || this._rhs is Extend) { initialInput = new IdentityMultiset(); } context.InputMultiset = initialInput; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult.IsEmpty) { //Only evaluate the RHS if the LHS was empty context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; } else { context.OutputMultiset = lhsResult; } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } List <Uri> activeGraphs = context.Data.ActiveGraphUris.ToList(); List <Uri> defaultGraphs = context.Data.DefaultGraphUris.ToList(); ParallelEvaluateDelegate d = new ParallelEvaluateDelegate(this.ParallelEvaluate); IAsyncResult lhs = d.BeginInvoke(this._lhs, context, activeGraphs, defaultGraphs, null, null); IAsyncResult rhs = d.BeginInvoke(this._rhs, context2, activeGraphs, defaultGraphs, null, null); WaitHandle.WaitAll(new WaitHandle[] { lhs.AsyncWaitHandle, rhs.AsyncWaitHandle }); bool rhsOk = false; try { BaseMultiset lhsResult = d.EndInvoke(lhs); rhsOk = true; BaseMultiset rhsResult = d.EndInvoke(rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); } catch { if (!rhsOk) { //Clean up the RHS evaluation call if the LHS has errored try { d.EndInvoke(rhs); } catch { //Ignore this error as we're already going to throw the other error } } throw; } }
private void EvalFilteredProduct(SparqlEvaluationContext context, ISet x, BaseMultiset other, PartitionedMultiset partitionedSet) { int id = partitionedSet.GetNextBaseID(); foreach (ISet y in other.Sets) { id++; ISet z = x.Join(y); z.ID = id; partitionedSet.Add(z); try { if (!this._expr.Evaluate(context, z.ID).AsSafeBoolean()) { //Means the expression evaluates to false so we discard the solution partitionedSet.Remove(z.ID); } } catch { //Means the solution does not meet the FILTER and can be discarded partitionedSet.Remove(z.ID); } } //Remember to check for timeouts occassionally context.CheckTimeout(); }
/// <summary> /// Evaluates an ExistsJoin /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { //Only execute the RHS if the LHS had results context.InputMultiset = lhsResult; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.ExistsJoin(rhsResult, this._mustExist); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; }
/// <summary> /// Evaluates the BGP against the Evaluation Context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { bool halt; context.CheckTimeout(); BaseMultiset results = this.StreamingEvaluate(context, 0, out halt); if (results is Multiset && results.IsEmpty) { results = new NullMultiset(); } context.CheckTimeout(); context.OutputMultiset = results; context.OutputMultiset.Trim(); return(context.OutputMultiset); }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Evaluates the Union. /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { // Create a copy of the evaluation context for the RHS var context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (var s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } var activeGraphs = context.Data.ActiveGraphUris.ToList(); var defaultGraphs = context.Data.DefaultGraphUris.ToList(); var lhsTask = Task.Factory.StartNew(() => ParallelEvaluate(Lhs, context, activeGraphs, defaultGraphs)); var rhsTask = Task.Factory.StartNew(() => ParallelEvaluate(Rhs, context2, activeGraphs, defaultGraphs)); Task[] evaluationTasks = { lhsTask, rhsTask }; try { Task.WaitAll(evaluationTasks); context.CheckTimeout(); var lhsResult = lhsTask.Result; var rhsResult = rhsTask.Result; context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); } catch (AggregateException ex) { if (ex.InnerExceptions.Any()) { throw ex.InnerExceptions.First(); } throw; } }
/// <summary> /// Evaluates the Minus join by evaluating the LHS and RHS and substracting the RHS results from the LHS. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(_lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else if (_lhs.Variables.IsDisjoint(_rhs.Variables)) { // If the RHS is disjoint then there is no need to evaluate the RHS context.OutputMultiset = lhsResult; } else { // If we get here then the RHS is not disjoint so it does affect the ouput // Only execute the RHS if the LHS had results // context.InputMultiset = lhsResult; context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(_rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.MinusJoin(rhsResult); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Evaluates the Service Clause by generating instance(s) of <see cref="SparqlRemoteEndpoint">SparqlRemoteEndpoint</see> as required and issuing the query to the remote endpoint(s). /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { SparqlRemoteEndpoint endpoint = GetRemoteEndpoint(context); try { context.OutputMultiset = new Multiset(); foreach (var query in GetRemoteQueries(context, GetBindings(context))) { // Try and get a Result Set from the Service SparqlResultSet results = endpoint.QueryWithResultSet(query.ToString()); context.CheckTimeout(); // Transform this Result Set back into a Multiset foreach (SparqlResult r in results) { context.OutputMultiset.Add(new Set(r)); } } return(context.OutputMultiset); } catch (Exception ex) { if (_silent) { // If Evaluation Errors are SILENT is specified then a Multiset containing a single set with all values unbound is returned // Unless some of the SPARQL queries did return results in which we just return the results we did obtain if (context.OutputMultiset.IsEmpty) { Set s = new Set(); foreach (String var in _pattern.Variables.Distinct()) { s.Add(var, null); } context.OutputMultiset.Add(s); } return(context.OutputMultiset); } else { throw new RdfQueryException("Query execution failed because evaluating a SERVICE clause failed - this may be due to an error with the remote service", ex); } } }
/// <summary> /// Evaluates the Minus join by evaluating the LHS and RHS and substracting the RHS results from the LHS /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else if (this._lhs.Variables.IsDisjoint(this._rhs.Variables)) { //If the RHS is disjoint then there is no need to evaluate the RHS context.OutputMultiset = lhsResult; } else { //If we get here then the RHS is not disjoint so it does affect the ouput //Only execute the RHS if the LHS had results //context.InputMultiset = lhsResult; context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.MinusJoin(rhsResult); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; }
private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt) { halt = false; //Handle Empty BGPs if (pattern == 0 && this._triplePatterns.Count == 0) { context.OutputMultiset = new IdentityMultiset(); return(context.OutputMultiset); } BaseMultiset initialInput, localOutput, results = null; //Determine whether the Pattern modifies the existing Input rather than joining to it bool modifies = (this._triplePatterns[pattern] is FilterPattern); bool extended = (pattern > 0 && this._triplePatterns[pattern - 1] is BindPattern); bool modified = (pattern > 0 && this._triplePatterns[pattern - 1] is FilterPattern); //Set up the Input and Output Multiset appropriately switch (pattern) { case 0: //Input is as given and Output is new empty multiset if (!modifies) { initialInput = context.InputMultiset; } else { //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input //This takes care of FILTERs being out of scope initialInput = new Multiset(); } localOutput = new Multiset(); break; case 1: //Input becomes current Output and Output is new empty multiset initialInput = context.OutputMultiset; localOutput = new Multiset(); break; default: if (!extended && !modified) { //Input is join of previous input and output and Output is new empty multiset if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join initialInput = context.InputMultiset.Join(context.OutputMultiset); } } else { initialInput = context.OutputMultiset; } localOutput = new Multiset(); break; } context.InputMultiset = initialInput; context.OutputMultiset = localOutput; //Get the Triple Pattern we're evaluating ITriplePattern temp = this._triplePatterns[pattern]; int resultsFound = 0; int prevResults = -1; if (temp is TriplePattern) { //Find the first Triple which matches the Pattern TriplePattern tp = (TriplePattern)temp; IEnumerable <Triple> ts = tp.GetTriples(context); //In the case that we're lazily evaluating an optimisable ORDER BY then //we need to apply OrderBy()'s to our enumeration //This only applies to the 1st pattern if (pattern == 0) { if (context.Query != null) { if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy) { IComparer <Triple> comparer = context.Query.OrderBy.GetComparer(tp); if (comparer != null) { ts = ts.OrderBy(t => t, comparer); } else { //Can't get a comparer so can't optimise this._requiredResults = -1; } } } } foreach (Triple t in ts) { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); if (tp.Accepts(context, t)) { resultsFound++; if (tp.IndexType == TripleIndexType.NoVariables) { localOutput = new IdentityMultiset(); context.OutputMultiset = localOutput; } else { context.OutputMultiset.Add(tp.CreateResult(t)); } //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt && results.Count >= this._requiredResults && this._requiredResults != -1) { return(results); } else if (halt) { if (results.Count == 0) { //If recursing leads to no results then eliminate all outputs //Also reset to prevResults to -1 resultsFound = 0; localOutput = new Multiset(); prevResults = -1; } else if (prevResults > -1) { if (results.Count == prevResults) { //If the amount of results found hasn't increased then this match does not //generate any further solutions further down the recursion so we can eliminate //this from the results localOutput.Remove(localOutput.SetIDs.Max()); } } prevResults = results.Count; //If we're supposed to halt but not reached the number of required results then continue context.InputMultiset = initialInput; context.OutputMultiset = localOutput; } else { //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } //If not reached required number of results continue if (results.Count >= this._requiredResults && this._requiredResults != -1) { context.OutputMultiset = results; return(context.OutputMultiset); } } } } } else if (temp is FilterPattern) { FilterPattern filter = (FilterPattern)temp; ISparqlExpression filterExpr = filter.Filter.Expression; if (filter.Variables.IsDisjoint(context.InputMultiset.Variables)) { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Filter is Disjoint so determine whether it has any affect or not if (filter.Variables.Any()) { //Has Variables but disjoint from input => not in scope so gets ignored //Do we recurse or not? if (pattern < this._triplePatterns.Count - 1) { //Recurse and return results = this.StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { //We don't affect the input in any way so just return it return(context.InputMultiset); } } else { //No Variables so have to evaluate it to see if it gives true otherwise try { if (filterExpr.EffectiveBooleanValue(context, 0)) { if (pattern < this._triplePatterns.Count - 1) { //Recurse and return results = this.StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { //Last Pattern and we evaluate to true so can return the input as-is halt = true; return(context.InputMultiset); } } } catch (RdfQueryException) { //Evaluates to false so eliminates all solutions (use an empty Multiset) return(new Multiset()); } } } else { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Test each solution found so far against the Filter and eliminate those that evalute to false/error foreach (int id in context.InputMultiset.SetIDs.ToList()) { try { if (filterExpr.EffectiveBooleanValue(context, id)) { //If evaluates to true then add to output context.OutputMultiset.Add(context.InputMultiset[id]); } } catch (RdfQueryException) { //Error means we ignore the solution } } //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < this._triplePatterns.Count - 1) { //Recurse then return //We can never decide whether to recurse again at this point as we are not capable of deciding //which solutions should be dumped (that is the job of an earlier pattern in the BGP) results = this.StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { halt = true; //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions //for us to filter return(context.OutputMultiset); } } } else if (temp is BindPattern) { BindPattern bind = (BindPattern)temp; ISparqlExpression bindExpr = bind.AssignExpression; String bindVar = bind.VariableName; if (context.InputMultiset.ContainsVariable(bindVar)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query"); } else { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Compute the Binding for every value context.OutputMultiset.AddVariable(bindVar); foreach (ISet s in context.InputMultiset.Sets) { ISet x = s.Copy(); try { INode val = bindExpr.Value(context, s.ID); x.Add(bindVar, val); } catch (RdfQueryException) { //Equivalent to no assignment but the solution is preserved } context.OutputMultiset.Add(x); } //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < this._triplePatterns.Count - 1) { //Recurse then return results = this.StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { halt = true; //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions //for us to extend return(context.OutputMultiset); } } } else { throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern"); } //If we found no possibles we return the null multiset if (resultsFound == 0) { return(new NullMultiset()); } else { //Generate the final output and return it if (!modifies) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } context.OutputMultiset = results; } return(context.OutputMultiset); } }
/// <summary> /// Evaluates the filtered product /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResults = context.Evaluate(this._lhs); if (lhsResults is NullMultiset || lhsResults.IsEmpty) { //If LHS Results are Null/Empty then end result will always be null so short circuit context.OutputMultiset = new NullMultiset(); } else { context.InputMultiset = initialInput; BaseMultiset rhsResults = context.Evaluate(this._rhs); if (rhsResults is NullMultiset || rhsResults.IsEmpty) { //If RHS Results are Null/Empty then end results will always be null so short circuit context.OutputMultiset = new NullMultiset(); } else if (rhsResults is IdentityMultiset) { //Apply Filter over LHS Results only - defer evaluation to filter implementation context.InputMultiset = lhsResults; UnaryExpressionFilter filter = new UnaryExpressionFilter(this._expr); filter.Evaluate(context); context.OutputMultiset = lhsResults; } else { //Calculate the product applying the filter as we go #if NET40 && !SILVERLIGHT if (Options.UsePLinqEvaluation && this._expr.CanParallelise) { PartitionedMultiset partitionedSet; SparqlResultBinder binder = context.Binder; if (lhsResults.Count >= rhsResults.Count) { partitionedSet = new PartitionedMultiset(lhsResults.Count, rhsResults.Count); context.Binder = new LeviathanLeftJoinBinder(partitionedSet); lhsResults.Sets.AsParallel().ForAll(x => this.EvalFilteredProduct(context, x, rhsResults, partitionedSet)); } else { partitionedSet = new PartitionedMultiset(rhsResults.Count, lhsResults.Count); context.Binder = new LeviathanLeftJoinBinder(partitionedSet); rhsResults.Sets.AsParallel().ForAll(y => this.EvalFilteredProduct(context, y, lhsResults, partitionedSet)); } context.Binder = binder; context.OutputMultiset = partitionedSet; } else { #endif BaseMultiset productSet = new Multiset(); SparqlResultBinder binder = context.Binder; context.Binder = new LeviathanLeftJoinBinder(productSet); foreach (ISet x in lhsResults.Sets) { foreach (ISet y in rhsResults.Sets) { ISet z = x.Join(y); productSet.Add(z); try { if (!this._expr.Evaluate(context, z.ID).AsSafeBoolean()) { //Means the expression evaluates to false so we discard the solution productSet.Remove(z.ID); } } catch { //Means this solution does not meet the FILTER and can be discarded productSet.Remove(z.ID); } } //Remember to check for timeouts occassionaly context.CheckTimeout(); } context.Binder = binder; context.OutputMultiset = productSet; #if NET40 && !SILVERLIGHT } #endif } } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } IGraph activeGraph = context.Data.ActiveGraph; IGraph defaultGraph = context.Data.DefaultGraph; ParallelEvaluateDelegate d = new ParallelEvaluateDelegate(this.ParallelEvaluate); IAsyncResult lhs = d.BeginInvoke(this._lhs, context, activeGraph, defaultGraph, null, null); IAsyncResult rhs = d.BeginInvoke(this._rhs, context2, activeGraph, defaultGraph, null, null); WaitHandle.WaitAll(new WaitHandle[] { lhs.AsyncWaitHandle, rhs.AsyncWaitHandle }); bool rhsOk = false; try { BaseMultiset lhsResult = d.EndInvoke(lhs); rhsOk = true; BaseMultiset rhsResult = d.EndInvoke(rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; } catch { if (!rhsOk) { //Clean up the RHS evaluation call if the LHS has errored try { d.EndInvoke(rhs); } catch { //Ignore this error as we're already going to throw the other error } } throw; } }
/// <summary> /// Evalutes a Join /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } IGraph activeGraph = context.Data.ActiveGraph; IGraph defaultGraph = context.Data.DefaultGraph; //Start both executing asynchronously IAsyncResult lhs = this._d.BeginInvoke(this._lhs, context, activeGraph, defaultGraph, null, null); IAsyncResult rhs = this._d.BeginInvoke(this._rhs, context2, activeGraph, defaultGraph, new AsyncCallback(this.RhsCallback), null); //Wait on the LHS if (context.RemainingTimeout > 0) { lhs.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, 0, 0, (int)context.RemainingTimeout)); } else { lhs.AsyncWaitHandle.WaitOne(); } context.CheckTimeout(); //Get the LHS result BaseMultiset lhsResult; try { lhsResult = this._d.EndInvoke(lhs); } catch { throw; } //If LHS came back as null/empty no need to wait for RHS to complete if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { //Wait for RHS to complete if (!rhs.IsCompleted) { if (context.RemainingTimeout > 0) { rhs.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, 0, 0, (int)context.RemainingTimeout)); } else { rhs.AsyncWaitHandle.WaitOne(); } context.CheckTimeout(); } if (this._rhsResult == null) { if (this._rhsError != null) throw this._rhsError; Thread.Sleep(10); } if (this._rhsResult == null) throw new RdfQueryException("Unknown error in parallel join evaluation, RHS is reported completed without errors but no result is available"); //Compute the product of the two sides context.OutputMultiset = lhsResult.Product(this._rhsResult); } return context.OutputMultiset; }
/// <summary> /// Evaluates the BGP against the Evaluation Context. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public virtual BaseMultiset Evaluate(SparqlEvaluationContext context) { if (_triplePatterns.Count > 0) { for (int i = 0; i < _triplePatterns.Count; i++) { if (i == 0) { // If the 1st thing in a BGP is a BIND/LET/FILTER the Input becomes the Identity Multiset if (_triplePatterns[i].PatternType == TriplePatternType.Filter || _triplePatterns[i].PatternType == TriplePatternType.BindAssignment || _triplePatterns[i].PatternType == TriplePatternType.LetAssignment) { if (_triplePatterns[i].PatternType == TriplePatternType.BindAssignment) { if (context.InputMultiset.ContainsVariable(((IAssignmentPattern)_triplePatterns[i]).VariableName)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been declared"); } } else { context.InputMultiset = new IdentityMultiset(); } } } // Create a new Output Multiset context.OutputMultiset = new Multiset(); _triplePatterns[i].Evaluate(context); // If at any point we've got an Empty Multiset as our Output then we terminate BGP execution if (context.OutputMultiset.IsEmpty) { break; } // Check for Timeout before attempting the Join context.CheckTimeout(); // If this isn't the first Pattern we do Join/Product the Output to the Input if (i > 0) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { // Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { // Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } } // Then the Input for the next Pattern is the Output from the previous Pattern context.InputMultiset = context.OutputMultiset; } if (context.TrimTemporaryVariables) { // Trim the Multiset - this eliminates any temporary variables context.OutputMultiset.Trim(); } } else { // For an Empty BGP we just return the Identity Multiset context.OutputMultiset = new IdentityMultiset(); } // If we've ended with an Empty Multiset then we turn it into the Null Multiset // to indicate that this BGP did not match anything if (context.OutputMultiset is Multiset && context.OutputMultiset.IsEmpty) { context.OutputMultiset = new NullMultiset(); } // Return the Output Multiset return(context.OutputMultiset); }
private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt) { halt = false; //Handle Empty BGPs if (pattern == 0 && this._triplePatterns.Count == 0) { context.OutputMultiset = new IdentityMultiset(); return context.OutputMultiset; } BaseMultiset initialInput, localOutput, results; //Set up the Input and Output Multiset appropriately switch (pattern) { case 0: //Input is as given and Output is new empty multiset initialInput = context.InputMultiset; localOutput = new Multiset(); break; case 1: //Input becomes current Output and Output is new empty multiset initialInput = context.OutputMultiset; localOutput = new Multiset(); break; default: //Input is join of previous input and ouput and Output is new empty multiset if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product initialInput = context.InputMultiset.Product(context.OutputMultiset); } else { //Normal Join initialInput = context.InputMultiset.Join(context.OutputMultiset); } localOutput = new Multiset(); break; } context.InputMultiset = initialInput; context.OutputMultiset = localOutput; //Get the Triple Pattern we're evaluating ITriplePattern temp = this._triplePatterns[pattern]; int resultsFound = 0; if (temp is TriplePattern) { //Find the first Triple which matches the Pattern TriplePattern tp = (TriplePattern)temp; foreach (Triple t in tp.GetTriples(context)) { //Remember to check for Timeout during lazy evaluation context.CheckTimeout(); if (tp.Accepts(context, t)) { resultsFound++; context.OutputMultiset.Add(tp.CreateResult(t)); //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt) return results; //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.QueryTimeout - context.QueryTime); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } return context.OutputMultiset; } } } } else if (temp is FilterPattern) { FilterPattern fp = (FilterPattern)temp; ISparqlFilter filter = fp.Filter; ISparqlExpression expr = filter.Expression; //Find the first result of those we've got so far that matches if (context.InputMultiset is IdentityMultiset || context.InputMultiset.IsEmpty) { try { //If the Input is the Identity Multiset then the Output is either //the Identity/Null Multiset depending on whether the Expression evaluates to true if (expr.EffectiveBooleanValue(context, 0)) { context.OutputMultiset = new IdentityMultiset(); } else { context.OutputMultiset = new NullMultiset(); } } catch { //If Expression fails to evaluate then result is NullMultiset context.OutputMultiset = new NullMultiset(); } } else { foreach (int id in context.InputMultiset.SetIDs) { //Remember to check for Timeout during lazy evaluation context.CheckTimeout(); try { if (expr.EffectiveBooleanValue(context, id)) { resultsFound++; context.OutputMultiset.Add(context.InputMultiset[id]); //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt) return results; //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } return context.OutputMultiset; } } } catch { //Ignore expression evaluation errors } } } } //If we found no possibles we return the null multiset if (resultsFound == 0) return new NullMultiset(); //We should never reach here so throw an error to that effect //The reason we'll never reach here is that this method should always return earlier throw new RdfQueryException("Unexpected control flow in evaluating a Streamed BGP for an ASK query"); }
/// <summary> /// Evaluates the Ask Union /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult.IsEmpty) { //Only evaluate the RHS if the LHS was empty context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; } else { context.OutputMultiset = lhsResult; } return context.OutputMultiset; }
/// <summary> /// Evaluates the Service Clause by generating instance(s) of <see cref="SparqlRemoteEndpoint">SparqlRemoteEndpoint</see> as required and issuing the query to the remote endpoint(s) /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { bool bypassSilent = false; try { #if SILVERLIGHT throw new PlatformNotSupportedException("SERVICE is not currently supported under Silverlight"); #else SparqlRemoteEndpoint endpoint; Uri endpointUri; String baseUri = (context.Query.BaseUri == null) ? String.Empty : context.Query.BaseUri.ToString(); SparqlParameterizedString sparqlQuery = new SparqlParameterizedString("SELECT * WHERE "); String pattern = this._pattern.ToString(); pattern = pattern.Substring(pattern.IndexOf('{')); sparqlQuery.CommandText += pattern; //Pass through LIMIT and OFFSET to the remote service if (context.Query.Limit >= 0) { //Calculate a LIMIT which is the LIMIT plus the OFFSET //We'll apply OFFSET locally so don't pass that through explicitly int limit = context.Query.Limit; if (context.Query.Offset > 0) limit += context.Query.Offset; sparqlQuery.CommandText += " LIMIT " + limit; } //Select which service to use if (this._endpointSpecifier.TokenType == Token.URI) { endpointUri = UriFactory.Create(Tools.ResolveUri(this._endpointSpecifier.Value, baseUri)); endpoint = new SparqlRemoteEndpoint(endpointUri); } else if (this._endpointSpecifier.TokenType == Token.VARIABLE) { //Get all the URIs that are bound to this Variable in the Input String var = this._endpointSpecifier.Value.Substring(1); if (!context.InputMultiset.ContainsVariable(var)) throw new RdfQueryException("Cannot evaluate a SERVICE clause which uses a Variable as the Service specifier when the Variable is unbound"); List<IUriNode> services = new List<IUriNode>(); foreach (ISet s in context.InputMultiset.Sets) { if (s.ContainsVariable(var)) { if (s[var].NodeType == NodeType.Uri) { services.Add((IUriNode)s[var]); } } } services = services.Distinct().ToList(); //Now generate a Federated Remote Endpoint List<SparqlRemoteEndpoint> serviceEndpoints = new List<SparqlRemoteEndpoint>(); services.ForEach(u => serviceEndpoints.Add(new SparqlRemoteEndpoint(u.Uri))); endpoint = new FederatedSparqlRemoteEndpoint(serviceEndpoints); } else { //Note that we must bypass the SILENT operator in this case as this is not an evaluation failure //but a query syntax error bypassSilent = true; throw new RdfQueryException("SERVICE Specifier must be a URI/Variable Token but a " + this._endpointSpecifier.GetType().ToString() + " Token was provided"); } //Where possible do substitution and execution to get accurate and correct SERVICE results context.OutputMultiset = new Multiset(); List<String> existingVars = (from v in this._pattern.Variables where context.InputMultiset.ContainsVariable(v) select v).ToList(); if (existingVars.Any() || context.Query.Bindings != null) { //Pre-bound variables/BINDINGS clause so do substitution and execution //Build the set of possible bindings HashSet<ISet> bindings = new HashSet<ISet>(); if (context.Query.Bindings != null && !this._pattern.Variables.IsDisjoint(context.Query.Bindings.Variables)) { //Possible Bindings comes from BINDINGS clause //In this case each possibility is a distinct binding tuple defined in the BINDINGS clause foreach (BindingTuple tuple in context.Query.Bindings.Tuples) { bindings.Add(new Set(tuple)); } } else { //Possible Bindings get built from current input (if there was a BINDINGS clause the variables it defines are not in this SERVICE clause) //In this case each possibility only contains Variables bound so far foreach (ISet s in context.InputMultiset.Sets) { Set t = new Set(); foreach (String var in existingVars) { t.Add(var, s[var]); } bindings.Add(t); } } //Execute the Query for every possible Binding and build up our Output Multiset from all the results foreach (ISet s in bindings) { //Q: Should we continue processing here if and when we hit an error? foreach (String var in s.Variables) { sparqlQuery.SetVariable(var, s[var]); } SparqlResultSet results = endpoint.QueryWithResultSet(sparqlQuery.ToString()); context.CheckTimeout(); foreach (SparqlResult r in results) { Set t = new Set(r); foreach (String var in s.Variables) { t.Add(var, s[var]); } context.OutputMultiset.Add(t); } } return context.OutputMultiset; } else { //No pre-bound variables/BINDINGS clause so just execute the query //Try and get a Result Set from the Service SparqlResultSet results = endpoint.QueryWithResultSet(sparqlQuery.ToString()); //Transform this Result Set back into a Multiset foreach (SparqlResult r in results.Results) { context.OutputMultiset.Add(new Set(r)); } return context.OutputMultiset; } #endif } catch (Exception ex) { if (this._silent && !bypassSilent) { //If Evaluation Errors are SILENT is specified then a Multiset containing a single set with all values unbound is returned //Unless some of the SPARQL queries did return results in which we just return the results we did obtain if (context.OutputMultiset.IsEmpty) { Set s = new Set(); foreach (String var in this._pattern.Variables.Distinct()) { s.Add(var, null); } context.OutputMultiset.Add(s); } return context.OutputMultiset; } else { throw new RdfQueryException("Query execution failed because evaluating a SERVICE clause failed - this may be due to an error with the remote service", ex); } } }
/// <summary> /// Evaluates the BGP against the Evaluation Context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { if (this._triplePatterns.Count > 0) { for (int i = 0; i < this._triplePatterns.Count; i++) { if (i == 0) { //If the 1st thing in a BGP is a BIND/LET/FILTER the Input becomes the Identity Multiset if (this._triplePatterns[i] is FilterPattern || this._triplePatterns[i] is BindPattern || this._triplePatterns[i] is LetPattern) { if (this._triplePatterns[i] is BindPattern) { if (context.InputMultiset.ContainsVariable(((BindPattern)this._triplePatterns[i]).VariableName)) throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been declared"); } else { context.InputMultiset = new IdentityMultiset(); } } } //Create a new Output Multiset context.OutputMultiset = new Multiset(); this._triplePatterns[i].Evaluate(context); //If at any point we've got an Empty Multiset as our Output then we terminate BGP execution if (context.OutputMultiset.IsEmpty) break; //Check for Timeout before attempting the Join context.CheckTimeout(); //If this isn't the first Pattern we do Join/Product the Output to the Input if (i > 0) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } } //Then the Input for the next Pattern is the Output from the previous Pattern context.InputMultiset = context.OutputMultiset; } if (context.TrimTemporaryVariables) { //Trim the Multiset - this eliminates any temporary variables context.OutputMultiset.Trim(); } } else { //For an Empty BGP we just return the Identity Multiset context.OutputMultiset = new IdentityMultiset(); } //If we've ended with an Empty Multiset then we turn it into the Null Multiset //to indicate that this BGP did not match anything if (context.OutputMultiset is Multiset && context.OutputMultiset.IsEmpty) context.OutputMultiset = new NullMultiset(); //Return the Output Multiset return context.OutputMultiset; }
/// <summary> /// Evalutes a Join /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } List <Uri> activeGraphs = context.Data.ActiveGraphUris.ToList(); List <Uri> defaultGraphs = context.Data.DefaultGraphUris.ToList(); //Start both executing asynchronously IAsyncResult lhs = this._d.BeginInvoke(this._lhs, context, activeGraphs, defaultGraphs, null, null); IAsyncResult rhs = this._d.BeginInvoke(this._rhs, context2, activeGraphs, defaultGraphs, new AsyncCallback(this.RhsCallback), null); //Wait on the LHS if (context.RemainingTimeout > 0) { lhs.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, 0, 0, (int)context.RemainingTimeout)); } else { lhs.AsyncWaitHandle.WaitOne(); } context.CheckTimeout(); //Get the LHS result BaseMultiset lhsResult; try { lhsResult = this._d.EndInvoke(lhs); } catch { throw; } //If LHS came back as null/empty no need to wait for RHS to complete if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { //Wait for RHS to complete if (!rhs.IsCompleted) { if (context.RemainingTimeout > 0) { rhs.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, 0, 0, (int)context.RemainingTimeout)); } else { rhs.AsyncWaitHandle.WaitOne(); } context.CheckTimeout(); } if (this._rhsResult == null) { if (this._rhsError != null) { throw this._rhsError; } #if !PORTABLE // No Thread.Sleep() in PCL Thread.Sleep(10); #endif } if (this._rhsResult == null) { throw new RdfQueryException("Unknown error in parallel join evaluation, RHS is reported completed without errors but no result is available"); } //Compute the product of the two sides context.OutputMultiset = lhsResult.Product(this._rhsResult); } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Lazy Union /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; if (this._lhs is Extend || this._rhs is Extend) initialInput = new IdentityMultiset(); context.InputMultiset = initialInput; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult.Count >= this._requiredResults || this._requiredResults == -1) { //Only evaluate the RHS if the LHS didn't yield sufficient results context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; } else { context.OutputMultiset = lhsResult; } return context.OutputMultiset; }
private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt) { halt = false; //Handle Empty BGPs if (pattern == 0 && this._triplePatterns.Count == 0) { context.OutputMultiset = new IdentityMultiset(); return(context.OutputMultiset); } BaseMultiset initialInput, localOutput, results; //Set up the Input and Output Multiset appropriately switch (pattern) { case 0: //Input is as given and Output is new empty multiset initialInput = context.InputMultiset; localOutput = new Multiset(); break; case 1: //Input becomes current Output and Output is new empty multiset initialInput = context.OutputMultiset; localOutput = new Multiset(); break; default: //Input is join of previous input and ouput and Output is new empty multiset if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product initialInput = context.InputMultiset.Product(context.OutputMultiset); } else { //Normal Join initialInput = context.InputMultiset.Join(context.OutputMultiset); } localOutput = new Multiset(); break; } context.InputMultiset = initialInput; context.OutputMultiset = localOutput; //Get the Triple Pattern we're evaluating ITriplePattern temp = this._triplePatterns[pattern]; int resultsFound = 0; if (temp.PatternType == TriplePatternType.Match) { //Find the first Triple which matches the Pattern IMatchTriplePattern tp = (IMatchTriplePattern)temp; foreach (Triple t in tp.GetTriples(context)) { //Remember to check for Timeout during lazy evaluation context.CheckTimeout(); if (tp.Accepts(context, t)) { resultsFound++; context.OutputMultiset.Add(tp.CreateResult(t)); //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt) { return(results); } //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.QueryTimeout - context.QueryTime); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } return(context.OutputMultiset); } } } } else if (temp.PatternType == TriplePatternType.Filter) { IFilterPattern fp = (IFilterPattern)temp; ISparqlFilter filter = fp.Filter; ISparqlExpression expr = filter.Expression; //Find the first result of those we've got so far that matches if (context.InputMultiset is IdentityMultiset || context.InputMultiset.IsEmpty) { try { //If the Input is the Identity Multiset then the Output is either //the Identity/Null Multiset depending on whether the Expression evaluates to true if (expr.Evaluate(context, 0).AsSafeBoolean()) { context.OutputMultiset = new IdentityMultiset(); } else { context.OutputMultiset = new NullMultiset(); } } catch { //If Expression fails to evaluate then result is NullMultiset context.OutputMultiset = new NullMultiset(); } } else { foreach (int id in context.InputMultiset.SetIDs) { //Remember to check for Timeout during lazy evaluation context.CheckTimeout(); try { if (expr.Evaluate(context, id).AsSafeBoolean()) { resultsFound++; context.OutputMultiset.Add(context.InputMultiset[id].Copy()); //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt) { return(results); } //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } return(context.OutputMultiset); } } } catch { //Ignore expression evaluation errors } } } } //If we found no possibles we return the null multiset if (resultsFound == 0) { return(new NullMultiset()); } //We should never reach here so throw an error to that effect //The reason we'll never reach here is that this method should always return earlier throw new RdfQueryException("Unexpected control flow in evaluating a Streamed BGP for an ASK query"); }
/// <summary> /// Evalutes a Join. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { // Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } List <Uri> activeGraphs = context.Data.ActiveGraphUris.ToList(); List <Uri> defaultGraphs = context.Data.DefaultGraphUris.ToList(); // Start both executing asynchronously var cts = new CancellationTokenSource(); var cancellationToken = cts.Token; var lhsEvaluation = Task.Factory.StartNew(() => ParallelEvaluate(_lhs, context, activeGraphs, defaultGraphs), cancellationToken); var rhsEvaluation = Task.Factory.StartNew(() => ParallelEvaluate(_rhs, context2, activeGraphs, defaultGraphs), cancellationToken); var evaluationTasks = new Task[] { lhsEvaluation, rhsEvaluation }; try { if (context.RemainingTimeout > 0) { Task.WaitAny(evaluationTasks, (int)context.RemainingTimeout, cancellationToken); } else { Task.WaitAny(evaluationTasks, cancellationToken); } var firstResult = lhsEvaluation.IsCompleted ? lhsEvaluation.Result : rhsEvaluation.Result; if (firstResult == null) { context.OutputMultiset = new NullMultiset(); cts.Cancel(); } else if (firstResult is NullMultiset) { context.OutputMultiset = new NullMultiset(); cts.Cancel(); } else { context.CheckTimeout(); if (context.RemainingTimeout > 0) { Task.WaitAll(evaluationTasks, (int)context.RemainingTimeout, cancellationToken); } else { Task.WaitAll(evaluationTasks, cancellationToken); } var lhsResult = lhsEvaluation.Result; var rhsResult = rhsEvaluation.Result; if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (rhsResult is NullMultiset) { context.OutputMultiset = rhsResult; } else if (lhsResult == null || rhsResult == null) { context.OutputMultiset = new NullMultiset(); } else { context.OutputMultiset = lhsResult.Product(rhsResult); } } return(context.OutputMultiset); } catch (OperationCanceledException) { throw new RdfQueryTimeoutException("Query Execution Time exceeded the Timeout of " + context.QueryTimeout + "ms, query aborted after " + context.QueryTime + "ms"); } catch (AggregateException ex) { var firstCause = ex.InnerExceptions.FirstOrDefault(); if (firstCause is RdfException) { throw firstCause; } throw new RdfQueryException("Error in parallel join evaluation.", ex); } catch (RdfException) { throw; } catch (Exception ex) { throw new RdfQueryException("Error in parallel join evaluation.", ex); } }
/// <summary> /// Evaluates the Service Clause by generating instance(s) of <see cref="SparqlRemoteEndpoint">SparqlRemoteEndpoint</see> as required and issuing the query to the remote endpoint(s). /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { bool bypassSilent = false; try { SparqlRemoteEndpoint endpoint; Uri endpointUri; String baseUri = (context.Query.BaseUri == null) ? String.Empty : context.Query.BaseUri.AbsoluteUri; SparqlParameterizedString sparqlQuery = new SparqlParameterizedString("SELECT * WHERE "); String pattern = _pattern.ToString(); pattern = pattern.Substring(pattern.IndexOf('{')); sparqlQuery.CommandText += pattern; // Pass through LIMIT and OFFSET to the remote service if (context.Query.Limit >= 0) { // Calculate a LIMIT which is the LIMIT plus the OFFSET // We'll apply OFFSET locally so don't pass that through explicitly int limit = context.Query.Limit; if (context.Query.Offset > 0) { limit += context.Query.Offset; } sparqlQuery.CommandText += " LIMIT " + limit; } // Select which service to use if (_endpointSpecifier.TokenType == Token.URI) { endpointUri = UriFactory.Create(Tools.ResolveUri(_endpointSpecifier.Value, baseUri)); endpoint = new SparqlRemoteEndpoint(endpointUri); } else if (_endpointSpecifier.TokenType == Token.VARIABLE) { // Get all the URIs that are bound to this Variable in the Input String var = _endpointSpecifier.Value.Substring(1); if (!context.InputMultiset.ContainsVariable(var)) { throw new RdfQueryException("Cannot evaluate a SERVICE clause which uses a Variable as the Service specifier when the Variable is unbound"); } List <IUriNode> services = new List <IUriNode>(); foreach (ISet s in context.InputMultiset.Sets) { if (s.ContainsVariable(var)) { if (s[var].NodeType == NodeType.Uri) { services.Add((IUriNode)s[var]); } } } services = services.Distinct().ToList(); // Now generate a Federated Remote Endpoint List <SparqlRemoteEndpoint> serviceEndpoints = new List <SparqlRemoteEndpoint>(); services.ForEach(u => serviceEndpoints.Add(new SparqlRemoteEndpoint(u.Uri))); endpoint = new FederatedSparqlRemoteEndpoint(serviceEndpoints); } else { // Note that we must bypass the SILENT operator in this case as this is not an evaluation failure // but a query syntax error bypassSilent = true; throw new RdfQueryException("SERVICE Specifier must be a URI/Variable Token but a " + _endpointSpecifier.GetType().ToString() + " Token was provided"); } // Where possible do substitution and execution to get accurate and correct SERVICE results context.OutputMultiset = new Multiset(); List <String> existingVars = (from v in _pattern.Variables where context.InputMultiset.ContainsVariable(v) select v).ToList(); if (existingVars.Any() || context.Query.Bindings != null) { // Pre-bound variables/BINDINGS clause so do substitution and execution // Build the set of possible bindings HashSet <ISet> bindings = new HashSet <ISet>(); if (context.Query.Bindings != null && !_pattern.Variables.IsDisjoint(context.Query.Bindings.Variables)) { // Possible Bindings comes from BINDINGS clause // In this case each possibility is a distinct binding tuple defined in the BINDINGS clause foreach (BindingTuple tuple in context.Query.Bindings.Tuples) { bindings.Add(new Set(tuple)); } } else { // Possible Bindings get built from current input (if there was a BINDINGS clause the variables it defines are not in this SERVICE clause) // In this case each possibility only contains Variables bound so far foreach (ISet s in context.InputMultiset.Sets) { Set t = new Set(); foreach (String var in existingVars) { t.Add(var, s[var]); } bindings.Add(t); } } // Execute the Query for every possible Binding and build up our Output Multiset from all the results foreach (ISet s in bindings) { // Q: Should we continue processing here if and when we hit an error? foreach (String var in s.Variables) { sparqlQuery.SetVariable(var, s[var]); } SparqlResultSet results = endpoint.QueryWithResultSet(sparqlQuery.ToString()); context.CheckTimeout(); foreach (SparqlResult r in results) { Set t = new Set(r); foreach (String var in s.Variables) { t.Add(var, s[var]); } context.OutputMultiset.Add(t); } } return(context.OutputMultiset); } else { // No pre-bound variables/BINDINGS clause so just execute the query // Try and get a Result Set from the Service SparqlResultSet results = endpoint.QueryWithResultSet(sparqlQuery.ToString()); // Transform this Result Set back into a Multiset foreach (SparqlResult r in results.Results) { context.OutputMultiset.Add(new Set(r)); } return(context.OutputMultiset); } } catch (Exception ex) { if (_silent && !bypassSilent) { // If Evaluation Errors are SILENT is specified then a Multiset containing a single set with all values unbound is returned // Unless some of the SPARQL queries did return results in which we just return the results we did obtain if (context.OutputMultiset.IsEmpty) { Set s = new Set(); foreach (String var in _pattern.Variables.Distinct()) { s.Add(var, null); } context.OutputMultiset.Add(s); } return(context.OutputMultiset); } else { throw new RdfQueryException("Query execution failed because evaluating a SERVICE clause failed - this may be due to an error with the remote service", ex); } } }
private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt) { halt = false; //Handle Empty BGPs if (pattern == 0 && this._triplePatterns.Count == 0) { context.OutputMultiset = new IdentityMultiset(); return context.OutputMultiset; } BaseMultiset initialInput, localOutput, results = null; //Determine whether the Pattern modifies the existing Input rather than joining to it bool modifies = (this._triplePatterns[pattern] is FilterPattern); bool extended = (pattern > 0 && this._triplePatterns[pattern-1] is BindPattern); bool modified = (pattern > 0 && this._triplePatterns[pattern-1] is FilterPattern); //Set up the Input and Output Multiset appropriately switch (pattern) { case 0: //Input is as given and Output is new empty multiset if (!modifies) { initialInput = context.InputMultiset; } else { //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input //This takes care of FILTERs being out of scope initialInput = new Multiset(); } localOutput = new Multiset(); break; case 1: //Input becomes current Output and Output is new empty multiset initialInput = context.OutputMultiset; localOutput = new Multiset(); break; default: if (!extended && !modified) { //Input is join of previous input and output and Output is new empty multiset if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join initialInput = context.InputMultiset.Join(context.OutputMultiset); } } else { initialInput = context.OutputMultiset; } localOutput = new Multiset(); break; } context.InputMultiset = initialInput; context.OutputMultiset = localOutput; //Get the Triple Pattern we're evaluating ITriplePattern temp = this._triplePatterns[pattern]; int resultsFound = 0; int prevResults = -1; if (temp is TriplePattern) { //Find the first Triple which matches the Pattern TriplePattern tp = (TriplePattern)temp; IEnumerable<Triple> ts = tp.GetTriples(context); //In the case that we're lazily evaluating an optimisable ORDER BY then //we need to apply OrderBy()'s to our enumeration //This only applies to the 1st pattern if (pattern == 0) { if (context.Query != null) { if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy) { IComparer<Triple> comparer = context.Query.OrderBy.GetComparer(tp); if (comparer != null) { ts = ts.OrderBy(t => t, comparer); } else { //Can't get a comparer so can't optimise this._requiredResults = -1; } } } } foreach (Triple t in ts) { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); if (tp.Accepts(context, t)) { resultsFound++; if (tp.IndexType == TripleIndexType.NoVariables) { localOutput = new IdentityMultiset(); context.OutputMultiset = localOutput; } else { context.OutputMultiset.Add(tp.CreateResult(t)); } //Recurse unless we're the last pattern if (pattern < this._triplePatterns.Count - 1) { results = this.StreamingEvaluate(context, pattern + 1, out halt); //If recursion leads to a halt then we halt and return immediately if (halt && results.Count >= this._requiredResults && this._requiredResults != -1) { return results; } else if (halt) { if (results.Count == 0) { //If recursing leads to no results then eliminate all outputs //Also reset to prevResults to -1 resultsFound = 0; localOutput = new Multiset(); prevResults = -1; } else if (prevResults > -1) { if (results.Count == prevResults) { //If the amount of results found hasn't increased then this match does not //generate any further solutions further down the recursion so we can eliminate //this from the results localOutput.Remove(localOutput.SetIDs.Max()); } } prevResults = results.Count; //If we're supposed to halt but not reached the number of required results then continue context.InputMultiset = initialInput; context.OutputMultiset = localOutput; } else { //Otherwise we need to keep going here //So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } } else { //If we're at the last pattern and we've found a match then we can halt halt = true; //Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } //If not reached required number of results continue if (results.Count >= this._requiredResults && this._requiredResults != -1) { context.OutputMultiset = results; return context.OutputMultiset; } } } } } else if (temp is FilterPattern) { FilterPattern filter = (FilterPattern)temp; ISparqlExpression filterExpr = filter.Filter.Expression; if (filter.Variables.IsDisjoint(context.InputMultiset.Variables)) { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Filter is Disjoint so determine whether it has any affect or not if (filter.Variables.Any()) { //Has Variables but disjoint from input => not in scope so gets ignored //Do we recurse or not? if (pattern < this._triplePatterns.Count - 1) { //Recurse and return results = this.StreamingEvaluate(context, pattern + 1, out halt); return results; } else { //We don't affect the input in any way so just return it return context.InputMultiset; } } else { //No Variables so have to evaluate it to see if it gives true otherwise try { if (filterExpr.Evaluate(context, 0).AsSafeBoolean()) { if (pattern < this._triplePatterns.Count - 1) { //Recurse and return results = this.StreamingEvaluate(context, pattern + 1, out halt); return results; } else { //Last Pattern and we evaluate to true so can return the input as-is halt = true; return context.InputMultiset; } } } catch (RdfQueryException) { //Evaluates to false so eliminates all solutions (use an empty Multiset) return new Multiset(); } } } else { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Test each solution found so far against the Filter and eliminate those that evalute to false/error foreach (int id in context.InputMultiset.SetIDs.ToList()) { try { if (filterExpr.Evaluate(context, id).AsSafeBoolean()) { //If evaluates to true then add to output context.OutputMultiset.Add(context.InputMultiset[id].Copy()); } } catch (RdfQueryException) { //Error means we ignore the solution } } //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < this._triplePatterns.Count - 1) { //Recurse then return //We can never decide whether to recurse again at this point as we are not capable of deciding //which solutions should be dumped (that is the job of an earlier pattern in the BGP) results = this.StreamingEvaluate(context, pattern + 1, out halt); return results; } else { halt = true; //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions //for us to filter return context.OutputMultiset; } } } else if (temp is BindPattern) { BindPattern bind = (BindPattern)temp; ISparqlExpression bindExpr = bind.AssignExpression; String bindVar = bind.VariableName; if (context.InputMultiset.ContainsVariable(bindVar)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query"); } else { //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Compute the Binding for every value context.OutputMultiset.AddVariable(bindVar); foreach (ISet s in context.InputMultiset.Sets) { ISet x = s.Copy(); try { INode val = bindExpr.Evaluate(context, s.ID); x.Add(bindVar, val); } catch (RdfQueryException) { //Equivalent to no assignment but the solution is preserved } context.OutputMultiset.Add(x.Copy()); } //Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); //Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < this._triplePatterns.Count - 1) { //Recurse then return results = this.StreamingEvaluate(context, pattern + 1, out halt); return results; } else { halt = true; //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions //for us to extend return context.OutputMultiset; } } } else { throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern"); } //If we found no possibles we return the null multiset if (resultsFound == 0) { return new NullMultiset(); } else { //Generate the final output and return it if (!modifies) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } context.OutputMultiset = results; } return context.OutputMultiset; } }