/// <summary> /// Applies the Filter over the results of evaluating the inner pattern. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public sealed override BaseMultiset Evaluate(SparqlEvaluationContext context) { INode term = _term.Evaluate(null, 0); // First take appropriate pre-filtering actions if (context.InputMultiset is IdentityMultiset) { // If the Input is Identity switch the input to be a Multiset containing a single Set // where the variable is bound to the term context.InputMultiset = new Multiset(); Set s = new Set(); s.Add(RestrictionVariable, term); context.InputMultiset.Add(s); } else if (context.InputMultiset is NullMultiset) { // If Input is Null then output is Null context.OutputMultiset = context.InputMultiset; return(context.OutputMultiset); } else { if (context.InputMultiset.ContainsVariable(RestrictionVariable)) { // If the Input Multiset contains the variable then pre-filter foreach (int id in context.InputMultiset.SetIDs.ToList()) { ISet x = context.InputMultiset[id]; try { if (x.ContainsVariable(RestrictionVariable)) { // If does exist check it has appropriate value and if not remove it if (!term.Equals(x[RestrictionVariable])) { context.InputMultiset.Remove(id); } } else { // If doesn't exist for this set then bind it to the term x.Add(RestrictionVariable, term); } } catch (RdfQueryException) { context.InputMultiset.Remove(id); } } } else { // If it doesn't contain the variable then bind for each existing set foreach (ISet x in context.InputMultiset.Sets) { x.Add(RestrictionVariable, term); } } } // Then evaluate the inner algebra BaseMultiset results = context.Evaluate(InnerAlgebra); if (results is NullMultiset || results is IdentityMultiset) { return(results); } // Filter the results to ensure that the variable is indeed bound to the term foreach (int id in results.SetIDs.ToList()) { ISet x = results[id]; try { if (!term.Equals(x[RestrictionVariable])) { results.Remove(id); } } catch (RdfQueryException) { results.Remove(id); } } if (results.Count > 0) { context.OutputMultiset = results; } else { context.OutputMultiset = new NullMultiset(); } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { // Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset? bool datasetOk = false; try { List <String> activeGraphs = new List <string>(); // Get the URIs of Graphs that should be evaluated over if (_graphSpecifier.TokenType != Token.VARIABLE) { switch (_graphSpecifier.TokenType) { case Token.URI: case Token.QNAME: Uri activeGraphUri = UriFactory.Create(Tools.ResolveUriOrQName(_graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri)); if (context.Data.HasGraph(activeGraphUri)) { // If the Graph is explicitly specified and there are FROM/FROM NAMED present then the Graph // URI must be in the graphs specified by a FROM/FROM NAMED or the result is null if (context.Query == null || ((!context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) || context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u))) ) { // Either there was no Query // OR there were no Default/Named Graphs (hence any Graph URI is permitted) // OR the specified URI was a Named Graph URI // In any case we can go ahead and set the active Graph activeGraphs.Add(activeGraphUri.AbsoluteUri); } else { // The specified URI was not present in the Named Graphs so return null context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } } else { // If specifies a specific Graph and not in the Dataset result is a null multiset context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } break; default: throw new RdfQueryException("Cannot use a '" + _graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause"); } } else { String gvar = _graphSpecifier.Value.Substring(1); // Watch out for the case in which the Graph Variable is not bound for all Sets in which case // we still need to operate over all Graphs if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null)) { // If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs List <Uri> graphUris = new List <Uri>(); foreach (ISet s in context.InputMultiset.Sets) { INode temp = s[gvar]; if (temp == null) { continue; } if (temp.NodeType != NodeType.Uri) { continue; } activeGraphs.Add(temp.ToString()); graphUris.Add(((IUriNode)temp).Uri); } } else { // Nothing yet bound to the Graph Variable so the Query is over all the named Graphs if (context.Query != null && context.Query.NamedGraphs.Any()) { // Query specifies one/more named Graphs activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.AbsoluteUri)); } else if (context.Query != null && context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) { // Gives null since the query dataset does not include any named graphs context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } else { // Query is over entire dataset/default Graph since no named Graphs are explicitly specified activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString())); } } } // Remove all duplicates from Active Graphs to avoid duplicate results activeGraphs = activeGraphs.Distinct().ToList(); // Evaluate the inner pattern BaseMultiset initialInput = context.InputMultiset; BaseMultiset finalResult = new Multiset(); // Evalute for each Graph URI and union the results foreach (String uri in activeGraphs) { // Always use the same Input for each Graph URI and set that Graph to be the Active Graph // Be sure to translate String.Empty back to the null URI to select the default graph // correctly context.InputMultiset = initialInput; Uri currGraphUri = (uri.Equals(String.Empty)) ? null : UriFactory.Create(uri); // Set Active Graph if (currGraphUri == null) { // GRAPH operates over named graphs only so default graph gets skipped continue; } // The result of the HasGraph() call is ignored we just make it so datasets with any kind of // load on demand behaviour work properly context.Data.HasGraph(currGraphUri); // All we actually care about is setting the active graph context.Data.SetActiveGraph(currGraphUri); datasetOk = true; // Evaluate for the current Active Graph BaseMultiset result = context.Evaluate(_pattern); // Merge the Results into our overall Results if (result is NullMultiset) { // Don't do anything, adds nothing to the results } else if (result is IdentityMultiset) { // Adds a single row to the results if (_graphSpecifier.TokenType == Token.VARIABLE) { // Include graph variable if not yet bound INode currGraph = new UriNode(null, currGraphUri); Set s = new Set(); s.Add(_graphSpecifier.Value.Substring(1), currGraph); finalResult.Add(s); } else { finalResult.Add(new Set()); } } else { // If the Graph Specifier is a Variable then we must either bind the // variable or eliminate solutions which have an incorrect value for it if (_graphSpecifier.TokenType == Token.VARIABLE) { String gvar = _graphSpecifier.Value.Substring(1); INode currGraph = new UriNode(null, currGraphUri); foreach (int id in result.SetIDs.ToList()) { ISet s = result[id]; if (s[gvar] == null) { // If Graph Variable is not yet bound for solution bind it s.Add(gvar, currGraph); } else if (!s[gvar].Equals(currGraph)) { // If Graph Variable is bound for solution and doesn't match // current Graph then we have to remove the solution result.Remove(id); } } } // Union solutions into the Results finalResult.Union(result); } // Reset the Active Graph after each pass context.Data.ResetActiveGraph(); datasetOk = false; } // Return the final result if (finalResult.IsEmpty) { finalResult = new NullMultiset(); } context.OutputMultiset = finalResult; } finally { if (datasetOk) { context.Data.ResetActiveGraph(); } } return(context.OutputMultiset); }
private void EvalLeftJoin(ISet x, BaseMultiset other, List <String> joinVars, List <MultiDictionary <INode, List <int> > > values, List <List <int> > nulls, BaseMultiset joinedSet, SparqlEvaluationContext subcontext, ISparqlExpression expr) { IEnumerable <int> possMatches = null; int i = 0; foreach (String var in joinVars) { INode value = x[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i][value].Concat(nulls[i]) : possMatches.Intersect(values[i][value].Concat(nulls[i]))); } else { possMatches = Enumerable.Empty <int>(); break; } } else { // Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? SetIDs : possMatches.Intersect(SetIDs)); } i++; } // If no possible matches just copy LHS across if (possMatches == null) { joinedSet.Add(x.Copy()); return; } // Now do the actual joins for the current set bool standalone = false; bool matched = false; foreach (int poss in possMatches) { if (other[poss].IsCompatibleWith(x, joinVars)) { ISet z = x.Join(other[poss]); joinedSet.Add(z); try { if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean()) { joinedSet.Remove(z.ID); } else { matched = true; } } catch { joinedSet.Remove(z.ID); standalone = true; } } } if (standalone || !matched) { joinedSet.Add(x.Copy()); } }