예제 #1
0
        /// <summary>
        /// Causes the Graph Pattern to be optimised if it isn't already
        /// </summary>
        /// <param name="gp">Graph Pattern</param>
        /// <param name="variables">Variables that have occurred prior to this Pattern</param>
        public void Optimise(GraphPattern gp, IEnumerable <String> variables)
        {
            // Our Variables is initially only those in our Triple Patterns since
            // anything else is considered to be out of scope
            List <String> ourVariables = (from tp in gp.TriplePatterns
                                          from v in tp.Variables
                                          select v).Distinct().ToList();

            // Start by sorting the Triple Patterns in the list according to the ranking function
            gp.TriplePatterns.Sort(GetRankingComparer());

            // Apply reordering unless an optimiser has chosen to disable it
            if (ShouldReorder)
            {
                if (gp.TriplePatterns.Count > 0)
                {
                    // After we sort which gives us a rough optimisation we then may want to reorder
                    // based on the Variables that occurred previous to us OR if we're the Root Graph Pattern

                    if (!variables.Any())
                    {
                        // Optimise this Graph Pattern
                        // No previously occurring variables so must be the first Graph Pattern
                        if (gp.TriplePatterns.Count > 1)
                        {
                            HashSet <String> currVariables = new HashSet <String>();
                            gp.TriplePatterns[0].Variables.ForEach(v => currVariables.Add(v));
                            for (int i = 1; i < gp.TriplePatterns.Count - 1; i++)
                            {
                                if (currVariables.Count == 0)
                                {
                                    gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v));
                                    continue;
                                }
                                else if (currVariables.IsDisjoint(gp.TriplePatterns[i].Variables))
                                {
                                    TryReorderPatterns(gp, currVariables.ToList(), i + 1, i);
                                    gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v));
                                }
                                else
                                {
                                    gp.TriplePatterns[i].Variables.ForEach(v => currVariables.Add(v));
                                }
                            }
                        }
                    }
                    else
                    {
                        // Optimise this Graph Pattern based on previously occurring variables
                        if (gp.TriplePatterns.Count > 1 && !gp.TriplePatterns[0].Variables.Any(v => variables.Contains(v)) && variables.Intersect(ourVariables).Any())
                        {
                            TryReorderPatterns(gp, variables.ToList(), 1, 0);
                        }
                        else if (gp.TriplePatterns.Count > 2)
                        {
                            // In the case where there are more than 2 patterns then we can try and reorder these
                            // in order to further optimise the pattern
                            TryReorderPatterns(gp, gp.TriplePatterns[0].Variables, 2, 1);
                        }
                    }
                }
            }

            if (ShouldPlaceAssignments)
            {
                // First we need to place Assignments (LETs) in appropriate places within the Pattern
                // This happens before Filter placement since Filters may use variables assigned to in LETs
                if (gp.UnplacedAssignments.Any())
                {
                    // Need to ensure that we sort Assignments
                    // This way those that use fewer variables get placed first
                    List <IAssignmentPattern> ps = gp.UnplacedAssignments.OrderBy(x => x).ToList();

                    // This next bit goes in a do loop as we want to keep attempting to place assignments while
                    // we are able to do so.  If the count of unplaced assignments has decreased but is not
                    // zero it may be that we were unable to place some patterns as they relied on variables
                    // assigned in other LETs which weren't placed when we attempted to place them
                    // When we reach the point where no further placements have occurred or all assignments
                    // are placed we stop trying to place assignments
                    int c;
                    do
                    {
                        c = ps.Count;

                        int i = 0;
                        while (i < ps.Count)
                        {
                            if (TryPlaceAssignment(gp, ps[i]))
                            {
                                // Remove from Unplaced Assignments since it's been successfully placed in the Triple Patterns
                                // Don't increment the counter since the next Assignment is now at the index we're already at
                                ps.RemoveAt(i);
                            }
                            else
                            {
                                // Unable to place so increment counter
                                i++;
                            }
                        }
                    } while (c > ps.Count && ps.Count > 0);
                }
            }

            // Regardless of what we've placed already we now place all remaining assignments
            // foreach (IAssignmentPattern assignment in gp.UnplacedAssignments.ToList())
            // {
            //    gp.InsertAssignment(assignment, gp.TriplePatterns.Count);
            // }


            if (ShouldPlaceFilters)
            {
                // Then we need to place the Filters in appropriate places within the Pattern
                if (gp.UnplacedFilters.Any())
                {
                    if (gp.TriplePatterns.Count == 0)
                    {
                        // Where there are no Triple Patterns the Graph Pattern just contains this Filter and possibly some
                        // child Graph Patterns.  In such a case then we shouldn't place the Filters
                    }
                    else
                    {
                        if (ShouldSplitFilters)
                        {
                            // See whether we can split any/all of the Unplaced Filters
                            List <ISparqlFilter> fs = gp.UnplacedFilters.ToList();
                            for (int i = 0; i < fs.Count; i++)
                            {
                                ISparqlFilter f = fs[i];
                                if (f.Expression is AndExpression)
                                {
                                    // Split the And
                                    // Note that multiple nested And's are handled by the fact that we will continue working through the list until it is finished
                                    UnaryExpressionFilter lhs = new UnaryExpressionFilter(f.Expression.Arguments.First());
                                    UnaryExpressionFilter rhs = new UnaryExpressionFilter(f.Expression.Arguments.Last());
                                    fs.RemoveAt(i);
                                    fs.Add(lhs);
                                    fs.Add(rhs);
                                }
                            }
                            // Finally we need to ensure the Unplaced Filters list is appropriately updated
                            gp.ResetFilters(fs);
                        }

                        foreach (ISparqlFilter f in gp.UnplacedFilters.ToList())
                        {
                            TryPlaceFilter(gp, f);
                        }
                    }
                }
            }

            // Finally optimise the Child Graph Patterns
            foreach (GraphPattern cgp in gp.ChildGraphPatterns)
            {
                // At each point the variables that have occurred are those in the Triple Patterns and
                // those in previous Graph Patterns
                cgp.Optimise(this, ourVariables);
                ourVariables.AddRange(cgp.Variables);
            }

            // Note: Any remaining Unplaced Filters/Assignments are OK since the ToAlgebra() method of a GraphPattern
            // will take care of placing these appropriately
        }
예제 #2
0
        /// <summary>
        /// Evaluates the filtered product
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;
            BaseMultiset lhsResults   = context.Evaluate(this._lhs);

            if (lhsResults is NullMultiset || lhsResults.IsEmpty)
            {
                //If LHS Results are Null/Empty then end result will always be null so short circuit
                context.OutputMultiset = new NullMultiset();
            }
            else
            {
                context.InputMultiset = initialInput;
                BaseMultiset rhsResults = context.Evaluate(this._rhs);
                if (rhsResults is NullMultiset || rhsResults.IsEmpty)
                {
                    //If RHS Results are Null/Empty then end results will always be null so short circuit
                    context.OutputMultiset = new NullMultiset();
                }
                else if (rhsResults is IdentityMultiset)
                {
                    //Apply Filter over LHS Results only - defer evaluation to filter implementation
                    context.InputMultiset = lhsResults;
                    UnaryExpressionFilter filter = new UnaryExpressionFilter(this._expr);
                    filter.Evaluate(context);
                    context.OutputMultiset = lhsResults;
                }
                else
                {
                    //Calculate the product applying the filter as we go
#if NET40 && !SILVERLIGHT
                    if (Options.UsePLinqEvaluation && this._expr.CanParallelise)
                    {
                        PartitionedMultiset partitionedSet;
                        SparqlResultBinder  binder = context.Binder;
                        if (lhsResults.Count >= rhsResults.Count)
                        {
                            partitionedSet = new PartitionedMultiset(lhsResults.Count, rhsResults.Count);
                            context.Binder = new LeviathanLeftJoinBinder(partitionedSet);
                            lhsResults.Sets.AsParallel().ForAll(x => this.EvalFilteredProduct(context, x, rhsResults, partitionedSet));
                        }
                        else
                        {
                            partitionedSet = new PartitionedMultiset(rhsResults.Count, lhsResults.Count);
                            context.Binder = new LeviathanLeftJoinBinder(partitionedSet);
                            rhsResults.Sets.AsParallel().ForAll(y => this.EvalFilteredProduct(context, y, lhsResults, partitionedSet));
                        }

                        context.Binder         = binder;
                        context.OutputMultiset = partitionedSet;
                    }
                    else
                    {
#endif
                    BaseMultiset productSet   = new Multiset();
                    SparqlResultBinder binder = context.Binder;
                    context.Binder = new LeviathanLeftJoinBinder(productSet);
                    foreach (ISet x in lhsResults.Sets)
                    {
                        foreach (ISet y in rhsResults.Sets)
                        {
                            ISet z = x.Join(y);
                            productSet.Add(z);
                            try
                            {
                                if (!this._expr.Evaluate(context, z.ID).AsSafeBoolean())
                                {
                                    //Means the expression evaluates to false so we discard the solution
                                    productSet.Remove(z.ID);
                                }
                            }
                            catch
                            {
                                //Means this solution does not meet the FILTER and can be discarded
                                productSet.Remove(z.ID);
                            }
                        }
                        //Remember to check for timeouts occassionaly
                        context.CheckTimeout();
                    }
                    context.Binder         = binder;
                    context.OutputMultiset = productSet;
#if NET40 && !SILVERLIGHT
                }
#endif
                }
            }
            return(context.OutputMultiset);
        }