Пример #1
0
        /// <summary>
        /// Evaluates the Ask Union
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;

            if (this._lhs is Extend || this._rhs is Extend)
            {
                initialInput = new IdentityMultiset();
            }

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context);

            context.CheckTimeout();

            if (lhsResult.IsEmpty)
            {
                //Only evaluate the RHS if the LHS was empty
                context.InputMultiset = initialInput;
                BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context);
                context.CheckTimeout();

                context.OutputMultiset = lhsResult.Union(rhsResult);
                context.CheckTimeout();

                context.InputMultiset = context.OutputMultiset;
            }
            else
            {
                context.OutputMultiset = lhsResult;
            }
            return(context.OutputMultiset);
        }
Пример #2
0
        /// <summary>
        /// Evaluates the Lazy Union.
        /// </summary>
        /// <param name="context">Evaluation Context.</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;

            if (_lhs is Extend || _rhs is Extend)
            {
                initialInput = new IdentityMultiset();
            }

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(_lhs); //this._lhs.Evaluate(context);

            context.CheckTimeout();

            if (lhsResult.Count >= _requiredResults || _requiredResults == -1)
            {
                // Only evaluate the RHS if the LHS didn't yield sufficient results
                context.InputMultiset = initialInput;
                BaseMultiset rhsResult = context.Evaluate(_rhs); //this._rhs.Evaluate(context);
                context.CheckTimeout();

                context.OutputMultiset = lhsResult.Union(rhsResult);
                context.CheckTimeout();

                context.InputMultiset = context.OutputMultiset;
            }
            else
            {
                context.OutputMultiset = lhsResult;
            }
            return(context.OutputMultiset);
        }
Пример #3
0
        /// <summary>
        /// Evaluates the Union
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;

            if (_lhs is Extend || _rhs is Extend)
            {
                initialInput = new IdentityMultiset();
            }

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(_lhs);

            context.CheckTimeout();

            context.InputMultiset = initialInput;
            BaseMultiset rhsResult = context.Evaluate(_rhs);

            context.CheckTimeout();

            context.OutputMultiset = lhsResult.Union(rhsResult);
            context.CheckTimeout();

            context.InputMultiset = context.OutputMultiset;
            return(context.OutputMultiset);
        }
Пример #4
0
        public void SparqlMultisetLeftJoin()
        {
            //Create a load of Nodes to use in the tests
            Graph g = new Graph();
            g.NamespaceMap.AddNamespace(String.Empty, new Uri("http://example.org"));
            IUriNode s1 = g.CreateUriNode(":s1");
            IUriNode s2 = g.CreateUriNode(":s2");
            IUriNode p1 = g.CreateUriNode(":p1");
            IUriNode p2 = g.CreateUriNode(":p2");
            IUriNode rdfsLabel = g.CreateUriNode("rdfs:label");
            ILiteralNode o1 = g.CreateLiteralNode("Some Text");
            ILiteralNode o2 = g.CreateLiteralNode("1", new Uri(XmlSpecsHelper.XmlSchemaDataTypeInteger));

            //Create an ID and Null Multiset
            IdentityMultiset id = new IdentityMultiset();
            NullMultiset nullset = new NullMultiset();

            //Create and Populate a Multiset
            Multiset m = new Multiset();
            Set s = new Set();
            s.Add("s", s1);
            s.Add("p", p1);
            s.Add("o", o1);
            m.Add(s);
            s = new Set();
            s.Add("s", s2);
            s.Add("p", p2);
            s.Add("o", o2);
            m.Add(s);

            //Create and Populate another Multiset
            Multiset n = new Multiset();
            s = new Set();
            s.Add("s", s1);
            s.Add("label", o1);
            n.Add(s);

            //Create and Populate another Multiset
            Multiset d = new Multiset();
            s = new Set();
            s.Add("s1", s1);
            s.Add("p1", p1);
            s.Add("o1", o1);
            d.Add(s);
            s = new Set();
            s.Add("s1", s2);
            s.Add("p1", p2);
            s.Add("o1", o2);
            d.Add(s);

            //Show the Sets
            Console.WriteLine("LHS");
            foreach (Set set in m.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
            Console.WriteLine("RHS");
            foreach (Set set in n.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
            Console.WriteLine("D");
            foreach (Set set in d.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Identity
            Console.WriteLine("Join ID-LHS");
            BaseMultiset join = id.Join(m);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Identity
            Console.WriteLine("Join LHS-ID");
            join = m.Join(id);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Null
            Console.WriteLine("Join NULL-LHS");
            join = nullset.Join(m);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Null
            Console.WriteLine("Join LHS-NULL");
            join = m.Join(nullset);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a LeftJoin
            Console.WriteLine("LeftJoin NULL-LHS");
            BaseMultiset leftjoin = nullset.LeftJoin(m, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a LeftJoin
            Console.WriteLine("LeftJoin LHS-NULL");
            leftjoin = m.LeftJoin(nullset, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join
            Console.WriteLine("Join LHS-RHS");
            join = m.Join(n);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
           
            //Try a LeftOuterJoin
            Console.WriteLine("LeftJoin LHS-RHS");
            leftjoin = m.LeftJoin(n, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Produce
            Console.WriteLine("Product LHS-RHS");
            BaseMultiset product = m.Product(n);
            foreach (Set set in product.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Self
            Console.WriteLine("Product LHS-D");
            product = m.Product(d);
            foreach (Set set in product.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Union
            Console.WriteLine("Union LHS-RHS");
            BaseMultiset union = m.Union(n);
            foreach (Set set in union.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
        }
Пример #5
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return(context.OutputMultiset);
            }

            BaseMultiset initialInput, localOutput, results = null;

            //Determine whether the Pattern modifies the existing Input rather than joining to it
            bool modifies = (this._triplePatterns[pattern] is FilterPattern);
            bool extended = (pattern > 0 && this._triplePatterns[pattern - 1] is BindPattern);
            bool modified = (pattern > 0 && this._triplePatterns[pattern - 1] is FilterPattern);

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
            case 0:
                //Input is as given and Output is new empty multiset
                if (!modifies)
                {
                    initialInput = context.InputMultiset;
                }
                else
                {
                    //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input
                    //This takes care of FILTERs being out of scope
                    initialInput = new Multiset();
                }
                localOutput = new Multiset();
                break;

            case 1:
                //Input becomes current Output and Output is new empty multiset
                initialInput = context.OutputMultiset;
                localOutput  = new Multiset();
                break;

            default:
                if (!extended && !modified)
                {
                    //Input is join of previous input and output and Output is new empty multiset
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        initialInput = context.InputMultiset.Join(context.OutputMultiset);
                    }
                }
                else
                {
                    initialInput = context.OutputMultiset;
                }
                localOutput = new Multiset();
                break;
            }
            context.InputMultiset  = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp         = this._triplePatterns[pattern];
            int            resultsFound = 0;
            int            prevResults  = -1;

            if (temp is TriplePattern)
            {
                //Find the first Triple which matches the Pattern
                TriplePattern        tp = (TriplePattern)temp;
                IEnumerable <Triple> ts = tp.GetTriples(context);

                //In the case that we're lazily evaluating an optimisable ORDER BY then
                //we need to apply OrderBy()'s to our enumeration
                //This only applies to the 1st pattern
                if (pattern == 0)
                {
                    if (context.Query != null)
                    {
                        if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy)
                        {
                            IComparer <Triple> comparer = context.Query.OrderBy.GetComparer(tp);
                            if (comparer != null)
                            {
                                ts = ts.OrderBy(t => t, comparer);
                            }
                            else
                            {
                                //Can't get a comparer so can't optimise
                                this._requiredResults = -1;
                            }
                        }
                    }
                }

                foreach (Triple t in ts)
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        if (tp.IndexType == TripleIndexType.NoVariables)
                        {
                            localOutput            = new IdentityMultiset();
                            context.OutputMultiset = localOutput;
                        }
                        else
                        {
                            context.OutputMultiset.Add(tp.CreateResult(t));
                        }

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt && results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                return(results);
                            }
                            else if (halt)
                            {
                                if (results.Count == 0)
                                {
                                    //If recursing leads to no results then eliminate all outputs
                                    //Also reset to prevResults to -1
                                    resultsFound = 0;
                                    localOutput  = new Multiset();
                                    prevResults  = -1;
                                }
                                else if (prevResults > -1)
                                {
                                    if (results.Count == prevResults)
                                    {
                                        //If the amount of results found hasn't increased then this match does not
                                        //generate any further solutions further down the recursion so we can eliminate
                                        //this from the results
                                        localOutput.Remove(localOutput.SetIDs.Max());
                                    }
                                }
                                prevResults = results.Count;

                                //If we're supposed to halt but not reached the number of required results then continue
                                context.InputMultiset  = initialInput;
                                context.OutputMultiset = localOutput;
                            }
                            else
                            {
                                //Otherwise we need to keep going here
                                //So must reset our input and outputs before continuing
                                context.InputMultiset  = initialInput;
                                context.OutputMultiset = new Multiset();
                                resultsFound--;
                            }
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                            }
                            else
                            {
                                //Normal Join
                                results = context.InputMultiset.Join(context.OutputMultiset);
                            }

                            //If not reached required number of results continue
                            if (results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                context.OutputMultiset = results;
                                return(context.OutputMultiset);
                            }
                        }
                    }
                }
            }
            else if (temp is FilterPattern)
            {
                FilterPattern     filter     = (FilterPattern)temp;
                ISparqlExpression filterExpr = filter.Filter.Expression;

                if (filter.Variables.IsDisjoint(context.InputMultiset.Variables))
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Filter is Disjoint so determine whether it has any affect or not
                    if (filter.Variables.Any())
                    {
                        //Has Variables but disjoint from input => not in scope so gets ignored

                        //Do we recurse or not?
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            //Recurse and return
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);
                            return(results);
                        }
                        else
                        {
                            //We don't affect the input in any way so just return it
                            return(context.InputMultiset);
                        }
                    }
                    else
                    {
                        //No Variables so have to evaluate it to see if it gives true otherwise
                        try
                        {
                            if (filterExpr.EffectiveBooleanValue(context, 0))
                            {
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    //Recurse and return
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);
                                    return(results);
                                }
                                else
                                {
                                    //Last Pattern and we evaluate to true so can return the input as-is
                                    halt = true;
                                    return(context.InputMultiset);
                                }
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Evaluates to false so eliminates all solutions (use an empty Multiset)
                            return(new Multiset());
                        }
                    }
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Test each solution found so far against the Filter and eliminate those that evalute to false/error
                    foreach (int id in context.InputMultiset.SetIDs.ToList())
                    {
                        try
                        {
                            if (filterExpr.EffectiveBooleanValue(context, id))
                            {
                                //If evaluates to true then add to output
                                context.OutputMultiset.Add(context.InputMultiset[id]);
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Error means we ignore the solution
                        }
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        //We can never decide whether to recurse again at this point as we are not capable of deciding
                        //which solutions should be dumped (that is the job of an earlier pattern in the BGP)
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);

                        return(results);
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to filter
                        return(context.OutputMultiset);
                    }
                }
            }
            else if (temp is BindPattern)
            {
                BindPattern       bind     = (BindPattern)temp;
                ISparqlExpression bindExpr = bind.AssignExpression;
                String            bindVar  = bind.VariableName;

                if (context.InputMultiset.ContainsVariable(bindVar))
                {
                    throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query");
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Compute the Binding for every value
                    context.OutputMultiset.AddVariable(bindVar);
                    foreach (ISet s in context.InputMultiset.Sets)
                    {
                        ISet x = s.Copy();
                        try
                        {
                            INode val = bindExpr.Value(context, s.ID);
                            x.Add(bindVar, val);
                        }
                        catch (RdfQueryException)
                        {
                            //Equivalent to no assignment but the solution is preserved
                        }
                        context.OutputMultiset.Add(x);
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);
                        return(results);
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to extend
                        return(context.OutputMultiset);
                    }
                }
            }
            else
            {
                throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern");
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return(new NullMultiset());
            }
            else
            {
                //Generate the final output and return it
                if (!modifies)
                {
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        results = context.InputMultiset.Join(context.OutputMultiset);
                    }
                    context.OutputMultiset = results;
                }
                return(context.OutputMultiset);
            }
        }
Пример #6
0
        /// <summary>
        /// Evaluates the Ask Union
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;
            if (this._lhs is Extend || this._rhs is Extend) initialInput = new IdentityMultiset();

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context);
            context.CheckTimeout();

            if (lhsResult.IsEmpty)
            {
                //Only evaluate the RHS if the LHS was empty
                context.InputMultiset = initialInput;
                BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context);
                context.CheckTimeout();

                context.OutputMultiset = lhsResult.Union(rhsResult);
                context.CheckTimeout();

                context.InputMultiset = context.OutputMultiset;
            }
            else
            {
                context.OutputMultiset = lhsResult;
            }
            return context.OutputMultiset;
        }
Пример #7
0
        /// <summary>
        /// Evaluates the Union
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;
            if (this._lhs is Extend || this._rhs is Extend) initialInput = new IdentityMultiset();

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context);
            context.CheckTimeout();

            context.InputMultiset = initialInput;
            BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context);
            context.CheckTimeout();

            context.OutputMultiset = lhsResult.Union(rhsResult);
            context.CheckTimeout();

            context.InputMultiset = context.OutputMultiset;
            return context.OutputMultiset;
        }
Пример #8
0
        /// <summary>
        /// Evaluates the Lazy Union
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;
            if (this._lhs is Extend || this._rhs is Extend) initialInput = new IdentityMultiset();

            context.InputMultiset = initialInput;
            BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context);
            context.CheckTimeout();

            if (lhsResult.Count >= this._requiredResults || this._requiredResults == -1)
            {
                //Only evaluate the RHS if the LHS didn't yield sufficient results
                context.InputMultiset = initialInput;
                BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context);
                context.CheckTimeout();

                context.OutputMultiset = lhsResult.Union(rhsResult);
                context.CheckTimeout();

                context.InputMultiset = context.OutputMultiset;
            }
            else
            {
                context.OutputMultiset = lhsResult;
            }
            return context.OutputMultiset;
        }
Пример #9
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return context.OutputMultiset;
            }

            BaseMultiset initialInput, localOutput, results = null;

            //Determine whether the Pattern modifies the existing Input rather than joining to it
            bool modifies = (this._triplePatterns[pattern] is FilterPattern);
            bool extended = (pattern > 0 && this._triplePatterns[pattern-1] is BindPattern);
            bool modified = (pattern > 0 && this._triplePatterns[pattern-1] is FilterPattern);

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
                case 0:
                    //Input is as given and Output is new empty multiset
                    if (!modifies)
                    {
                        initialInput = context.InputMultiset;
                    }
                    else
                    {
                        //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input
                        //This takes care of FILTERs being out of scope
                        initialInput = new Multiset();
                    }
                    localOutput = new Multiset();
                    break;

                case 1:
                    //Input becomes current Output and Output is new empty multiset
                    initialInput = context.OutputMultiset;
                    localOutput = new Multiset();
                    break;

                default:
                    if (!extended && !modified)
                    {
                        //Input is join of previous input and output and Output is new empty multiset
                        if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                        {
                            //Disjoint so do a Product
                            initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                        }
                        else
                        {
                            //Normal Join
                            initialInput = context.InputMultiset.Join(context.OutputMultiset);
                        }
                    }
                    else
                    {
                        initialInput = context.OutputMultiset;
                    }
                    localOutput = new Multiset();
                    break;
            }
            context.InputMultiset = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp = this._triplePatterns[pattern];
            int resultsFound = 0;
            int prevResults = -1;

            if (temp is TriplePattern)
            {
                //Find the first Triple which matches the Pattern
                TriplePattern tp = (TriplePattern)temp;
                IEnumerable<Triple> ts = tp.GetTriples(context);

                //In the case that we're lazily evaluating an optimisable ORDER BY then
                //we need to apply OrderBy()'s to our enumeration
                //This only applies to the 1st pattern
                if (pattern == 0)
                {
                    if (context.Query != null)
                    {
                        if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy)
                        {
                            IComparer<Triple> comparer = context.Query.OrderBy.GetComparer(tp);
                            if (comparer != null)
                            {
                                ts = ts.OrderBy(t => t, comparer);
                            }
                            else
                            {
                                //Can't get a comparer so can't optimise
                                this._requiredResults = -1;
                            }
                        }
                    }
                }

                foreach (Triple t in ts)
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        if (tp.IndexType == TripleIndexType.NoVariables)
                        {
                            localOutput = new IdentityMultiset();
                            context.OutputMultiset = localOutput;
                        }
                        else
                        {
                            context.OutputMultiset.Add(tp.CreateResult(t));
                        }

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt && results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                return results;
                            }
                            else if (halt)
                            {
                                if (results.Count == 0)
                                {
                                    //If recursing leads to no results then eliminate all outputs
                                    //Also reset to prevResults to -1
                                    resultsFound = 0;
                                    localOutput = new Multiset();
                                    prevResults = -1;
                                }
                                else if (prevResults > -1)
                                {
                                    if (results.Count == prevResults)
                                    {
                                        //If the amount of results found hasn't increased then this match does not
                                        //generate any further solutions further down the recursion so we can eliminate
                                        //this from the results
                                        localOutput.Remove(localOutput.SetIDs.Max());
                                    }
                                }
                                prevResults = results.Count;

                                //If we're supposed to halt but not reached the number of required results then continue
                                context.InputMultiset = initialInput;
                                context.OutputMultiset = localOutput;
                            }
                            else
                            {
                                //Otherwise we need to keep going here
                                //So must reset our input and outputs before continuing
                                context.InputMultiset = initialInput;
                                context.OutputMultiset = new Multiset();
                                resultsFound--;
                            }
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                            }
                            else
                            {
                                //Normal Join
                                results = context.InputMultiset.Join(context.OutputMultiset);
                            }

                            //If not reached required number of results continue
                            if (results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                context.OutputMultiset = results;
                                return context.OutputMultiset;
                            }
                        }
                    }
                }
            }
            else if (temp is FilterPattern)
            {
                FilterPattern filter = (FilterPattern)temp;
                ISparqlExpression filterExpr = filter.Filter.Expression;

                if (filter.Variables.IsDisjoint(context.InputMultiset.Variables))
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Filter is Disjoint so determine whether it has any affect or not
                    if (filter.Variables.Any())
                    {
                        //Has Variables but disjoint from input => not in scope so gets ignored

                        //Do we recurse or not?
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            //Recurse and return
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);
                            return results;
                        }
                        else
                        {
                            //We don't affect the input in any way so just return it
                            return context.InputMultiset;
                        }
                    }
                    else
                    {
                        //No Variables so have to evaluate it to see if it gives true otherwise
                        try
                        {
                            if (filterExpr.Evaluate(context, 0).AsSafeBoolean())
                            {
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    //Recurse and return
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);
                                    return results;
                                }
                                else
                                {
                                    //Last Pattern and we evaluate to true so can return the input as-is
                                    halt = true;
                                    return context.InputMultiset;
                                }
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Evaluates to false so eliminates all solutions (use an empty Multiset)
                            return new Multiset();
                        }
                    }
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Test each solution found so far against the Filter and eliminate those that evalute to false/error
                    foreach (int id in context.InputMultiset.SetIDs.ToList())
                    {
                        try
                        {
                            if (filterExpr.Evaluate(context, id).AsSafeBoolean())
                            {
                                //If evaluates to true then add to output
                                context.OutputMultiset.Add(context.InputMultiset[id].Copy());
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Error means we ignore the solution
                        }
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        //We can never decide whether to recurse again at this point as we are not capable of deciding
                        //which solutions should be dumped (that is the job of an earlier pattern in the BGP)
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);

                        return results;
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to filter
                        return context.OutputMultiset;
                    }
                }
            }
            else if (temp is BindPattern)
            {
                BindPattern bind = (BindPattern)temp;
                ISparqlExpression bindExpr = bind.AssignExpression;
                String bindVar = bind.VariableName;

                if (context.InputMultiset.ContainsVariable(bindVar))
                {
                    throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query");
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Compute the Binding for every value
                    context.OutputMultiset.AddVariable(bindVar);
                    foreach (ISet s in context.InputMultiset.Sets)
                    {
                        ISet x = s.Copy();
                        try
                        {
                            INode val = bindExpr.Evaluate(context, s.ID);
                            x.Add(bindVar, val);
                        }
                        catch (RdfQueryException)
                        {
                            //Equivalent to no assignment but the solution is preserved
                        }
                        context.OutputMultiset.Add(x.Copy());
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);
                        return results;
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to extend
                        return context.OutputMultiset;
                    }
                }
            }
            else
            {
                throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern");
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return new NullMultiset();
            }
            else
            {
                //Generate the final output and return it
                if (!modifies)
                {
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        results = context.InputMultiset.Join(context.OutputMultiset);
                    }
                    context.OutputMultiset = results;
                }
                return context.OutputMultiset;
            }
        }