/// <summary> /// Creates a new Multiset by flattening a Group Multiset /// </summary> /// <param name="multiset">Group Multiset</param> internal Multiset(GroupMultiset multiset) { foreach (String var in multiset.Variables) { this.AddVariable(var); } foreach (ISet s in multiset.Sets) { this.Add(s.Copy()); } }
/// <summary> /// Applies the Projection to the results of Evaluating the Inner Pattern /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { try { context.InputMultiset = context.Evaluate(this._pattern);//this._pattern.Evaluate(context); } catch (RdfQueryTimeoutException) { //If not partial results throw the error if (!context.Query.PartialResultsOnTimeout) { throw; } } IEnumerable <SparqlVariable> vars; if (context.Query != null) { vars = context.Query.Variables; } else { vars = this._variables; } //For Null and Identity Multisets this is just a simple selection if (context.InputMultiset is NullMultiset) { context.InputMultiset = new Multiset(vars.Select(v => v.Name)); context.OutputMultiset = context.InputMultiset; } else if (context.InputMultiset is IdentityMultiset) { context.InputMultiset = new Multiset(vars.Select(v => v.Name)); Set s = new Set(); context.InputMultiset.Add(s); context.OutputMultiset = context.InputMultiset; } //If we have a Group Multiset then Projection is more complex GroupMultiset groupSet = null; if (context.InputMultiset is GroupMultiset) { groupSet = (GroupMultiset)context.InputMultiset; //Project all simple variables for the Groups here foreach (SparqlVariable v in vars.Where(v => v.IsResultVariable && !v.IsProjection && !v.IsAggregate)) { //Can only project a variable if it's used in the GROUP OR if it was assigned by a GROUP BY expression if (context.Query != null) { if (!groupSet.ContainsVariable(v.Name) && !context.Query.GroupBy.Variables.Contains(v.Name) && !context.Query.GroupBy.ProjectableVariables.Contains(v.Name)) { throw new RdfQueryException("Cannot project the variable ?" + v.Name + " since this Query contains Grouping(s) but the given Variable is not in the GROUP BY - use the SAMPLE aggregate if you need to sample this Variable"); } } //Project the value for each variable if (!groupSet.ContainsVariable(v.Name)) { //Simple Variable Projection used in GROUP BY so grab first value as all should be same //for the group context.OutputMultiset.AddVariable(v.Name); foreach (int id in groupSet.SetIDs) { INode value = groupSet.Contents[groupSet.GroupSetIDs(id).First()][v.Name]; context.OutputMultiset[id].Add(v.Name, value); } } } } else if (context.Query != null && context.Query.IsAggregate) { context.OutputMultiset = new Multiset(); } //Project the rest of the Variables Set aggSet = new Set(); foreach (SparqlVariable v in vars.Where(v => v.IsResultVariable)) { if (groupSet == null) { context.InputMultiset.AddVariable(v.Name); } else { context.OutputMultiset.AddVariable(v.Name); } if (v.IsAggregate) { //Compute the Aggregate if (groupSet != null) { context.InputMultiset = groupSet.Contents; foreach (int id in groupSet.SetIDs) { INode aggValue = v.Aggregate.Apply(context, groupSet.GroupSetIDs(id)); context.OutputMultiset[id].Add(v.Name, aggValue); } context.InputMultiset = groupSet; } else { INode aggValue = v.Aggregate.Apply(context, context.InputMultiset.SetIDs); aggSet.Add(v.Name, aggValue); } } else if (v.IsProjection) { if (context.Query != null && context.Query.IsAggregate && context.Query.GroupBy == null) { throw new RdfQueryException("Cannot project an expression since this Query contains Aggregates and no GROUP BY"); } else { //Compute the Value of the Projection Expression for each Set foreach (int id in context.InputMultiset.SetIDs) { ISet s = context.InputMultiset[id]; try { INode temp = v.Projection.Evaluate(context, id); s.Add(v.Name, temp); } catch (RdfQueryException) { s.Add(v.Name, null); } } } } else { if (context.Query != null && context.Query.IsAggregate && context.Query.GroupBy == null) { //If this is an Aggregate without a GROUP BY projected variables are invalid throw new RdfQueryException("Cannot project the variable ?" + v.Name + " since this Query contains Aggregates and no GROUP BY"); } else if (context.Query != null && context.Query.IsAggregate && !context.Query.GroupBy.ProjectableVariables.Contains(v.Name)) { //If this is an Aggregate with a GROUP BY projected variables are only valid if they occur in the GROUP BY throw new RdfQueryException("Cannot project the variable ?" + v.Name + " since this Query contains Aggregates but the given Variable is not in the GROUP BY - use the SAMPLE aggregate if you need to access this variable"); } //Otherwise we don't need to do anything with the Variable } } if (context.Query != null && context.Query.IsAggregate && context.Query.GroupBy == null) { context.OutputMultiset.Add(aggSet); } else { context.OutputMultiset = context.InputMultiset; } return(context.OutputMultiset); }
/// <summary> /// Evaluates a Group By by generating a <see cref="GroupMultiset">GroupMultiset</see> from the Input Multiset /// </summary> /// <param name="context">SPARQL Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset results = context.Evaluate(this._pattern); context.InputMultiset = results; //Identity/Null yields an empty multiset if (context.InputMultiset is IdentityMultiset || context.InputMultiset is NullMultiset) { results = new Multiset(); } GroupMultiset groupSet = new GroupMultiset(results); List <BindingGroup> groups; //Calculate Groups if (context.Query.GroupBy != null) { groups = context.Query.GroupBy.Apply(context); } else if (this._grouping != null) { groups = this._grouping.Apply(context); } else { groups = new List <BindingGroup>() { new BindingGroup(results.SetIDs) }; } //Add Groups to the GroupMultiset HashSet <String> vars = new HashSet <String>(); foreach (BindingGroup group in groups) { foreach (KeyValuePair <String, INode> assignment in group.Assignments) { if (vars.Contains(assignment.Key)) { continue; } groupSet.AddVariable(assignment.Key); vars.Add(assignment.Key); } groupSet.AddGroup(group); } //If grouping produced no groups and there are aggregates present //then an implicit group is created if (groups.Count == 0 && this._aggregates.Count > 0) { groupSet.AddGroup(new BindingGroup()); } //Apply the aggregates context.InputMultiset = groupSet; context.Binder.SetGroupContext(true); foreach (SparqlVariable var in this._aggregates) { if (!vars.Contains(var.Name)) { groupSet.AddVariable(var.Name); vars.Add(var.Name); } foreach (ISet s in groupSet.Sets) { try { INode value = var.Aggregate.Apply(context, groupSet.GroupSetIDs(s.ID)); s.Add(var.Name, value); } catch (RdfQueryException) { s.Add(var.Name, null); } } } context.Binder.SetGroupContext(false); context.OutputMultiset = groupSet; return(context.OutputMultiset); }
/// <summary> /// Sets the Group Context for the Binder /// </summary> /// <param name="accessContents">Whether you want to access the Group Contents or the Groups themselves</param> public override void SetGroupContext(bool accessContents) { if (accessContents) { if (this._context.InputMultiset is GroupMultiset) { this._groupSet = (GroupMultiset)this._context.InputMultiset; this._context.InputMultiset = this._groupSet.Contents; } else { throw new RdfQueryException("Cannot set Group Context to access Contents data when the Input is not a Group Multiset"); } } else { if (this._groupSet != null) { this._context.InputMultiset = this._groupSet; this._groupSet = null; } else { throw new RdfQueryException("Cannot set Group Context to acess Group data when there is no Group data available"); } } }