/// <summary> /// Optimises the algebra so that all Node terms are virtualised /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); TNodeID nullID = this._provider.NullID; for (int i = 0; i < current.PatternCount; i++) { if (ps[i] is FilterPattern || ps[i] is BindPattern) { //First ensure that if we've found any other Triple Patterns up to this point //we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } if (ps[i] is FilterPattern) { result = new Filter(result, ((FilterPattern)ps[i]).Filter); } else { BindPattern bind = (BindPattern)ps[i]; result = new Extend(result, bind.AssignExpression, bind.VariableName); } } else { //Convert Terms in the Pattern into Virtual Nodes TriplePattern tp = (TriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } } if (result is NullOperator) { return(result); } else if (patterns.Count == current.PatternCount) { //If count of remaining patterns same as original pattern count there was no optimisation //to do so return as is return(current); } else if (patterns.Count > 0) { //If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
/// <summary> /// Optimises BGPs in the Algebra to use Filter() and Extend() rather than the embedded FILTER and BIND /// </summary> /// <param name="algebra">Algebra to optimise</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); for (int i = 0; i < current.PatternCount; i++) { if (!(ps[i] is TriplePattern)) { //First ensure that if we've found any other Triple Patterns up to this point //we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } //Then generate the appropriate strict algebra operator if (ps[i] is FilterPattern) { result = new Filter(result, ((FilterPattern)ps[i]).Filter); } else if (ps[i] is BindPattern) { BindPattern bind = (BindPattern)ps[i]; result = new Extend(result, bind.AssignExpression, bind.VariableName); } else if (ps[i] is LetPattern) { LetPattern let = (LetPattern)ps[i]; result = new Extend(result, let.AssignExpression, let.VariableName); } else if (ps[i] is SubQueryPattern) { SubQueryPattern sq = (SubQueryPattern)ps[i]; result = Join.CreateJoin(result, new SubQuery(sq.SubQuery)); } else if (ps[i] is PropertyPathPattern) { PropertyPathPattern pp = (PropertyPathPattern)ps[i]; result = Join.CreateJoin(result, new PropertyPath(pp.Subject, pp.Path, pp.Object)); } } else { patterns.Add(ps[i]); } } if (patterns.Count == current.PatternCount) { //If count of remaining patterns same as original pattern count there was no optimisation //to do so return as is return(current); } else if (patterns.Count > 0) { //If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
/// <summary> /// Gets the Algebra representation of the Graph Pattern /// </summary> /// <returns></returns> public ISparqlAlgebra ToAlgebra() { if (_isUnion) { // If this Graph Pattern represents a UNION of Graph Patterns turn into a series of UNIONs ISparqlAlgebra union = new Union(_graphPatterns[0].ToAlgebra(), _graphPatterns[1].ToAlgebra()); if (_graphPatterns.Count > 2) { for (int i = 2; i < _graphPatterns.Count; i++) { union = new Union(union, _graphPatterns[i].ToAlgebra()); } } // Apply Inline Data if (HasInlineData) { union = Join.CreateJoin(union, new Bindings(_data)); } // If there's a FILTER apply it over the Union if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { return(new Filter(union, Filter)); } return(union); } // Terminal graph pattern if (_graphPatterns.Count == 0) { // If there are no Child Graph Patterns then this is a BGP ISparqlAlgebra bgp = new Bgp(_triplePatterns); if (_unplacedAssignments.Count > 0) { // If we have any unplaced LETs these get Extended onto the BGP foreach (IAssignmentPattern p in _unplacedAssignments) { bgp = new Extend(bgp, p.AssignExpression, p.VariableName); } } if (IsGraph) { bgp = Algebra.Graph.ApplyGraph(bgp, GraphSpecifier); } else if (IsService) { bgp = new Service(GraphSpecifier, this, IsSilent); } // Apply Inline Data if (HasInlineData) { bgp = Join.CreateJoin(bgp, new Bindings(_data)); } if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { if (_isOptional && !(_isExists || _isNotExists)) { // If we contain an unplaced FILTER and we're an OPTIONAL then the FILTER // applies over the LEFT JOIN and will have been added elsewhere in the Algebra transform return(bgp); } // If we contain an unplaced FILTER and we're not an OPTIONAL the FILTER // applies here return(new Filter(bgp, Filter)); } // We're not filtered (or all FILTERs were placed in the BGP) so we're just a BGP return(bgp); } // Create a basic BGP to start with ISparqlAlgebra complex = new Bgp(); if (_triplePatterns.Count > 0) { complex = new Bgp(_triplePatterns); } // Apply Inline Data // If this Graph Pattern had child patterns before this Graph Pattern then we would // have broken the BGP and not added the Inline Data here so it's always safe to apply this here if (HasInlineData) { complex = Join.CreateJoin(complex, new Bindings(_data)); } // Then Join each of the Graph Patterns as appropriate foreach (GraphPattern gp in _graphPatterns) { if (gp.IsGraph) { // A GRAPH clause means a Join of the current pattern to a Graph clause ISparqlAlgebra gpAlgebra = gp.ToAlgebra(); complex = Join.CreateJoin(complex, Algebra.Graph.ApplyGraph(gpAlgebra, gp.GraphSpecifier)); } else if (gp.IsOptional) { if (gp.IsExists || gp.IsNotExists) { // An EXISTS/NOT EXISTS means an Exists Join of the current pattern to the EXISTS/NOT EXISTS clause complex = new ExistsJoin(complex, gp.ToAlgebra(), gp.IsExists); } else { // An OPTIONAL means a Left Join of the current pattern to the OPTIONAL clause // with a possible FILTER applied over the LeftJoin if (gp.IsFiltered && gp.Filter != null) { // If the OPTIONAL clause has an unplaced FILTER it applies over the Left Join complex = new LeftJoin(complex, gp.ToAlgebra(), gp.Filter); } else { complex = new LeftJoin(complex, gp.ToAlgebra()); } } } else if (gp.IsMinus) { // Always introduce a Minus here even if the Minus is disjoint since during evaluation we'll choose // not to execute it if it's disjoint complex = new Minus(complex, gp.ToAlgebra()); } else if (gp.IsService) { complex = Join.CreateJoin(complex, new Service(gp.GraphSpecifier, gp, gp.IsSilent)); } else { // Otherwise we just join the pattern to the existing pattern complex = Join.CreateJoin(complex, gp.ToAlgebra()); } } if (_unplacedAssignments.Count > 0) { // Unplaced assignments get Extended over the algebra so far here // complex = Join.CreateJoin(complex, new Bgp(this._unplacedAssignments.OfType<ITriplePattern>())); foreach (IAssignmentPattern p in _unplacedAssignments) { complex = new Extend(complex, p.AssignExpression, p.VariableName); } } if (IsGraph) { complex = Algebra.Graph.ApplyGraph(complex, GraphSpecifier); } if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { if (_isOptional && !(_isExists || _isNotExists)) { // If there's an unplaced FILTER and we're an OPTIONAL then the FILTER will // apply over the LeftJoin and is applied elsewhere in the Algebra transform return(complex); } else { if (_filter != null || _unplacedFilters.Count > 0) { // If there's an unplaced FILTER and we're not an OPTIONAL pattern we apply // the FILTER here return(new Filter(complex, Filter)); } else { return(complex); } } } else { // If no FILTER just return the transform return(complex); } }
/// <summary> /// Optimises the algebra so that all Node terms are virtualised. /// </summary> /// <param name="algebra">Algebra.</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); TNodeID nullID = _provider.NullID; for (int i = 0; i < current.PatternCount; i++) { if (ps[i].PatternType == TriplePatternType.Filter || ps[i].PatternType == TriplePatternType.BindAssignment || ps[i].PatternType == TriplePatternType.LetAssignment) { // First ensure that if we've found any other Triple Patterns up to this point // we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } if (ps[i].PatternType == TriplePatternType.Filter) { result = new Filter(result, new UnaryExpressionFilter(Transform(((IFilterPattern)ps[i]).Filter.Expression))); } else { IAssignmentPattern bind = (IAssignmentPattern)ps[i]; result = new Extend(result, Transform(bind.AssignExpression), bind.VariableName); } } else if (ps[i].PatternType == TriplePatternType.Match) { // Convert Terms in the Pattern into Virtual Nodes IMatchTriplePattern tp = (IMatchTriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } else { // Can't optimize if other pattern types involved return(current); } } if (result is NullOperator) { return(result); } else if (patterns.Count > 0) { // If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
/// <summary> /// Optimises BGPs in the Algebra to use Filter() and Extend() rather than the embedded FILTER and BIND /// </summary> /// <param name="algebra">Algebra to optimise</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { // Don't integerfer with other optimisers which have added custom BGP implementations if (!(algebra is Bgp)) { return(algebra); } IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); for (int i = 0; i < current.PatternCount; i++) { // Can't split the BGP if there are Blank Nodes present if (!ps[i].HasNoBlankVariables) { return(current); } if (ps[i].PatternType != TriplePatternType.Match) { // First ensure that if we've found any other Triple Patterns up to this point // we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } // Then generate the appropriate strict algebra operator switch (ps[i].PatternType) { case TriplePatternType.Filter: result = new Filter(result, ((IFilterPattern)ps[i]).Filter); break; case TriplePatternType.BindAssignment: case TriplePatternType.LetAssignment: IAssignmentPattern assignment = (IAssignmentPattern)ps[i]; result = new Extend(result, assignment.AssignExpression, assignment.VariableName); break; case TriplePatternType.SubQuery: ISubQueryPattern sq = (ISubQueryPattern)ps[i]; result = Join.CreateJoin(result, new SubQuery(sq.SubQuery)); break; case TriplePatternType.Path: IPropertyPathPattern pp = (IPropertyPathPattern)ps[i]; result = Join.CreateJoin(result, new PropertyPath(pp.Subject, pp.Path, pp.Object)); break; case TriplePatternType.PropertyFunction: IPropertyFunctionPattern pf = (IPropertyFunctionPattern)ps[i]; result = new PropertyFunction(result, pf.PropertyFunction); break; default: throw new RdfQueryException("Cannot apply strict algebra form to a BGP containing a unknown triple pattern type"); } } else { patterns.Add(ps[i]); } } if (patterns.Count == current.PatternCount) { // If count of remaining patterns same as original pattern count there was no optimisation // to do so return as is return(current); } else if (patterns.Count > 0) { // If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
/// <summary> /// Converts the Query into it's SPARQL Algebra representation (as represented in the Leviathan API) /// </summary> /// <returns></returns> public ISparqlAlgebra ToAlgebra() { //Depending on how the query gets built we may not have had graph pattern optimization applied //which we should do here if query optimization is enabled if (!this.IsOptimised && Options.QueryOptimisation) { this.Optimise(); } //Firstly Transform the Root Graph Pattern to SPARQL Algebra ISparqlAlgebra algebra; if (this._rootGraphPattern != null) { if (Options.AlgebraOptimisation) { //If using Algebra Optimisation may use a special algebra in some cases switch (this.SpecialType) { case SparqlSpecialQueryType.DistinctGraphs: algebra = new SelectDistinctGraphs(this.Variables.First(v => v.IsResultVariable).Name); break; case SparqlSpecialQueryType.AskAnyTriples: algebra = new AskAnyTriples(); break; case SparqlSpecialQueryType.NotApplicable: default: //If not just use the standard transform algebra = this._rootGraphPattern.ToAlgebra(); break; } } else { //If not using Algebra Optimisation just use the standard transform algebra = this._rootGraphPattern.ToAlgebra(); } } else { //No root graph pattern means empty BGP algebra = new Bgp(); } //If we have a top level VALUES clause then we'll add it into the algebra here if (this._bindings != null) { algebra = Join.CreateJoin(algebra, new Bindings(this._bindings)); } //Then we apply any optimisers followed by relevant solution modifiers switch (this._type) { case SparqlQueryType.Ask: //Apply Algebra Optimisation is enabled if (Options.AlgebraOptimisation) { algebra = this.ApplyAlgebraOptimisations(algebra); } return(new Ask(algebra)); case SparqlQueryType.Construct: case SparqlQueryType.Describe: case SparqlQueryType.DescribeAll: case SparqlQueryType.Select: case SparqlQueryType.SelectAll: case SparqlQueryType.SelectAllDistinct: case SparqlQueryType.SelectAllReduced: case SparqlQueryType.SelectDistinct: case SparqlQueryType.SelectReduced: //Apply Algebra Optimisation if enabled if (Options.AlgebraOptimisation) { algebra = this.ApplyAlgebraOptimisations(algebra); } //GROUP BY is the first thing applied //This applies if there is a GROUP BY or if there are aggregates //With no GROUP BY it produces a single group of all results if (this._groupBy != null || this._vars.Any(v => v.IsAggregate)) { algebra = new GroupBy(algebra, this._groupBy, this._vars.Where(v => v.IsAggregate)); } //After grouping we do projection //We introduce an Extend for each Project Expression foreach (SparqlVariable var in this._vars) { if (var.IsProjection) { algebra = new Extend(algebra, var.Projection, var.Name); } } //Add HAVING clause after the projection if (this._having != null) { algebra = new Having(algebra, this._having); } //We can then Order our results //We do ordering before we do Select but after Project so we can order by any of //the project expressions/aggregates and any variable in the results even if //it won't be output as a result variable if (this._orderBy != null) { algebra = new OrderBy(algebra, this._orderBy); } //After Ordering we apply Select //Select effectively trims the results so only result variables are left //This doesn't apply to CONSTRUCT since any variable may be used in the Construct Template //so we don't want to eliminate anything if (this._type != SparqlQueryType.Construct) { algebra = new Select(algebra, this.Variables); } //If we have a Distinct/Reduced then we'll apply those after Selection if (this._type == SparqlQueryType.SelectAllDistinct || this._type == SparqlQueryType.SelectDistinct) { algebra = new Distinct(algebra); } else if (this._type == SparqlQueryType.SelectAllReduced || this._type == SparqlQueryType.SelectReduced) { algebra = new Reduced(algebra); } //Finally we can apply any limit and/or offset if (this._limit >= 0 || this._offset > 0) { algebra = new Slice(algebra, this._limit, this._offset); } return(algebra); default: throw new RdfQueryException("Unable to convert unknown Query Types to SPARQL Algebra"); } }
/// <summary> /// Gets the Algebra representation of the Graph Pattern /// </summary> /// <returns></returns> public ISparqlAlgebra ToAlgebra() { if (this._isUnion) { //If this Graph Pattern represents a UNION of Graph Patterns turn into a series of UNIONs ISparqlAlgebra union = new Union(this._graphPatterns[0].ToAlgebra(), this._graphPatterns[1].ToAlgebra()); if (this._graphPatterns.Count > 2) { for (int i = 2; i < this._graphPatterns.Count; i++) { union = new Union(union, this._graphPatterns[i].ToAlgebra()); } } //If there's a FILTER apply it over the Union if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0)) { return(new Filter(union, this.Filter)); } else { return(union); } } else if (this._graphPatterns.Count == 0) { //If there are no Child Graph Patterns then this is a BGP ISparqlAlgebra bgp = new Bgp(this._triplePatterns); if (this._unplacedAssignments.Count > 0) { //If we have any unplaced LETs these get Joined onto the BGP bgp = Join.CreateJoin(bgp, new Bgp(this._unplacedAssignments)); } if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0)) { if (this._isOptional && !(this._isExists || this._isNotExists)) { //If we contain an unplaced FILTER and we're an OPTIONAL then the FILTER //applies over the LEFT JOIN and will have been added elsewhere in the Algebra transform return(bgp); } else { ISparqlAlgebra complex = bgp; //If we contain an unplaced FILTER and we're not an OPTIONAL the FILTER //applies here return(new Filter(bgp, this.Filter)); } } else { //We're not filtered (or all FILTERs were placed in the BGP) so we're just a BGP return(bgp); } } else { //Create a basic BGP to start with ISparqlAlgebra complex = new Bgp(); if (this._triplePatterns.Count > 0) { complex = new Bgp(this._triplePatterns); } //Then Join each of the Graph Patterns as appropriate foreach (GraphPattern gp in this._graphPatterns) { if (gp.IsGraph) { //A GRAPH clause means a Join of the current pattern to a Graph clause complex = Join.CreateJoin(complex, new Algebra.Graph(gp.ToAlgebra(), gp.GraphSpecifier)); } else if (gp.IsOptional) { if (gp.IsExists || gp.IsNotExists) { //An EXISTS/NOT EXISTS means an Exists Join of the current pattern to the EXISTS/NOT EXISTS clause complex = new ExistsJoin(complex, gp.ToAlgebra(), gp.IsExists); } else { //An OPTIONAL means a Left Join of the current pattern to the OPTIONAL clause //with a possible FILTER applied over the LeftJoin if (gp.IsFiltered && gp.Filter != null) { //If the OPTIONAL clause has an unplaced FILTER it applies over the Left Join complex = new LeftJoin(complex, gp.ToAlgebra(), gp.Filter); } else { complex = new LeftJoin(complex, gp.ToAlgebra()); } } } else if (gp.IsMinus) { //Always introduce a Minus here even if the Minus is disjoint since during evaluation we'll choose //not to execute it if it's disjoint complex = new Minus(complex, gp.ToAlgebra()); } else if (gp.IsService) { complex = Join.CreateJoin(complex, new Service(gp.GraphSpecifier, gp, gp.IsSilent)); } else { //Otherwise we just join the pattern to the existing pattern complex = Join.CreateJoin(complex, gp.ToAlgebra()); } } if (this._unplacedAssignments.Count > 0) { //Unplaced assignments get Joined as a BGP here complex = Join.CreateJoin(complex, new Bgp(this._unplacedAssignments)); } if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0)) { if (this._isOptional && !(this._isExists || this._isNotExists)) { //If there's an unplaced FILTER and we're an OPTIONAL then the FILTER will //apply over the LeftJoin and is applied elsewhere in the Algebra transform return(complex); } else { if (this._filter != null || this._unplacedFilters.Count > 0) { //If there's an unplaced FILTER and we're not an OPTIONAL pattern we apply //the FILTER here return(new Filter(complex, this.Filter)); } else { return(complex); } } } else { //If no FILTER just return the transform return(complex); } } }
/// <summary> /// Optimises the Algebra so that BGPs containing relevant patterns are converted to use the <see cref="FullTextMatch">FullTextMatch</see> operator /// </summary> /// <param name="algebra">Algebra to optimise</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <FullTextPattern> fps = FullTextHelper.ExtractPatterns(current.TriplePatterns); if (fps.Count == 0) { return(algebra); } List <ITriplePattern> ps = current.TriplePatterns.ToList(); //First we want to find where each FullTextPattern is located in the original triple patterns Dictionary <int, int> locations = new Dictionary <int, int>(); for (int i = 0; i < fps.Count; i++) { locations.Add(i, -1); ITriplePattern first = fps[i].OriginalPatterns.First(); for (int j = 0; j < ps.Count; j++) { if (first.Equals(ps[j])) { locations[i] = j; break; } } //If we fail to locate this we've failed to optimise here so must abort if (locations[i] == -1) { return(algebra); } } //Knowing this we can then start splitting the BGP into several BGPs int locBase = 0; foreach (int i in Enumerable.Range(0, fps.Count).OrderBy(x => locations[x]).ToList()) { //Wrap everything up to that point in a BGP excluding any patterns relevant to any FullTextPattern result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Take(locations[i]).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp))))); locBase = locations[i] + 1; //Then apply the FullTextMatch operator over it FullTextPattern ftp = fps[i]; result = new FullTextMatch(this._provider, result, ftp.MatchVariable, ftp.ScoreVariable, ftp.SearchTerm, ftp.Limit, ftp.ScoreThreshold); } //If there are any patterns left over remember to include them if (locBase < ps.Count) { result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp))))); } return(result); //List<ITriplePattern> patterns = new List<ITriplePattern>(); //List<ITriplePattern> ps = new List<ITriplePattern>(current.TriplePatterns.ToList()); //for (int i = 0; i < current.PatternCount; i++) //{ // if (!(ps[i] is TriplePattern)) // { // patterns.Add(ps[i]); // } // else // { // //Check to see if the Predicate of the Pattern match the Full Text Match Predicate URI // TriplePattern tp = (TriplePattern)ps[i]; // PatternItem pred = tp.Predicate; // if (pred is NodeMatchPattern) // { // INode predNode = ((NodeMatchPattern)pred).Node; // if (predNode.NodeType == NodeType.Uri) // { // String predUri = ((IUriNode)predNode).Uri.ToString(); // if (predUri.Equals(FullTextHelper.FullTextMatchPredicateUri)) // { // if (patterns.Count > 0) result = Join.CreateJoin(result, new Bgp(patterns)); // result = new FullTextMatch(this._provider, result, tp.Subject, tp.Object); // patterns.Clear(); // } // else // { // patterns.Add(ps[i]); // } // } // else // { // patterns.Add(ps[i]); // } // } // else // { // patterns.Add(ps[i]); // } // } //} //if (patterns.Count == current.PatternCount) //{ // //If count of remaining patterns same as original pattern count there was no optimisation // //to do so return as is // return current; //} //else if (patterns.Count > 0) //{ // //If any patterns left at end join as a BGP with result so far // result = Join.CreateJoin(result, new Bgp(patterns)); // return result; //} //else //{ // return result; //} } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }