Пример #1
0
        /// <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;
        }
Пример #2
0
 /// <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();
     }
 }
Пример #3
0
 /// <summary>
 /// Inserts an Assignment at a given position
 /// </summary>
 /// <param name="assignment">Assignment</param>
 /// <param name="i">Position to insert at</param>
 /// <remarks>
 /// Intended for use by Query Optimisers
 /// </remarks>
 public void InsertAssignment(IAssignmentPattern assignment, int i)
 {
     if (!this._unplacedAssignments.Contains(assignment)) throw new RdfQueryException("Cannot Insert an Assignment that is not currently an unplaced Assignment in this Graph Pattern");
     this._unplacedAssignments.Remove(assignment);
     this._triplePatterns.Insert(i, assignment);
 }
Пример #4
0
 /// <summary>
 /// Compares this Let to another Let.
 /// </summary>
 /// <param name="other">Let to compare to.</param>
 /// <returns>Just calls the base compare method since that implements all the logic we need.</returns>
 public int CompareTo(IAssignmentPattern other)
 {
     return(base.CompareTo(other));
 }
        /// <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].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(this.Transform(((IFilterPattern)ps[i]).Filter.Expression)));
                            }
                            else
                            {
                                IAssignmentPattern bind = (IAssignmentPattern)ps[i];
                                result = new Extend(result, this.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 = 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));
                        }
                        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);
            }
        }
Пример #6
0
        /// <summary>
        /// Formats a Triple Pattern in nicely formatted SPARQL syntax
        /// </summary>
        /// <param name="tp">Triple Pattern</param>
        /// <returns></returns>
        public virtual String Format(ITriplePattern tp)
        {
            StringBuilder output = new StringBuilder();

            switch (tp.PatternType)
            {
            case TriplePatternType.Match:
                IMatchTriplePattern match = (IMatchTriplePattern)tp;
                output.Append(Format(match.Subject, TripleSegment.Subject));
                output.Append(' ');
                output.Append(Format(match.Predicate, TripleSegment.Predicate));
                output.Append(' ');
                output.Append(Format(match.Object, TripleSegment.Object));
                output.Append(" .");
                break;

            case TriplePatternType.Filter:
                IFilterPattern filter = (IFilterPattern)tp;
                output.Append("FILTER(");
                output.Append(FormatExpression(filter.Filter.Expression));
                output.Append(")");
                break;

            case TriplePatternType.SubQuery:
                ISubQueryPattern subquery = (ISubQueryPattern)tp;
                output.AppendLine("{");
                output.AppendLineIndented(Format(subquery.SubQuery), 2);
                output.AppendLine("}");
                break;

            case TriplePatternType.Path:
                IPropertyPathPattern path = (IPropertyPathPattern)tp;
                output.Append(Format(path.Subject, TripleSegment.Subject));
                output.Append(' ');
                output.Append(FormatPath(path.Path));
                output.Append(' ');
                output.Append(Format(path.Object, TripleSegment.Object));
                output.Append(" .");
                break;

            case TriplePatternType.LetAssignment:
                IAssignmentPattern let = (IAssignmentPattern)tp;
                output.Append("LET(?");
                output.Append(let.VariableName);
                output.Append(" := ");
                output.Append(FormatExpression(let.AssignExpression));
                output.Append(")");
                break;

            case TriplePatternType.BindAssignment:
                IAssignmentPattern bind = (IAssignmentPattern)tp;
                output.Append("BIND (");
                output.Append(FormatExpression(bind.AssignExpression));
                output.Append(" AS ?");
                output.Append(bind.VariableName);
                output.Append(")");
                break;

            case TriplePatternType.PropertyFunction:
                IPropertyFunctionPattern propFunc = (IPropertyFunctionPattern)tp;
                if (propFunc.SubjectArgs.Count() > 1)
                {
                    output.Append("( ");
                    foreach (PatternItem arg in propFunc.SubjectArgs)
                    {
                        output.Append(Format(arg, TripleSegment.Subject));
                        output.Append(' ');
                    }
                    output.Append(')');
                }
                else
                {
                    output.Append(Format(propFunc.SubjectArgs.First(), TripleSegment.Subject));
                }
                output.Append(" <");
                output.Append(FormatUri(propFunc.PropertyFunction.FunctionUri));
                output.Append("> ");
                if (propFunc.ObjectArgs.Count() > 1)
                {
                    output.Append("( ");
                    foreach (PatternItem arg in propFunc.ObjectArgs)
                    {
                        output.Append(Format(arg, TripleSegment.Object));
                        output.Append(' ');
                    }
                    output.Append(')');
                }
                else
                {
                    output.Append(Format(propFunc.ObjectArgs.First(), TripleSegment.Object));
                }
                output.Append(" .");
                break;

            default:
                throw new RdfOutputException("Unable to Format an unknown ITriplePattern implementation as a String");
            }

            return(output.ToString());
        }
        /// <summary>
        /// Attempts to do variable substitution within the given algebra.
        /// </summary>
        /// <param name="algebra">Algebra.</param>
        /// <returns></returns>
        public ISparqlAlgebra Optimise(ISparqlAlgebra algebra)
        {
            // By default we are only safe to replace objects in a scope if we are replacing with a constant
            // Note that if we also make a replace in a subject/predicate position for a variable replace then
            // that makes object replacement safe for that scope only
            bool canReplaceObjects = (_canReplaceCustom ? _canReplaceObjects : _replaceItem is NodeMatchPattern);

            if (algebra is IBgp)
            {
                IBgp bgp = (IBgp)algebra;
                if (bgp.PatternCount == 0)
                {
                    return(bgp);
                }

                // Do variable substitution on the patterns
                List <ITriplePattern> ps = new List <ITriplePattern>();
                foreach (ITriplePattern p in bgp.TriplePatterns)
                {
                    switch (p.PatternType)
                    {
                    case TriplePatternType.Match:
                        IMatchTriplePattern tp   = (IMatchTriplePattern)p;
                        PatternItem         subj = tp.Subject.VariableName != null && tp.Subject.VariableName.Equals(_findVar) ? _replaceItem : tp.Subject;
                        if (ReferenceEquals(subj, _replaceItem))
                        {
                            canReplaceObjects = (_canReplaceCustom ? _canReplaceObjects : true);
                        }
                        PatternItem pred = tp.Predicate.VariableName != null && tp.Predicate.VariableName.Equals(_findVar) ? _replaceItem : tp.Predicate;
                        if (ReferenceEquals(pred, _replaceItem))
                        {
                            canReplaceObjects = (_canReplaceCustom ? _canReplaceObjects : true);
                        }
                        PatternItem obj = tp.Object.VariableName != null && tp.Object.VariableName.Equals(_findVar) ? _replaceItem : tp.Object;
                        if (ReferenceEquals(obj, _replaceItem) && !canReplaceObjects)
                        {
                            throw new Exception("Unable to substitute a variable into the object position in this scope");
                        }
                        ps.Add(new TriplePattern(subj, pred, obj));
                        break;

                    case TriplePatternType.Filter:
                        IFilterPattern fp = (IFilterPattern)p;
                        ps.Add(new FilterPattern(new UnaryExpressionFilter(Transform(fp.Filter.Expression))));
                        break;

                    case TriplePatternType.BindAssignment:
                        IAssignmentPattern bp = (IAssignmentPattern)p;
                        ps.Add(new BindPattern(bp.VariableName, Transform(bp.AssignExpression)));
                        break;

                    case TriplePatternType.LetAssignment:
                        IAssignmentPattern lp = (IAssignmentPattern)p;
                        ps.Add(new LetPattern(lp.VariableName, Transform(lp.AssignExpression)));
                        break;

                    case TriplePatternType.SubQuery:
                        throw new RdfQueryException("Cannot do variable substitution when a sub-query is present");

                    case TriplePatternType.Path:
                        throw new RdfQueryException("Cannot do variable substitution when a property path is present");

                    case TriplePatternType.PropertyFunction:
                        throw new RdfQueryException("Cannot do variable substituion when a property function is present");

                    default:
                        throw new RdfQueryException("Cannot do variable substitution on unknown triple patterns");
                    }
                }
                return(new Bgp(ps));
            }
            else if (algebra is Service)
            {
                throw new RdfQueryException("Cannot do variable substitution when a SERVICE clause is present");
            }
            else if (algebra is SubQuery)
            {
                throw new RdfQueryException("Cannot do variable substitution when a sub-query is present");
            }
            else if (algebra is IPathOperator)
            {
                throw new RdfQueryException("Cannot do variable substitution when a property path is present");
            }
            else if (algebra is Algebra.Graph)
            {
                Algebra.Graph g = (Algebra.Graph)((IUnaryOperator)algebra).Transform(this);
                if (g.GraphSpecifier is VariableToken && g.GraphSpecifier.Value.Equals("?" + _findVar))
                {
                    if (_replaceToken != null)
                    {
                        return(new Algebra.Graph(g.InnerAlgebra, _replaceToken));
                    }
                    else
                    {
                        throw new RdfQueryException("Cannot do a variable substitution when the variable is used for a GRAPH specifier and the replacement term is not a URI");
                    }
                }
                else
                {
                    return(g);
                }
            }
            else if (algebra is IUnaryOperator)
            {
                return(((IUnaryOperator)algebra).Transform(this));
            }
            else if (algebra is IAbstractJoin)
            {
                return(((IAbstractJoin)algebra).Transform(this));
            }
            else if (algebra is ITerminalOperator)
            {
                return(algebra);
            }
            else
            {
                throw new RdfQueryException("Cannot do variable substitution on unknown 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);
            }
        }