public void SparqlBgpEvaluation()
        {
            //Prepare the Store
            TripleStore store = new TripleStore();
            Graph g = new Graph();
            FileLoader.Load(g, "Turtle.ttl");
            store.Add(g);

            SparqlQueryParser parser = new SparqlQueryParser();
            SparqlQuery q = parser.ParseFromString(@"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * WHERE {?s ?p ?o . ?s rdfs:label ?label}");
            Object testResult = store.ExecuteQuery(q);

            ISparqlAlgebra testAlgebra = q.ToAlgebra();

            if (testResult is SparqlResultSet)
            {
                SparqlResultSet rset = (SparqlResultSet)testResult;
                Console.WriteLine(rset.Count + " Results");
                foreach (SparqlResult r in rset) 
                {
                    Console.WriteLine(r.ToString());
                }
                Console.WriteLine();
            }

            //Create some Triple Patterns
            TriplePattern t1 = new TriplePattern(new VariablePattern("?s"), new VariablePattern("?p"), new VariablePattern("?o"));
            TriplePattern t2 = new TriplePattern(new VariablePattern("?s"), new NodeMatchPattern(g.CreateUriNode("rdfs:label")), new VariablePattern("?label"));
            TriplePattern t3 = new TriplePattern(new VariablePattern("?x"), new VariablePattern("?y"), new VariablePattern("?z"));
            TriplePattern t4 = new TriplePattern(new VariablePattern("?s"), new NodeMatchPattern(g.CreateUriNode(":name")), new VariablePattern("?name"));

            //Build some BGPs
            Bgp selectNothing = new Bgp();
            Bgp selectAll = new Bgp(t1);
            Bgp selectLabelled = new Bgp(new List<ITriplePattern>() { t1, t2 });
            Bgp selectAllDisjoint = new Bgp(new List<ITriplePattern>() { t1, t3 });
            Bgp selectLabels = new Bgp(t2);
            Bgp selectNames = new Bgp(t4);
            //LeftJoin selectOptionalNamed = new LeftJoin(selectAll, new Optional(selectNames));
            LeftJoin selectOptionalNamed = new LeftJoin(selectAll, selectNames);
            Union selectAllUnion = new Union(selectAll, selectAll);
            Union selectAllUnion2 = new Union(selectAllUnion, selectAll);
            Filter selectAllUriObjects = new Filter(selectAll, new UnaryExpressionFilter(new IsUriFunction(new VariableExpressionTerm("o"))));

            //Test out the BGPs
            //Console.WriteLine("{}");
            //this.ShowMultiset(selectNothing.Evaluate(new SparqlEvaluationContext(null, store)));

            //Console.WriteLine("{?s ?p ?o}");
            //this.ShowMultiset(selectAll.Evaluate(new SparqlEvaluationContext(null, store)));

            //Console.WriteLine("{?s ?p ?o . ?s rdfs:label ?label}");
            //SparqlEvaluationContext context = new SparqlEvaluationContext(null, store);
            //this.ShowMultiset(selectLabelled.Evaluate(context));
            //SparqlResultSet lvnResult = new SparqlResultSet(context);

            //Console.WriteLine("{?s ?p ?o . ?x ?y ?z}");
            //this.ShowMultiset(selectAllDisjoint.Evaluate(new SparqlEvaluationContext(null, store)));

            //Console.WriteLine("{?s ?p ?o . OPTIONAL {?s :name ?name}}");
            //this.ShowMultiset(selectOptionalNamed.Evaluate(new SparqlEvaluationContext(null, store)));

            Console.WriteLine("{{?s ?p ?o} UNION {?s ?p ?o}}");
            this.ShowMultiset(selectAllUnion.Evaluate(new SparqlEvaluationContext(null, new InMemoryDataset(store))));

            Console.WriteLine("{{?s ?p ?o} UNION {?s ?p ?o} UNION {?s ?p ?o}}");
            this.ShowMultiset(selectAllUnion2.Evaluate(new SparqlEvaluationContext(null, new InMemoryDataset(store))));

            Console.WriteLine("{?s ?p ?o FILTER (ISURI(?o))}");
            this.ShowMultiset(selectAllUriObjects.Evaluate(new SparqlEvaluationContext(null, new InMemoryDataset(store))));
        }
Example #2
0
        /// <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] is TriplePattern))
                        {
                            //First ensure that if we've found any other Triple Patterns up to this point
                            //we dump this into a BGP and join with the result so far
                            if (patterns.Count > 0)
                            {
                                result = Join.CreateJoin(result, new Bgp(patterns));
                                patterns.Clear();
                            }

                            //Then generate the appropriate strict algebra operator
                            if (ps[i] is FilterPattern)
                            {
                                result = new Filter(result, ((FilterPattern)ps[i]).Filter);
                            }
                            else if (ps[i] is BindPattern)
                            {
                                BindPattern bind = (BindPattern)ps[i];
                                result = new Extend(result, bind.AssignExpression, bind.VariableName);
                            }
                            else if (ps[i] is LetPattern)
                            {
                                LetPattern let = (LetPattern)ps[i];
                                result = new Extend(result, let.AssignExpression, let.VariableName);
                            }
                            else if (ps[i] is SubQueryPattern)
                            {
                                SubQueryPattern sq = (SubQueryPattern)ps[i];
                                result = Join.CreateJoin(result, new SubQuery(sq.SubQuery));
                            }
                            else if (ps[i] is PropertyPathPattern)
                            {
                                PropertyPathPattern pp = (PropertyPathPattern)ps[i];
                                result = Join.CreateJoin(result, new PropertyPath(pp.Subject, pp.Path, pp.Object));
                            }
                        }
                        else
                        {
                            patterns.Add(ps[i]);
                        }
                    }

                    if (patterns.Count == current.PatternCount)
                    {
                        //If count of remaining patterns same as original pattern count there was no optimisation
                        //to do so return as is
                        return current;
                    }
                    else if (patterns.Count > 0)
                    {
                        //If any patterns left at end join as a BGP with result so far
                        result = Join.CreateJoin(result, new Bgp(patterns));
                        return result;
                    }
                    else
                    {
                        return result;
                    }
                }
            }
            else if (algebra is ITerminalOperator)
            {
                return algebra;
            }
            else
            {
                return algebra;
            }
        }
        /// <summary>
        /// Optimises BGPs in the Algebra to use Filter() and Extend() rather than the embedded FILTER and BIND
        /// </summary>
        /// <param name="algebra">Algebra to optimise</param>
        /// <returns></returns>
        public ISparqlAlgebra Optimise(ISparqlAlgebra algebra)
        {
            if (algebra is IAbstractJoin)
            {
                return ((IAbstractJoin)algebra).Transform(this);
            }
            else if (algebra is IUnaryOperator)
            {
                return ((IUnaryOperator)algebra).Transform(this);
            }
            else if (algebra is IBgp)
            {
                IBgp current = (IBgp)algebra;
                if (current.PatternCount == 0)
                {
                    return current;
                }
                else
                {
                    ISparqlAlgebra result = new Bgp();
                    List<ITriplePattern> patterns = new List<ITriplePattern>();
                    List<ITriplePattern> ps = new List<ITriplePattern>(current.TriplePatterns.ToList());
                    for (int i = 0; i < current.PatternCount; i++)
                    {
                        if (ps[i] is FilterPattern || ps[i] is BindPattern)
                        {
                            //First ensure that if we've found any other Triple Patterns up to this point
                            //we dump this into a BGP and join with the result so far
                            if (patterns.Count > 0)
                            {
                                result = Join.CreateJoin(result, new Bgp(patterns));
                                patterns.Clear();
                            }
                            if (ps[i] is FilterPattern)
                            {
                                result = new Filter(result, ((FilterPattern)ps[i]).Filter);
                            }
                            else
                            {
                                BindPattern bind = (BindPattern)ps[i];
                                result = new Extend(result, bind.AssignExpression, bind.VariableName);
                            }
                        }
                        else
                        {
                            patterns.Add(ps[i]);
                        }
                    }

                    if (patterns.Count == current.PatternCount)
                    {
                        //If count of remaining patterns same as original pattern count there was no optimisation
                        //to do so return as is
                        return current;
                    }
                    else if (patterns.Count > 0)
                    {
                        //If any patterns left at end join as a BGP with result so far
                        result = Join.CreateJoin(result, new Bgp(patterns));
                        return result;
                    }
                    else
                    {
                        return result;
                    }
                }
            }
            else if (algebra is ITerminalOperator)
            {
                return algebra;
            }
            else
            {
                return algebra;
            }
        }
        /// <summary>
        /// Runs the optimisation against a Filter algebra
        /// </summary>
        /// <param name="filter">The Filter algebra to optimise</param>
        /// <param name="optimisedAlgebra">Receives the optimised algebra if optimisation was performed or the input algebra otherwise</param>
        /// <returns>True if an optimisation was performed, false otherwise</returns>
        /// <remarks>
        /// <para>This implementation currently handles the simple case of a Filter applied to a BGP where the filter
        /// expression is either a single EqualsExpression or SameTermExpression or an AndExpression containing one or more
        /// EqualsExpression or SameTermExpression arguments. The implementation ensures that the replaced variable is still
        /// available to the outer algebra by inserting a BindPattern into the BGP. If the filter expression is a single 
        /// EqualsExpression or SameTermExpression, the optimiser will also strip this out of the algebra, but with an
        /// AndExpression it will leave the full filter expression untouched.</para>
        /// <para>The implementation will replace only URI and PlainLiteral types</para>
        /// TODO: It should be possible to remove EqualsExpression and SameTermExpression instances from the AndExpression arguments and then either strip it out (if it has no remaining arguments), or optimise it to a single expression (if it has one remaining argument)
        /// </remarks>
        private bool OptimiseFilter(IFilter filter, out ISparqlAlgebra optimisedAlgebra)
        {
            if (!(filter.InnerAlgebra is Bgp))
            {
                // Need a BGP to be able to insert BindPatterns for replaced variables
                optimisedAlgebra = filter;
                return false;
            }

            var filterExpression = filter.SparqlFilter.Expression;
            var replacementTerms = new Dictionary<string, INode>();
            string var;
            INode term;
            bool equals;
            
            // Currently only handle the simple filter cases of a single identity expression
            // or an AND of expressions
            if (IsIdentityExpression(filterExpression, out var, out term, out equals))
            {
                if (CanOptimize(term))
                {
                    replacementTerms.Add(var, term);
                }
            }
            else if (filterExpression is AndExpression)
            {
                foreach (var arg in filterExpression.Arguments)
                {
                    if (IsIdentityExpression(arg, out var, out term, out equals) && CanOptimize(term))
                    {
                            replacementTerms.Add(var, term);
                    }
                    else
                    {
                        foreach (var variable in arg.Variables) {
                            // Cannot guarantee that the argument doesn't imply some other possible binding for the variables
                            replacementTerms.Remove(variable);
                        }
                    }
                }
            }

            if (replacementTerms.Any())
            {
                var optimisedInner = filter.InnerAlgebra as Bgp;
                foreach (var replacementEntry in replacementTerms)
                {
                    try
                    {
                        // Replace the variable with a constant term wherever it appears and then add a Bind pattern
                        // to ensure that the variable is bound for use in the outer algebra
                        var t = new VariableSubstitutionTransformer(replacementEntry.Key, replacementEntry.Value);
                        optimisedInner = t.Optimise(optimisedInner) as Bgp;
                        optimisedInner =
                            new Bgp(
                                optimisedInner.TriplePatterns.Concat(new[]
                                {new BindPattern(replacementEntry.Key, new ConstantTerm(replacementEntry.Value))}));
                    }
                    catch (RdfQueryException)
                    {
                        // Could not perform this replacement.
                    }
                }
                if (filterExpression is AndExpression)
                {
                    // Keep the filter as it may contain other necessary expressions
                    // TODO: Could try to remove the identity expressions here ?
                    optimisedAlgebra = new Filter(optimisedInner, filter.SparqlFilter);
                }
                else
                {
                    // Can optimise away the filter entirely
                    optimisedAlgebra = optimisedInner;
                }
                return true;
            }
            optimisedAlgebra = filter;
            return false;
        }
        /// <summary>
        /// Converts the algebra back into a Graph Pattern.
        /// </summary>
        /// <returns></returns>
        public Patterns.GraphPattern ToGraphPattern()
        {
            ISparqlAlgebra algebra = new Filter(new Join(_lhs, _rhs), new UnaryExpressionFilter(_expr));

            return(algebra.ToGraphPattern());
        }
        /// <summary>
        /// Converts the algebra back into a query.
        /// </summary>
        /// <returns></returns>
        public SparqlQuery ToQuery()
        {
            ISparqlAlgebra algebra = new Filter(new Join(_lhs, _rhs), new UnaryExpressionFilter(_expr));

            return(algebra.ToQuery());
        }