/// <summary> /// Creates a new DELETE command which operates on the Default Graph /// </summary> /// <param name="deletions">Pattern to construct Triples to delete</param> /// <param name="where">Pattern to select data which is then used in evaluating the deletions pattern</param> public DeleteCommand(GraphPattern deletions, GraphPattern where) : base(SparqlUpdateCommandType.Delete) { if (!this.IsValidDeletePattern(deletions, true)) throw new SparqlUpdateException("Cannot create a DELETE command where any of the Triple Patterns are not constructable triple patterns (Blank Node Variables are not permitted) or a GRAPH clause has nested Graph Patterns"); this._deletePattern = deletions; this._wherePattern = where; }
/// <summary> /// Creates a new INSERT command /// </summary> /// <param name="insertions">Pattern to construct Triples to insert</param> /// <param name="where">Pattern to select data which is then used in evaluating the insertions</param> /// <param name="graphUri">URI of the affected Graph</param> public InsertCommand(GraphPattern insertions, GraphPattern where, Uri graphUri) : base(SparqlUpdateCommandType.Insert) { this._insertPattern = insertions; this._wherePattern = where; this._graphUri = graphUri; //Optimise the WHERE this._wherePattern.Optimise(); }
/// <summary> /// Creates a new INSERT/DELETE command /// </summary> /// <param name="deletions">Pattern to construct Triples to delete</param> /// <param name="insertions">Pattern to construct Triples to insert</param> /// <param name="where">Pattern to select data which is then used in evaluating the insertions and deletions</param> /// <param name="graphUri">URI of the affected Graph</param> public ModifyCommand(GraphPattern deletions, GraphPattern insertions, GraphPattern where, Uri graphUri) : base(SparqlUpdateCommandType.Modify) { if (!this.IsValidDeletePattern(deletions, true)) throw new SparqlUpdateException("Cannot create a DELETE command where any of the Triple Patterns are not constructable triple patterns (Blank Node Variables are not permitted) or a GRAPH clause has nested Graph Patterns"); this._deletePattern = deletions; this._insertPattern = insertions; this._wherePattern = where; this._graphUri = graphUri; //Optimise the WHERE this._wherePattern.Optimise(); }
/// <summary> /// Adds a Triple Pattern to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Triple Pattern</param> internal void AddTriplePattern(ITriplePattern p) { if (_break) { if (_broken) { _graphPatterns.Last().AddTriplePattern(p); } else { GraphPattern breakPattern = new GraphPattern(); breakPattern.AddTriplePattern(p); _graphPatterns.Add(breakPattern); } } else { _triplePatterns.Add(p); } }
/// <summary> /// Determines whether a Graph Pattern is valid for use in an DELETE DATA command /// </summary> /// <param name="p">Graph Pattern</param> /// <param name="top">Is this the top level pattern?</param> /// <returns></returns> private bool IsValidDataPattern(GraphPattern p, bool top) { if (p.IsGraph) { //If a GRAPH clause then all triple patterns must be constructable and have no Child Graph Patterns return !p.HasChildGraphPatterns && p.TriplePatterns.All(tp => tp is IConstructTriplePattern && ((IConstructTriplePattern)tp).HasNoVariables); } else if (p.IsExists || p.IsMinus || p.IsNotExists || p.IsOptional || p.IsService || p.IsSubQuery || p.IsUnion) { //EXISTS/MINUS/NOT EXISTS/OPTIONAL/SERVICE/Sub queries/UNIONs are not permitted return false; } else { //For other patterns all Triple patterns must be constructable with no explicit variables //If top level then any Child Graph Patterns must be valid //Otherwise must have no Child Graph Patterns return p.TriplePatterns.All(tp => tp is IConstructTriplePattern && ((IConstructTriplePattern)tp).HasNoVariables) && ((top && p.ChildGraphPatterns.All(gp => IsValidDataPattern(gp, false))) || !p.HasChildGraphPatterns); } }
internal GraphPattern(GraphPattern gp) { this._break = gp._break; this._broken = gp._broken; this._filter = gp._filter; this._graphPatterns.AddRange(gp._graphPatterns); this._graphSpecifier = gp._graphSpecifier; this._isExists = gp._isExists; this._isFiltered = gp._isFiltered; this._isGraph = gp._isGraph; this._isMinus = gp._isMinus; this._isNotExists = gp._isExists; this._isOptimised = gp._isOptimised; this._isOptional = gp._isOptional; this._isService = gp._isService; this._isSilent = gp._isSilent; this._isUnion = gp._isUnion; this._triplePatterns.AddRange(gp._triplePatterns); this._unplacedAssignments.AddRange(gp._unplacedAssignments); this._unplacedFilters.AddRange(gp._unplacedFilters); }
/// <summary> /// Adds an Assignment to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Assignment Pattern</param> internal void AddAssignment(IAssignmentPattern p) { if (this._break) { if (this._broken) { this._graphPatterns.Last().AddAssignment(p); } else { GraphPattern breakPattern = new GraphPattern(); breakPattern.AddAssignment(p); this._graphPatterns.Add(breakPattern); } } else { this._unplacedAssignments.Add(p); this.BreakBGP(); } }
internal GraphPattern(GraphPattern gp) { this._break = gp._break; this._broken = gp._broken; this._filter = gp._filter; this._graphPatterns.AddRange(gp._graphPatterns); this._graphSpecifier = gp._graphSpecifier; this._isExists = gp._isExists; this._isFiltered = gp._isFiltered; this._isGraph = gp._isGraph; this._isMinus = gp._isMinus; this._isNotExists = gp._isExists; this._isOptimised = gp._isOptimised; this._isOptional = gp._isOptional; this._isService = gp._isService; this._isSilent = gp._isSilent; this._isUnion = gp._isUnion; this._triplePatterns.AddRange(gp._triplePatterns); this._unplacedAssignments.AddRange(gp._unplacedAssignments); this._unplacedFilters.AddRange(gp._unplacedFilters); }
/// <summary> /// Adds a child Graph Pattern to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Graph Pattern</param> internal void AddGraphPattern(GraphPattern p) { if (_break) { if (_broken) { _graphPatterns.Last().AddGraphPattern(p); } else { _graphPatterns.Add(p); } } else { _graphPatterns.Add(p); if (!_isUnion && !p.IsSubQuery) { BreakBGP(); } } }
/// <summary> /// Converts the Algebra to a Graph Pattern /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern gp = this._inner.ToGraphPattern(); if (gp.HasModifier) { GraphPattern p = new GraphPattern(); p.AddGraphPattern(gp); p.AddAssignment(new BindPattern(this._var, this._expr)); return p; } else { gp.AddAssignment(new BindPattern(this._var, this._expr)); return gp; } }
/// <summary> /// Converts the BGP to a Graph Pattern /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern p = new GraphPattern(); foreach (ITriplePattern tp in this._triplePatterns) { p.AddTriplePattern(tp); } return p; }
/// <summary> /// Transforms the Algebra back into a Graph Pattern /// </summary> /// <returns></returns> public override GraphPattern ToGraphPattern() { GraphPattern gp = new GraphPattern(); PropertyPathPattern pp = new PropertyPathPattern(this.PathStart, new FixedCardinality(this.Path, 0), this.PathEnd); gp.AddTriplePattern(pp); return gp; }
/// <summary> /// Creates a new Service clause with the given Endpoint Specifier and Graph Pattern /// </summary> /// <param name="endpointSpecifier">Endpoint Specifier</param> /// <param name="pattern">Graph Pattern</param> /// <param name="silent">Whether Evaluation Errors are suppressed</param> public Service(IToken endpointSpecifier, GraphPattern pattern, bool silent) { this._endpointSpecifier = endpointSpecifier; this._pattern = pattern; this._silent = silent; }
/// <summary> /// Creates a new Service clause with the given Endpoint Specifier and Graph Pattern /// </summary> /// <param name="endpointSpecifier">Endpoint Specifier</param> /// <param name="pattern">Graph Pattern</param> public Service(IToken endpointSpecifier, GraphPattern pattern) : this(endpointSpecifier, pattern, false) { }
/// <summary> /// Tries to place assignments at the earliest point possible i.e. the first point after which all required variables have occurred /// </summary> /// <param name="gp">Graph Pattern</param> /// <param name="assignment">Assignment (LET/BIND)</param> /// <returns></returns> private bool TryPlaceAssignment(GraphPattern gp, IAssignmentPattern assignment) { //Firstly we need to find out what variables are needed in the Assignment //The Variables property will include the variable that the Assignment assigns to so we can safely remove this List<String> variablesNeeded = assignment.Variables.Distinct().ToList(); variablesNeeded.Remove(assignment.VariableName); //If there are no Variables Needed we can just place the assignment at the start //This implies that the assignment sets something to a fixed value if (variablesNeeded.Count == 0) { gp.InsertAssignment(assignment, 0); return true; } //Then we need to move through the Triple Patterns and find the first place at which all the //Variables used in the Assignment have been used in ordinary Triple Patterns List<String> variablesUsed = new List<string>(); for (int p = 0; p < gp.TriplePatterns.Count; p++) { if (gp.TriplePatterns[p] is TriplePattern || gp.TriplePatterns[p] is IAssignmentPattern) { foreach (String var in gp.TriplePatterns[p].Variables) { if (!variablesUsed.Contains(var)) variablesUsed.Add(var); } //Have all the Variables we need now been used in a Pattern? if (variablesNeeded.All(v => variablesUsed.Contains(v))) { //We can place this Assignment after the Pattern we were just looking at gp.InsertAssignment(assignment, p + 1); return true; } } } //If we reach here then this means that all the Variables used in the Assignment did not occur //in the Triple Patterns which means they likely occur in child graph patterns (or the query //is malformed). In this case we cannot place the Assignment and it has to be applied post-commit //rather than during Triple Pattern execution return false; }
/// <summary> /// Adds an Assignment to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Assignment Pattern</param> internal void AddAssignment(IAssignmentPattern p) { if (this._break) { if (this._broken) { this._graphPatterns.Last().AddAssignment(p); } else { GraphPattern breakPattern = new GraphPattern(); breakPattern.AddAssignment(p); this._graphPatterns.Add(breakPattern); } } else { this._unplacedAssignments.Add(p); this.BreakBGP(); } }
/// <summary> /// Converts the Algebra back to a SPARQL Query /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern p = new GraphPattern(); p.IsUnion = true; p.AddGraphPattern(this._lhs.ToGraphPattern()); p.AddGraphPattern(this._rhs.ToGraphPattern()); return p; }
/// <summary> /// Adds a Triple Pattern to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Triple Pattern</param> internal void AddTriplePattern(ITriplePattern p) { if (this._break) { if (this._broken) { this._graphPatterns.Last().AddTriplePattern(p); } else { GraphPattern breakPattern = new GraphPattern(); breakPattern.AddTriplePattern(p); this._graphPatterns.Add(breakPattern); } } else { this._triplePatterns.Add(p); } }
/// <summary> /// Creates a new INSERT DATA command /// </summary> /// <param name="pattern">Pattern containing concrete Triples to insert</param> public InsertDataCommand(GraphPattern pattern) : base(SparqlUpdateCommandType.InsertData) { if (!this.IsValidDataPattern(pattern, true)) throw new SparqlUpdateException("Cannot create a INSERT DATA command where any of the Triple Patterns are not concrete triples (variables are not permitted) or a GRAPH clause has nested Graph Patterns"); this._pattern = pattern; }
/// <summary> /// Transforms the Algebra back into a Graph Pattern /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern gp = new GraphPattern(); PropertyPathPattern pp; if (this._inverse) { pp = new PropertyPathPattern(this.PathStart, new NegatedSet(Enumerable.Empty<Property>(), this._properties.Select(p => new Property(p))), this.PathEnd); } else { pp = new PropertyPathPattern(this.PathStart, new NegatedSet(this._properties.Select(p => new Property(p)), Enumerable.Empty<Property>()), this.PathEnd); } gp.AddTriplePattern(pp); return gp; }
/// <summary> /// Creates a new INSERT/DELETE command which operates on the Default Graph /// </summary> /// <param name="deletions">Pattern to construct Triples to delete</param> /// <param name="insertions">Pattern to construct Triples to insert</param> /// <param name="where">Pattern to select data which is then used in evaluating the insertions and deletions</param> public ModifyCommand(GraphPattern deletions, GraphPattern insertions, GraphPattern where) : this(deletions, insertions, where, null) { }
/// <summary> /// Adds a child Graph Pattern to the Graph Pattern respecting any BGP breaks /// </summary> /// <param name="p">Graph Pattern</param> internal void AddGraphPattern(GraphPattern p) { if (this._break) { if (this._broken) { this._graphPatterns.Last().AddGraphPattern(p); } else { this._graphPatterns.Add(p); } } else { this._graphPatterns.Add(p); if (!this._isUnion && !p.IsSubQuery) this.BreakBGP(); } }
/// <summary> /// Creates a new EXISTS/NOT EXISTS function /// </summary> /// <param name="pattern">Graph Pattern</param> /// <param name="mustExist">Whether this is an EXIST</param> public ExistsFunction(GraphPattern pattern, bool mustExist) { this._pattern = pattern; this._mustExist = mustExist; }
/// <summary> /// Transforms the Algebra into a Graph Pattern /// </summary> /// <returns></returns> public override GraphPattern ToGraphPattern() { GraphPattern gp = new GraphPattern(); PropertyPathPattern pp = new PropertyPathPattern(this.PathStart, new ZeroOrMore(this.Path), this.PathEnd); gp.AddTriplePattern(pp); return gp; }
/// <summary> /// Tries to reorder patterns when the initial ordering is considered poor /// </summary> /// <param name="gp">Graph Pattern</param> /// <param name="desiredVariables">Variables that are desired</param> /// <param name="start">Point at which to start looking for better matches</param> /// <param name="end">Point at which to move the better match to</param> private void TryReorderPatterns(GraphPattern gp, List<String> desiredVariables, int start, int end) { if (end > start) return; //Find the first pattern which does contain a pre-existing variable for (int i = start; i < gp.TriplePatterns.Count; i++) { if (gp.TriplePatterns[i].Variables.Any(v => desiredVariables.Contains(v))) { int newEnd = i; desiredVariables.AddRange(gp.TriplePatterns[i].Variables.Where(v => desiredVariables.Contains(v))); while (i > end) { //Swap Patterns around gp.SwapTriplePatterns(i - 1, i); i--; } end = newEnd; } } }
/// <summary> /// Creates a new Graph Pattern Term /// </summary> /// <param name="pattern">Graph Pattern</param> public GraphPatternTerm(GraphPattern pattern) { this._pattern = pattern; }
/// <summary> /// Converts the algebra back into a Subquery /// </summary> /// <returns></returns> public VDS.RDF.Query.Patterns.GraphPattern ToGraphPattern() { GraphPattern gp = new GraphPattern(); gp.TriplePatterns.Add(new SubQueryPattern(this._subquery)); return gp; }
/// <summary> /// Gets the String representation of the Graph Pattern /// </summary> /// <returns></returns> public override string ToString() { StringBuilder output = new StringBuilder(); String indent = String.Empty; if (_isUnion) { indent = new String(' ', 2); for (int i = 0; i < _graphPatterns.Count; i++) { GraphPattern gp = _graphPatterns[i]; if (i > 0) { output.Append(indent); } String temp = gp.ToString(); if (!temp.Contains('\n')) { if (gp.HasModifier) { temp = "{ " + temp + " }"; } output.Append(temp + " "); } else { if (gp.HasModifier) { temp = "{\n" + temp + "\n}"; } output.AppendLineIndented(temp, 2); } if (i < _graphPatterns.Count - 1) { output.AppendLine(); output.Append(indent); output.AppendLine("UNION"); } } return(output.ToString()); } if (_isGraph || _isService) { if (_isGraph) { output.Append("GRAPH "); } else { output.Append("SERVICE "); if (_isSilent) { output.Append("SILENT "); } } switch (_graphSpecifier.TokenType) { case Token.QNAME: output.Append(_graphSpecifier.Value); break; case Token.URI: output.Append('<'); output.Append(_graphSpecifier.Value); output.Append('>'); break; case Token.VARIABLE: default: output.Append(_graphSpecifier.Value); break; } output.Append(" "); } else if (_isOptional) { if (_isExists) { output.Append("EXISTS "); } else if (_isNotExists) { output.Append("NOT EXISTS "); } else { output.Append("OPTIONAL "); } } else if (_isMinus) { output.Append("MINUS "); } output.Append("{ "); bool linebreaks = ((_triplePatterns.Count + _graphPatterns.Count + _unplacedAssignments.Count) > 1) || _isFiltered; if (linebreaks) { output.AppendLine(); indent = new String(' ', 2); } // Triple Patterns foreach (ITriplePattern tp in _triplePatterns) { String temp = tp.ToString(); output.Append(indent); if (temp.Contains('\n')) { String[] lines = temp.Split('\n'); for (int i = 0; i < lines.Length; i++) { if (i > 0) { output.Append(indent); } if (i > 0 && i < lines.Length - 1) { output.Append(' '); } output.Append(lines[i]); if (i < lines.Length - 1) { output.AppendLine(); } } if (tp.PatternType != TriplePatternType.SubQuery) { output.Append(" . "); } if (linebreaks) { output.AppendLine(); } } else { output.Append(temp + " . "); if (linebreaks) { output.AppendLine(); } } } // Unplaced Assignments foreach (IAssignmentPattern ap in _unplacedAssignments) { output.Append(ap.ToString()); if (linebreaks) { output.AppendLine(); } } // Inline Data if (HasInlineData) { output.Append(indent); String temp = _data.ToString(); if (!temp.Contains('\n')) { output.Append(temp + " "); } else { String[] lines = temp.Split('\n'); for (int i = 0; i < lines.Length; i++) { if (i > 0) { output.Append(indent); } output.Append(lines[i]); if (i < lines.Length - 1) { output.AppendLine(); } } } if (linebreaks) { output.AppendLine(); } } // Graph Patterns foreach (GraphPattern gp in _graphPatterns) { output.Append(indent); String temp = gp.ToString(); if (!temp.Contains('\n')) { output.Append(temp + " "); } else { String[] lines = temp.Split('\n'); for (int i = 0; i < lines.Length; i++) { if (i > 0) { output.Append(indent); } output.Append(lines[i]); if (i < lines.Length - 1) { output.AppendLine(); } } } if (linebreaks) { output.AppendLine(); } } // Filters if (_filter != null) { output.Append(indent); output.Append(_filter.ToString()); if (linebreaks) { output.AppendLine(); } } foreach (ISparqlFilter filter in _unplacedFilters) { output.Append(indent); output.Append(filter.ToString()); if (linebreaks) { output.AppendLine(); } } output.Append("}"); return(output.ToString()); }
/// <summary> /// Creates a new DELETE command /// </summary> /// <param name="where">Pattern to construct Triples to delete</param> /// <param name="graphUri">URI of the affected Graph</param> public DeleteCommand(GraphPattern where, Uri graphUri) : this(where, where, graphUri) { }
/// <summary> /// Converts the Algebra back to a Graph Pattern /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern p = this._pattern.ToGraphPattern(); GraphPattern f = new GraphPattern(); f.AddFilter(this._filter); p.AddGraphPattern(f); return p; }
/// <summary> /// Createa a new DELETE command which operates on the Default Graph /// </summary> /// <param name="where">Pattern to construct Triples to delete</param> public DeleteCommand(GraphPattern where) : this(where, where, null) { }
/// <summary> /// Tries to place filters at the earliest point possible i.e. the first point after which all required variables have occurred /// </summary> /// <param name="gp">Graph Pattern</param> /// <param name="filter">Filter to place</param> /// <returns></returns> private bool TryPlaceFilter(GraphPattern gp, ISparqlFilter filter) { //Firstly we need to find out what variables are needed in the Filter List<String> variablesNeeded = filter.Variables.Distinct().ToList(); //Then we need to move through the Triple Patterns and find the first place at which all the //Variables used in the Filter have been used in ordinary Triple Patterns List<String> variablesUsed = new List<string>(); for (int p = 0; p < gp.TriplePatterns.Count; p++) { if (gp.TriplePatterns[p] is TriplePattern || gp.TriplePatterns[p] is IAssignmentPattern) { foreach (String var in gp.TriplePatterns[p].Variables) { if (!variablesUsed.Contains(var)) variablesUsed.Add(var); } //Have all the Variables we need now been used in a Pattern? if (variablesNeeded.All(v => variablesUsed.Contains(v))) { //We can place this Filter after the Pattern we were just looking at gp.InsertFilter(filter, p + 1); return true; } } } //If we reach here then this means that all the Variables used in the Filter did not occur //in the Triple Patterns which means they likely occur in child graph patterns (or the query //is malformed). In this case we cannot place the Filter and it has to be applied post-commit //rather than during Triple Pattern execution return false; }
/// <summary> /// Formats a Graph Pattern in nicely formatted SPARQL syntax /// </summary> /// <param name="gp">Graph Pattern</param> /// <returns></returns> public virtual String Format(GraphPattern gp) { if (gp == null) throw new RdfOutputException("Cannot format a null Graph Pattern as a String"); StringBuilder output = new StringBuilder(); if (gp.IsUnion) { for (int i = 0; i < gp.ChildGraphPatterns.Count; i++) { output.Append(this.Format(gp.ChildGraphPatterns[i])); if (i < gp.ChildGraphPatterns.Count - 1) { output.AppendLine(); output.AppendLine("UNION"); } } return output.ToString(); } else if (gp.IsGraph || gp.IsService) { if (gp.IsGraph) { output.Append("GRAPH "); } else { output.Append("SERVICE "); if (gp.IsSilent) output.Append("SILENT "); } switch (gp.GraphSpecifier.TokenType) { case Token.QNAME: try { String uri = Tools.ResolveQName(gp.GraphSpecifier.Value, this._qnameMapper, this._tempBaseUri); //If the QName resolves OK in the context of the Namespace Map we're using to format this then we //can print the QName as-is output.Append(gp.GraphSpecifier.Value); } catch { //If the QName fails to resolve then can't format in the context throw new RdfOutputException("Cannot format the Graph/Service Specifier QName " + gp.GraphSpecifier.Value + " as the Namespace Mapper in use for this Formatter cannot resolve the QName"); } break; case Token.URI: output.Append('<'); output.Append(this.FormatUri(gp.GraphSpecifier.Value)); output.Append('>'); break; case Token.VARIABLE: default: output.Append(gp.GraphSpecifier.Value); break; } output.Append(' '); } else if (gp.IsSubQuery) { output.AppendLine("{"); output.AppendLineIndented(this.Format(((SubQueryPattern)gp.TriplePatterns[0]).SubQuery), 2); output.AppendLine("}"); return output.ToString(); } else if (gp.IsOptional) { output.Append("OPTIONAL "); } else if (gp.IsExists) { output.Append("EXISTS "); } else if (gp.IsNotExists) { output.Append("NOT EXISTS "); } else if (gp.IsMinus) { output.Append("MINUS "); } if (gp.TriplePatterns.Count > 1 || gp.HasChildGraphPatterns || (gp.TriplePatterns.Count <= 1 && gp.Filter != null) || gp.UnplacedAssignments.Count() > 0 || gp.UnplacedFilters.Count() > 0) { output.AppendLine("{"); foreach (ITriplePattern tp in gp.TriplePatterns) { output.AppendLineIndented(this.Format(tp), 2); } foreach (IAssignmentPattern ap in gp.UnplacedAssignments) { output.AppendLineIndented(this.Format(ap), 2); } foreach (GraphPattern child in gp.ChildGraphPatterns) { output.AppendLineIndented(this.Format(child), 2); } foreach (ISparqlFilter fp in gp.UnplacedFilters) { output.AppendIndented("FILTER(", 2); output.Append(this.FormatExpression(fp.Expression)); output.AppendLine(")"); } output.Append("}"); } else if (gp.TriplePatterns.Count == 0) { if (gp.Filter != null) { output.AppendIndented("{ FILTER(", 2); output.Append(this.FormatExpression(gp.Filter.Expression)); output.AppendLine(") }"); } else { output.Append("{ }"); } } else { output.Append("{ "); output.Append(this.Format(gp.TriplePatterns[0])); output.Append(" }"); } return output.ToString(); }
/// <summary> /// Causes the Graph Pattern to be optimised if it isn't already /// </summary> /// <param name="gp">Graph Pattern</param> /// <param name="variables">Variables that have occurred prior to this Pattern</param> public void Optimise(GraphPattern gp, IEnumerable<String> variables) { //Our Variables is initially only those in our Triple Patterns since //anything else is considered to be out of scope List<String> ourVariables = (from tp in gp.TriplePatterns from v in tp.Variables select v).Distinct().ToList(); //Start by sorting the Triple Patterns in the list according to the ranking function gp.TriplePatterns.Sort(this.GetRankingComparer()); //Apply reordering unless an optimiser has chosen to disable it if (this.ShouldReorder) { if (gp.TriplePatterns.Count > 0) { //After we sort which gives us a rough optimisation we then may want to reorder //based on the Variables that occurred previous to us OR if we're the Root Graph Pattern if (!variables.Any()) { //Optimise this Graph Pattern //No previously occurring variables so must be the first Graph Pattern if (gp.TriplePatterns.Count > 1) { HashSet<String> currVariables = new HashSet<String>(); gp.TriplePatterns[0].Variables.ForEach(v => currVariables.Add(v)); for (int i = 1; i < gp.TriplePatterns.Count - 1; i++) { if (currVariables.Count == 0) { gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v)); continue; } else if (currVariables.IsDisjoint(gp.TriplePatterns[i].Variables)) { this.TryReorderPatterns(gp, currVariables.ToList(), i + 1, i); gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v)); } else { gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v)); } } } } else { //Optimise this Graph Pattern based on previously occurring variables if (gp.TriplePatterns.Count > 1 && !gp.TriplePatterns[0].Variables.Any(v => variables.Contains(v)) && variables.Intersect(ourVariables).Any()) { this.TryReorderPatterns(gp, variables.ToList(), 1, 0); } else if (gp.TriplePatterns.Count > 2) { //In the case where there are more than 2 patterns then we can try and reorder these //in order to further optimise the pattern this.TryReorderPatterns(gp, gp.TriplePatterns[0].Variables, 2, 1); } } } } if (this.ShouldPlaceAssignments) { //First we need to place Assignments (LETs) in appropriate places within the Pattern //This happens before Filter placement since Filters may use variables assigned to in LETs if (gp.UnplacedAssignments.Any()) { //Need to ensure that we sort Assignments //This way those that use fewer variables get placed first List<IAssignmentPattern> ps = gp.UnplacedAssignments.OrderBy(x => x).ToList(); //This next bit goes in a do loop as we want to keep attempting to place assignments while //we are able to do so. If the count of unplaced assignments has decreased but is not //zero it may be that we were unable to place some patterns as they relied on variables //assigned in other LETs which weren't placed when we attempted to place them //When we reach the point where no further placements have occurred or all assignments //are placed we stop trying to place assignments int c; do { c = ps.Count; int i = 0; while (i < ps.Count) { if (this.TryPlaceAssignment(gp, ps[i])) { //Remove from Unplaced Assignments since it's been successfully placed in the Triple Patterns //Don't increment the counter since the next Assignment is now at the index we're already at ps.RemoveAt(i); } else { //Unable to place so increment counter i++; } } } while (c > ps.Count && ps.Count > 0); } } //Regardless of what we've placed already we now place all remaining assignments foreach (IAssignmentPattern assignment in gp.UnplacedAssignments.ToList()) { gp.InsertAssignment(assignment, gp.TriplePatterns.Count); } if (this.ShouldPlaceFilters) { //Then we need to place the Filters in appropriate places within the Pattern if (gp.UnplacedFilters.Any()) { if (gp.TriplePatterns.Count == 0) { //Where there are no Triple Patterns the Graph Pattern just contains this Filter and possibly some //child Graph Patterns. In such a case then we shouldn't place the Filters } else { foreach (ISparqlFilter f in gp.UnplacedFilters.ToList()) { this.TryPlaceFilter(gp, f); } } } } //Finally optimise the Child Graph Patterns foreach (GraphPattern cgp in gp.ChildGraphPatterns) { //At each point the variables that have occurred are those in the Triple Patterns and //those in previous Graph Patterns cgp.Optimise(this, ourVariables); ourVariables.AddRange(cgp.Variables); } //Note: Any remaining Unplaced Filters/Assignments are OK since the ToAlgebra() method of a GraphPattern //will take care of placing these appropriately }
/// <summary> /// Converts the Algebra into a Graph Pattern /// </summary> /// <returns></returns> public GraphPattern ToGraphPattern() { GraphPattern p = new GraphPattern(this._pattern); if (!p.HasModifier) { p.IsService = true; p.GraphSpecifier = this._endpointSpecifier; return p; } else { GraphPattern parent = new GraphPattern(); parent.IsService = true; parent.GraphSpecifier = this._endpointSpecifier; parent.AddGraphPattern(p); return parent; } }