Пример #1
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;

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
            case 0:
                //Input is as given and Output is new empty multiset
                initialInput = context.InputMultiset;
                localOutput  = new Multiset();
                break;

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

            default:
                //Input is join of previous input and ouput and Output is new empty multiset
                if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                {
                    //Disjoint so do a Product
                    initialInput = context.InputMultiset.Product(context.OutputMultiset);
                }
                else
                {
                    //Normal Join
                    initialInput = context.InputMultiset.Join(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;

            if (temp.PatternType == TriplePatternType.Match)
            {
                //Find the first Triple which matches the Pattern
                IMatchTriplePattern tp = (IMatchTriplePattern)temp;
                foreach (Triple t in tp.GetTriples(context))
                {
                    //Remember to check for Timeout during lazy evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        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)
                            {
                                return(results);
                            }

                            //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
                                context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.QueryTimeout - context.QueryTime);
                            }
                            else
                            {
                                //Normal Join
                                context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                            }
                            return(context.OutputMultiset);
                        }
                    }
                }
            }
            else if (temp.PatternType == TriplePatternType.Filter)
            {
                IFilterPattern    fp     = (IFilterPattern)temp;
                ISparqlFilter     filter = fp.Filter;
                ISparqlExpression expr   = filter.Expression;

                //Find the first result of those we've got so far that matches
                if (context.InputMultiset is IdentityMultiset || context.InputMultiset.IsEmpty)
                {
                    try
                    {
                        //If the Input is the Identity Multiset then the Output is either
                        //the Identity/Null Multiset depending on whether the Expression evaluates to true
                        if (expr.Evaluate(context, 0).AsSafeBoolean())
                        {
                            context.OutputMultiset = new IdentityMultiset();
                        }
                        else
                        {
                            context.OutputMultiset = new NullMultiset();
                        }
                    }
                    catch
                    {
                        //If Expression fails to evaluate then result is NullMultiset
                        context.OutputMultiset = new NullMultiset();
                    }
                }
                else
                {
                    foreach (int id in context.InputMultiset.SetIDs)
                    {
                        //Remember to check for Timeout during lazy evaluation
                        context.CheckTimeout();

                        try
                        {
                            if (expr.Evaluate(context, id).AsSafeBoolean())
                            {
                                resultsFound++;
                                context.OutputMultiset.Add(context.InputMultiset[id].Copy());

                                //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)
                                    {
                                        return(results);
                                    }

                                    //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
                                        context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                                    }
                                    else
                                    {
                                        //Normal Join
                                        context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                                    }
                                    return(context.OutputMultiset);
                                }
                            }
                        }
                        catch
                        {
                            //Ignore expression evaluation errors
                        }
                    }
                }
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return(new NullMultiset());
            }

            //We should never reach here so throw an error to that effect
            //The reason we'll never reach here is that this method should always return earlier
            throw new RdfQueryException("Unexpected control flow in evaluating a Streamed BGP for an ASK query");
        }
Пример #2
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            // Remember to check for Timeouts during Lazy Evaluation
            context.CheckTimeout();

            halt = false;

            // Handle Empty BGPs
            if (pattern == 0 && _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 = (_triplePatterns[pattern].PatternType == TriplePatternType.Filter);
            bool extended = (pattern > 0 && _triplePatterns[pattern - 1].PatternType == TriplePatternType.BindAssignment);
            bool modified = (pattern > 0 && _triplePatterns[pattern - 1].PatternType == TriplePatternType.Filter);

            // 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         = _triplePatterns[pattern];
            int            resultsFound = 0;
            int            prevResults  = -1;

            if (temp.PatternType == TriplePatternType.Match)
            {
                // Find the first Triple which matches the Pattern
                IMatchTriplePattern  tp = (IMatchTriplePattern)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
                                // Thus required results is everything so just use normal evaluation as otherwise
                                // lazy evaluation will significantly impact performance and lead to an apparent infinite loop
                                return(base.Evaluate(context));
                            }
                        }
                    }
                }

                foreach (Triple t in ts)
                {
                    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 < _triplePatterns.Count - 1)
                {
                    results = StreamingEvaluate(context, pattern + 1, out halt);

                    // If recursion leads to a halt then we halt and return immediately
                    if (halt && results.Count >= _requiredResults && _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 >= _requiredResults && _requiredResults != -1)
                    {
                        context.OutputMultiset = results;
                        return(context.OutputMultiset);
                    }
                }
                context.InputMultiset = results;
            }
            else if (temp.PatternType == TriplePatternType.Filter)
            {
                IFilterPattern    filter     = (IFilterPattern)temp;
                ISparqlExpression filterExpr = filter.Filter.Expression;

                if (filter.Variables.IsDisjoint(context.InputMultiset.Variables))
                {
                    // 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 < _triplePatterns.Count - 1)
                        {
                            // Recurse and return
                            results = 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 < _triplePatterns.Count - 1)
                                {
                                    // Recurse and return
                                    results = 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
                {
                    // 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 < _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 = 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
                {
                    // 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 < _triplePatterns.Count - 1)
                    {
                        // Recurse then return
                        results = 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
            {
                // Remember to check for Timeouts during Lazy Evaluation
                context.CheckTimeout();

                // 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);
            }
        }