Beispiel #1
0
        public void SparqlAlgebraVariableClassification1()
        {
            TriplePattern tp  = MakeTriplePattern(this._s, this._p, this._o);
            IBgp          bgp = new Bgp(tp);

            this.TestClassification(bgp, this._emptyList, this._emptyList);
        }
Beispiel #2
0
        public void SparqlAlgebraVariableClassification3()
        {
            TriplePattern tp  = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._rdfType, this._factory.CreateVariableNode("type"));
            IBgp          lhs = new Bgp(tp);

            this.TestClassification(lhs, new String[] { "s", "type" }, this._emptyList);

            tp = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._factory.CreateVariableNode("p"), this._factory.CreateVariableNode("o"));
            IBgp rhs = new Bgp(tp);

            this.TestClassification(rhs, new String[] { "s", "p", "o" }, this._emptyList);

            // In a join everything should end up fixed since everything started as fixed
            IJoin join = new Join(lhs, rhs);

            this.TestClassification(join, new String[] { "s", "type", "p", "o" }, this._emptyList);

            // In the left join only the LHS variables should be fixed, others should be floating
            ILeftJoin leftJoin = new LeftJoin(lhs, rhs);

            this.TestClassification(leftJoin, new String[] { "s", "type" }, new String[] { "p", "o" });
            leftJoin = new LeftJoin(rhs, lhs);
            this.TestClassification(leftJoin, new String[] { "s", "p", "o" }, new String[] { "type" });

            // In the union only fixed variables on both sides are fixed, others should be floating
            IUnion union = new Union(lhs, rhs);

            this.TestClassification(union, new String[] { "s" }, new String[] { "p", "o", "type" });
        }
Beispiel #3
0
        public void SparqlAlgebraVariableClassification2()
        {
            TriplePattern tp  = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._p, this._o);
            IBgp          bgp = new Bgp(tp);

            this.TestClassification(bgp, new String[] { "s" }, this._emptyList);
        }
        /// <summary>
        /// Determines the starting points for Path evaluation
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <param name="paths">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        protected void GetPathStarts(SparqlEvaluationContext context, List <List <INode> > paths, bool reverse)
        {
            HashSet <KeyValuePair <INode, INode> > nodes = new HashSet <KeyValuePair <INode, INode> >();

            if (this.Path is Property)
            {
                INode predicate = ((Property)this.Path).Predicate;
                foreach (Triple t in context.Data.GetTriplesWithPredicate(predicate))
                {
                    if (reverse)
                    {
                        nodes.Add(new KeyValuePair <INode, INode>(t.Object, t.Subject));
                    }
                    else
                    {
                        nodes.Add(new KeyValuePair <INode, INode>(t.Subject, t.Object));
                    }
                }
            }
            else
            {
                BaseMultiset initialInput = context.InputMultiset;
                context.InputMultiset = new IdentityMultiset();
                VariablePattern x   = new VariablePattern("?x");
                VariablePattern y   = new VariablePattern("?y");
                Bgp             bgp = new Bgp(new PropertyPathPattern(x, this.Path, y));

                BaseMultiset results = context.Evaluate(bgp); //bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (ISet s in results.Sets)
                    {
                        if (s["x"] != null && s["y"] != null)
                        {
                            if (reverse)
                            {
                                nodes.Add(new KeyValuePair <INode, INode>(s["y"], s["x"]));
                            }
                            else
                            {
                                nodes.Add(new KeyValuePair <INode, INode>(s["x"], s["y"]));
                            }
                        }
                    }
                }
            }

            paths.AddRange(nodes.Select(kvp => new List <INode>(new INode[] { kvp.Key, kvp.Value })));
        }
Beispiel #5
0
        public void SparqlAlgebraVariableClassification4()
        {
            TriplePattern tp  = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._rdfType, this._factory.CreateVariableNode("type"));
            IBgp          lhs = new Bgp(tp);

            tp = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._factory.CreateVariableNode("p"), this._factory.CreateVariableNode("o"));
            IBgp rhs = new Bgp(tp);

            // In the left join only the LHS variables should be fixed, others should be floating
            ILeftJoin leftJoin = new LeftJoin(lhs, rhs);

            this.TestClassification(leftJoin, new String[] { "s", "type" }, new String[] { "p", "o" });

            tp = MakeTriplePattern(this._factory.CreateVariableNode("s"), this._factory.CreateUriNode(new Uri(NamespaceMapper.RDFS + "label")), this._factory.CreateVariableNode("label"));
            Bgp top = new Bgp(tp);

            // Everything in the RHS not fixed on the LHS is floating
            ILeftJoin parentJoin = new LeftJoin(top, leftJoin);

            this.TestClassification(parentJoin, new String[] { "s", "label" }, new String[] { "p", "o", "type" });

            parentJoin = new LeftJoin(leftJoin, top);
            this.TestClassification(parentJoin, new String[] { "s", "type" }, new String[] { "p", "o", "label" });
        }
        public void SparqlStreamingBgpSelectEvaluation()
        {
            //Get the Data we want to query
            TripleStore store = new TripleStore();
            Graph g = new Graph();
            FileLoader.Load(g, "InferenceTest.ttl");
            store.Add(g);
            //g = new Graph();
            //FileLoader.Load(g, "noise.ttl");
            //store.Add(g);

            Console.WriteLine(store.Triples.Count() + " Triples in Store");

            //Create the Triple Pattern we want to query with
            IUriNode fordFiesta = g.CreateUriNode(new Uri("http://example.org/vehicles/FordFiesta"));
            IUriNode rdfType = g.CreateUriNode(new Uri(RdfSpecsHelper.RdfType));
            IUriNode rdfsLabel = g.CreateUriNode(new Uri(NamespaceMapper.RDFS + "label"));
            IUriNode speed = g.CreateUriNode(new Uri("http://example.org/vehicles/Speed"));
            IUriNode carClass = g.CreateUriNode(new Uri("http://example.org/vehicles/Car"));

            TriplePattern allTriples = new TriplePattern(new VariablePattern("?s"), new VariablePattern("?p"), new VariablePattern("?o"));
            TriplePattern allTriples2 = new TriplePattern(new VariablePattern("?x"), new VariablePattern("?y"), new VariablePattern("?z"));
            TriplePattern tp1 = new TriplePattern(new VariablePattern("?s"), new NodeMatchPattern(rdfType), new NodeMatchPattern(carClass));
            TriplePattern tp2 = new TriplePattern(new VariablePattern("?s"), new NodeMatchPattern(speed), new VariablePattern("?speed"));
            TriplePattern tp3 = new TriplePattern(new VariablePattern("?s"), new NodeMatchPattern(rdfsLabel), new VariablePattern("?label"));
            TriplePattern novars = new TriplePattern(new NodeMatchPattern(fordFiesta), new NodeMatchPattern(rdfType), new NodeMatchPattern(carClass));
            TriplePattern novars2 = new TriplePattern(new NodeMatchPattern(fordFiesta), new NodeMatchPattern(rdfsLabel), new NodeMatchPattern(carClass));
            FilterPattern blankSubject = new FilterPattern(new UnaryExpressionFilter(new IsBlankFunction(new VariableExpressionTerm("?s"))));
            List<List<ITriplePattern>> tests = new List<List<ITriplePattern>>()
            {
                new List<ITriplePattern>() { },
                new List<ITriplePattern>() { allTriples },
                new List<ITriplePattern>() { allTriples, allTriples2 },
                new List<ITriplePattern>() { tp1 },
                new List<ITriplePattern>() { tp1, tp2 },
                new List<ITriplePattern>() { tp1, tp3 },
                new List<ITriplePattern>() { novars },
                new List<ITriplePattern>() { novars, tp1 },
                new List<ITriplePattern>() { novars, tp1, tp2 },
                new List<ITriplePattern>() { novars2 },
                new List<ITriplePattern>() { tp1, blankSubject }
            };

            foreach (List<ITriplePattern> tps in tests)
            {
                Console.WriteLine(tps.Count + " Triple Patterns in the Query");
                foreach (ITriplePattern tp in tps)
                {
                    Console.WriteLine(tp.ToString());
                }
                Console.WriteLine();

                ISparqlAlgebra select = new Bgp(tps);
                ISparqlAlgebra selectOptimised = new LazyBgp(tps, 10);

                //Evaluate with timings
                Stopwatch timer = new Stopwatch();
                TimeSpan unopt, opt;
                timer.Start();
                BaseMultiset results1 = select.Evaluate(new SparqlEvaluationContext(null, new InMemoryDataset(store)));
                timer.Stop();
                unopt = timer.Elapsed;
                timer.Reset();
                timer.Start();
                BaseMultiset results2 = selectOptimised.Evaluate(new SparqlEvaluationContext(null, new InMemoryDataset(store)));
                timer.Stop();
                opt = timer.Elapsed;

                Console.WriteLine("SELECT = " + results1.GetType().ToString() + " (" + results1.Count + " Results) in " + unopt.ToString());
                Console.WriteLine("SELECT Optimised = " + results2.GetType().ToString() + " (" + results2.Count + " Results) in " + opt.ToString());

                Console.WriteLine();
                Console.WriteLine("Optimised Results");
                foreach (Set s in results2.Sets)
                {
                    Console.WriteLine(s.ToString());
                }

                Assert.IsTrue(results1.Count >= results2.Count, "Optimised Select should have produced as many/fewer results than Unoptimised Select");

                Console.WriteLine();
            }
        }
        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))));
        }
Beispiel #8
0
 /// <summary>
 /// Evaluates the Triple Pattern in the given Context
 /// </summary>
 /// <param name="context">Context</param>
 /// <remarks>
 /// <para>
 /// Since a <see cref="FullTextPattern">FullTextPattern</see> on its own does not know how to execute itself as it would need a <see cref="VDS.RDF.Query.FullText.Search.IFullTextSearchProvider">IFullTextSearchProvider</see> it simply creates a BGP from the original patterns and they are evaluated as simple triple matches
 /// </para>
 /// </remarks>
 public override void Evaluate(SparqlEvaluationContext context)
 {
     Bgp bgp = new Bgp(this._origPatterns);
     context.Evaluate(bgp);
 }
        /// <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;
            }
        }
Beispiel #10
0
        /// <summary>
        /// Optimises the Algebra so that BGPs containing relevant patterns are converted to use the <see cref="FullTextMatch">FullTextMatch</see> operator
        /// </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<FullTextPattern> fps = FullTextHelper.ExtractPatterns(current.TriplePatterns);
                    if (fps.Count == 0) return algebra;
                    List<ITriplePattern> ps = current.TriplePatterns.ToList();

                    //First we want to find where each FullTextPattern is located in the original triple patterns
                    Dictionary<int, int> locations = new Dictionary<int, int>();
                    for (int i = 0; i < fps.Count; i++)
                    {
                        locations.Add(i, -1);
                        ITriplePattern first = fps[i].OriginalPatterns.First();
                        for (int j = 0; j < ps.Count; j++)
                        {
                            if (first.Equals(ps[j]))
                            {
                                locations[i] = j;
                                break;
                            }
                        }
                        //If we fail to locate this we've failed to optimise here so must abort
                        if (locations[i] == -1) return algebra;
                    }

                    //Knowing this we can then start splitting the BGP into several BGPs
                    int locBase = 0;
                    foreach (int i in Enumerable.Range(0, fps.Count).OrderBy(x => locations[x]).ToList())
                    {
                        //Wrap everything up to that point in a BGP excluding any patterns relevant to any FullTextPattern
                        result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Take(locations[i]).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp)))));
                        locBase = locations[i] + 1;
                        //Then apply the FullTextMatch operator over it
                        FullTextPattern ftp = fps[i];
                        result = new FullTextMatch(this._provider, result, ftp.MatchVariable, ftp.ScoreVariable, ftp.SearchTerm, ftp.Limit, ftp.ScoreThreshold);
                    }

                    //If there are any patterns left over remember to include them
                    if (locBase < ps.Count)
                    {
                        result = Join.CreateJoin(result, new Bgp(ps.Skip(locBase).Where(tp => !(tp is TriplePattern) || !fps.Any(fp => fp.OriginalPatterns.Contains((TriplePattern)tp)))));
                    }
                    return result;

                    //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 TriplePattern))
                    //    {
                    //        patterns.Add(ps[i]);
                    //    }
                    //    else
                    //    {
                    //        //Check to see if the Predicate of the Pattern match the Full Text Match Predicate URI
                    //        TriplePattern tp = (TriplePattern)ps[i];
                    //        PatternItem pred = tp.Predicate;
                    //        if (pred is NodeMatchPattern)
                    //        {
                    //            INode predNode = ((NodeMatchPattern)pred).Node;
                    //            if (predNode.NodeType == NodeType.Uri)
                    //            {
                    //                String predUri = ((IUriNode)predNode).Uri.ToString();
                    //                if (predUri.Equals(FullTextHelper.FullTextMatchPredicateUri))
                    //                {
                    //                    if (patterns.Count > 0) result = Join.CreateJoin(result, new Bgp(patterns));
                    //                    result = new FullTextMatch(this._provider, result, tp.Subject, tp.Object);
                    //                    patterns.Clear();
                    //                }
                    //                else
                    //                {
                    //                    patterns.Add(ps[i]);
                    //                }
                    //            }
                    //            else
                    //            {
                    //                patterns.Add(ps[i]);
                    //            }
                    //        }
                    //        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>
        /// Determines the starting points for Path evaluation
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <param name="paths">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        protected void GetPathStarts(SparqlEvaluationContext context, List<List<INode>> paths, bool reverse)
        {
            HashSet<KeyValuePair<INode, INode>> nodes = new HashSet<KeyValuePair<INode, INode>>();
            if (this.Path is Property)
            {
                INode predicate = ((Property)this.Path).Predicate;
                foreach (Triple t in context.Data.GetTriplesWithPredicate(predicate))
                {
                    if (reverse)
                    {
                        nodes.Add(new KeyValuePair<INode, INode>(t.Object, t.Subject));
                    }
                    else
                    {
                        nodes.Add(new KeyValuePair<INode, INode>(t.Subject, t.Object));
                    }
                }
            }
            else
            {
                BaseMultiset initialInput = context.InputMultiset;
                context.InputMultiset = new IdentityMultiset();
                VariablePattern x = new VariablePattern("?x");
                VariablePattern y = new VariablePattern("?y");
                Bgp bgp = new Bgp(new PropertyPathPattern(x, this.Path, y));

                BaseMultiset results = context.Evaluate(bgp);//bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (Set s in results.Sets)
                    {
                        if (s["x"] != null && s["y"] != null)
                        {
                            if (reverse)
                            {
                                nodes.Add(new KeyValuePair<INode, INode>(s["y"], s["x"]));
                            }
                            else
                            {
                                nodes.Add(new KeyValuePair<INode, INode>(s["x"], s["y"]));
                            }
                        }
                    }
                }
            }

            paths.AddRange(nodes.Select(kvp => new List<INode>(new INode[] { kvp.Key, kvp.Value })));
        }
Beispiel #13
0
        /// <summary>
        /// Gets the Algebra representation of the Graph Pattern
        /// </summary>
        /// <returns></returns>
        public ISparqlAlgebra ToAlgebra()
        {
            if (this._isUnion)
            {
                //If this Graph Pattern represents a UNION of Graph Patterns turn into a series of UNIONs
                ISparqlAlgebra union = new Union(this._graphPatterns[0].ToAlgebra(), this._graphPatterns[1].ToAlgebra());
                if (this._graphPatterns.Count > 2)
                {
                    for (int i = 2; i < this._graphPatterns.Count; i++)
                    {
                        union = new Union(union, this._graphPatterns[i].ToAlgebra());
                    }
                }
                //If there's a FILTER apply it over the Union
                if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0))
                {
                    return new Filter(union, this.Filter);
                }
                else
                {
                    return union;
                }
            }
            else if (this._graphPatterns.Count == 0)
            {
                //If there are no Child Graph Patterns then this is a BGP
                ISparqlAlgebra bgp = new Bgp(this._triplePatterns);
                if (this._unplacedAssignments.Count > 0)
                {
                    //If we have any unplaced LETs these get Joined onto the BGP
                    bgp = Join.CreateJoin(bgp, new Bgp(this._unplacedAssignments));
                }
                if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0))
                {
                    if (this._isOptional && !(this._isExists || this._isNotExists))
                    {
                        //If we contain an unplaced FILTER and we're an OPTIONAL then the FILTER
                        //applies over the LEFT JOIN and will have been added elsewhere in the Algebra transform
                        return bgp;
                    }
                    else
                    {
                        ISparqlAlgebra complex = bgp;

                        //If we contain an unplaced FILTER and we're not an OPTIONAL the FILTER
                        //applies here
                        return new Filter(bgp, this.Filter);
                    }
                }
                else
                {
                    //We're not filtered (or all FILTERs were placed in the BGP) so we're just a BGP
                    return bgp;
                }
            }
            else
            {
                //Create a basic BGP to start with
                ISparqlAlgebra complex = new Bgp();
                if (this._triplePatterns.Count > 0)
                {
                    complex = new Bgp(this._triplePatterns);
                }

                //Then Join each of the Graph Patterns as appropriate
                foreach (GraphPattern gp in this._graphPatterns)
                {
                    if (gp.IsGraph)
                    {
                        //A GRAPH clause means a Join of the current pattern to a Graph clause
                        complex = Join.CreateJoin(complex, new Algebra.Graph(gp.ToAlgebra(), gp.GraphSpecifier));
                    }
                    else if (gp.IsOptional)
                    {
                        if (gp.IsExists || gp.IsNotExists)
                        {
                            //An EXISTS/NOT EXISTS means an Exists Join of the current pattern to the EXISTS/NOT EXISTS clause
                            complex = new ExistsJoin(complex, gp.ToAlgebra(), gp.IsExists);
                        }
                        else
                        {
                            //An OPTIONAL means a Left Join of the current pattern to the OPTIONAL clause
                            //with a possible FILTER applied over the LeftJoin
                            if (gp.IsFiltered && gp.Filter != null)
                            {
                                //If the OPTIONAL clause has an unplaced FILTER it applies over the Left Join
                                complex = new LeftJoin(complex, gp.ToAlgebra(), gp.Filter);
                            }
                            else
                            {
                                complex = new LeftJoin(complex, gp.ToAlgebra());
                            }
                        }
                    }
                    else if (gp.IsMinus)
                    {
                        //Always introduce a Minus here even if the Minus is disjoint since during evaluation we'll choose
                        //not to execute it if it's disjoint
                        complex = new Minus(complex, gp.ToAlgebra());
                    }
                    else if (gp.IsService)
                    {
                        complex = Join.CreateJoin(complex, new Service(gp.GraphSpecifier, gp, gp.IsSilent));
                    }
                    else
                    {
                        //Otherwise we just join the pattern to the existing pattern
                        complex = Join.CreateJoin(complex, gp.ToAlgebra());
                    }
                }
                if (this._unplacedAssignments.Count > 0)
                {
                    //Unplaced assignments get Joined as a BGP here
                    complex = Join.CreateJoin(complex, new Bgp(this._unplacedAssignments));
                }
                if (this._isFiltered && (this._filter != null || this._unplacedFilters.Count > 0))
                {
                    if (this._isOptional && !(this._isExists || this._isNotExists))
                    {
                        //If there's an unplaced FILTER and we're an OPTIONAL then the FILTER will
                        //apply over the LeftJoin and is applied elsewhere in the Algebra transform
                        return complex;
                    }
                    else
                    {
                        if (this._filter != null || this._unplacedFilters.Count > 0)
                        {
                            //If there's an unplaced FILTER and we're not an OPTIONAL pattern we apply
                            //the FILTER here
                            return new Filter(complex, this.Filter);
                        }
                        else
                        {
                            return complex;
                        }
                    }
                }
                else
                {
                    //If no FILTER just return the transform
                    return complex;
                }
            }
        }
Beispiel #14
0
        /// <summary>
        /// Converts the Query into it's SPARQL Algebra representation (as represented in the Leviathan API)
        /// </summary>
        /// <returns></returns>
        public ISparqlAlgebra ToAlgebra()
        {
            //Firstly Transform the Root Graph Pattern to SPARQL Algebra
            ISparqlAlgebra pattern;
            if (this._rootGraphPattern != null)
            {
                if (Options.AlgebraOptimisation)
                {
                    //If using Algebra Optimisation may use a special algebra in some cases
                    switch (this.SpecialType)
                    {
                        case SparqlSpecialQueryType.DistinctGraphs:
                            pattern = new SelectDistinctGraphs(this.Variables.First(v => v.IsResultVariable).Name);
                            break;
                        case SparqlSpecialQueryType.AskAnyTriples:
                            pattern = new AskAnyTriples();
                            break;
                        case SparqlSpecialQueryType.NotApplicable:
                        default:
                            //If not just use the standard transform
                            pattern = this._rootGraphPattern.ToAlgebra();
                            break;
                    }
                }
                else
                {
                    //If not using Algebra Optimisation just use the standard transform
                    pattern = this._rootGraphPattern.ToAlgebra();
                }
            }
            else
            {
                pattern = new Bgp();
            }

            //If we have a BINDINGS clause then we'll add it into the algebra here
            if (this._bindings != null)
            {
                pattern = new Bindings(this._bindings, pattern);
            }

            //Then we apply any optimisers followed by relevant solution modifiers
            switch (this._type)
            {
                case SparqlQueryType.Ask:
                    //Apply Algebra Optimisation is enabled
                    if (Options.AlgebraOptimisation)
                    {
                        pattern = this.ApplyAlgebraOptimisations(pattern);
                    }
                    return new Ask(pattern);

                case SparqlQueryType.Construct:
                case SparqlQueryType.Describe:
                case SparqlQueryType.DescribeAll:
                case SparqlQueryType.Select:
                case SparqlQueryType.SelectAll:
                case SparqlQueryType.SelectAllDistinct:
                case SparqlQueryType.SelectAllReduced:
                case SparqlQueryType.SelectDistinct:
                case SparqlQueryType.SelectReduced:
                    //Apply Algebra Optimisation if enabled
                    if (Options.AlgebraOptimisation)
                    {
                        pattern = this.ApplyAlgebraOptimisations(pattern);
                    }
                    
                    //GROUP BY is the first thing applied
                    if (this._groupBy != null) pattern = new GroupBy(pattern, this._groupBy);

                    //After grouping we do projection
                    //This will generate the values for any Project Expressions and Aggregates
                    pattern = new Project(pattern, this.Variables);

                    //Add HAVING clause after the projection
                    if (this._having != null) pattern = new Having(pattern, this._having);

                    //We can then Order our results
                    //We do ordering before we do Select but after Project so we can order by any of
                    //the project expressions/aggregates and any variable in the results even if
                    //it won't be output as a result variable
                    if (this._orderBy != null) pattern = new OrderBy(pattern, this._orderBy);

                    //After Ordering we apply Select
                    //Select effectively trims the results so only result variables are left
                    //This doesn't apply to CONSTRUCT since any variable may be used in the Construct Template
                    //so we don't want to eliminate anything
                    if (this._type != SparqlQueryType.Construct) pattern = new Select(pattern, this.Variables);

                    //If we have a Distinct/Reduced then we'll apply those after Selection
                    if (this._type == SparqlQueryType.SelectAllDistinct || this._type == SparqlQueryType.SelectDistinct)
                    {
                        pattern = new Distinct(pattern);
                    }
                    else if (this._type == SparqlQueryType.SelectAllReduced || this._type == SparqlQueryType.SelectReduced)
                    {
                        pattern = new Reduced(pattern);
                    }

                    //Finally we can apply any limit and/or offset
                    if (this._limit >= 0 || this._offset > 0)
                    {
                        pattern = new Slice(pattern, this._limit, this._offset);
                    }

                    return pattern;

                default:
                    throw new RdfQueryException("Unable to convert unknown Query Types to SPARQL 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;
        }
 private bool OptimiseBgp(Bgp bgp, out ISparqlAlgebra optimisedAlgebra)
 {
     if (bgp.TriplePatterns.OfType<FilterPattern>().Count() == 1)
     {
         var filter = bgp.TriplePatterns.OfType<FilterPattern>().Select(fp => fp.Filter).First();
         string var;
         INode term;
         bool equals;
         if (IsIdentityExpression(filter.Expression, out var, out term, out @equals))
         {
             if (@equals)
             {
                 var triplePatterns = new List<ITriplePattern>();
                 foreach (var tp in bgp.TriplePatterns)
                 {
                     if (tp is FilterPattern) continue;
                     if (tp is TriplePattern)
                     {
                         var triplePattern = (TriplePattern) tp;
                         if (triplePattern.Variables.Contains(var))
                         {
                             PatternItem subjPattern = triplePattern.Subject,
                                 predPattern = triplePattern.Predicate,
                                 objPattern = triplePattern.Object;
                             if (var.Equals(triplePattern.Subject.VariableName))
                             {
                                 subjPattern = new NodeMatchPattern(term);
                             }
                             if (var.Equals(triplePattern.Predicate.VariableName))
                             {
                                 predPattern = new NodeMatchPattern(term);
                             }
                             if (var.Equals(triplePattern.Object.VariableName))
                             {
                                 objPattern = new NodeMatchPattern(term);
                             }
                             triplePatterns.Add(new TriplePattern(subjPattern, predPattern, objPattern));
                         }
                         else
                         {
                             triplePatterns.Add(triplePattern);
                         }
                     }
                     else
                     {
                         triplePatterns.Add(tp);
                     }
                 }
                 {
                     optimisedAlgebra = new Bgp(triplePatterns);
                     return true;
                 }
             }
         }
     }
     optimisedAlgebra = bgp;
     return false;
 }
        /// <summary>
        /// Evaluates a setp of the Path
        /// </summary>
        /// <param name="context">Context</param>
        /// <param name="path">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        /// <returns></returns>
        protected List <INode> EvaluateStep(SparqlEvaluationContext context, List <INode> path, bool reverse)
        {
            if (this.Path is Property)
            {
                HashSet <INode>      nodes     = new HashSet <INode>();
                INode                predicate = ((Property)this.Path).Predicate;
                IEnumerable <Triple> ts        = (reverse ? context.Data.GetTriplesWithPredicateObject(predicate, path[path.Count - 1]) : context.Data.GetTriplesWithSubjectPredicate(path[path.Count - 1], predicate));
                foreach (Triple t in ts)
                {
                    if (reverse)
                    {
                        if (!path.Contains(t.Subject))
                        {
                            nodes.Add(t.Subject);
                        }
                    }
                    else
                    {
                        if (!path.Contains(t.Object))
                        {
                            nodes.Add(t.Object);
                        }
                    }
                }
                return(nodes.ToList());
            }
            else
            {
                HashSet <INode> nodes = new HashSet <INode>();

                BaseMultiset    initialInput = context.InputMultiset;
                Multiset        currInput    = new Multiset();
                VariablePattern x            = new VariablePattern("?x");
                VariablePattern y            = new VariablePattern("?y");
                Set             temp         = new Set();
                if (reverse)
                {
                    temp.Add("y", path[path.Count - 1]);
                }
                else
                {
                    temp.Add("x", path[path.Count - 1]);
                }
                currInput.Add(temp);
                context.InputMultiset = currInput;

                Bgp          bgp     = new Bgp(new PropertyPathPattern(x, this.Path, y));
                BaseMultiset results = context.Evaluate(bgp); //bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (ISet s in results.Sets)
                    {
                        if (reverse)
                        {
                            if (s["x"] != null)
                            {
                                if (!path.Contains(s["x"]))
                                {
                                    nodes.Add(s["x"]);
                                }
                            }
                        }
                        else
                        {
                            if (s["y"] != null)
                            {
                                if (!path.Contains(s["y"]))
                                {
                                    nodes.Add(s["y"]);
                                }
                            }
                        }
                    }
                }

                return(nodes.ToList());
            }
        }
        /// <summary>
        /// Evaluates a setp of the Path
        /// </summary>
        /// <param name="context">Context</param>
        /// <param name="path">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        /// <returns></returns>
        protected List<INode> EvaluateStep(SparqlEvaluationContext context, List<INode> path, bool reverse)
        {
            if (this.Path is Property)
            {
                HashSet<INode> nodes = new HashSet<INode>();
                INode predicate = ((Property)this.Path).Predicate;
                IEnumerable<Triple> ts = (reverse ? context.Data.GetTriplesWithPredicateObject(predicate, path[path.Count - 1]) : context.Data.GetTriplesWithSubjectPredicate(path[path.Count - 1], predicate));
                foreach (Triple t in ts)
                {
                    if (reverse)
                    {
                        if (!path.Contains(t.Subject))
                        {
                            nodes.Add(t.Subject);
                        }
                    }
                    else
                    {
                        if (!path.Contains(t.Object))
                        {
                            nodes.Add(t.Object);
                        }
                    }
                }
                return nodes.ToList();
            }
            else
            {
                List<INode> nodes = new List<INode>();

                BaseMultiset initialInput = context.InputMultiset;
                Multiset currInput = new Multiset();
                VariablePattern x = new VariablePattern("?x");
                VariablePattern y = new VariablePattern("?y");
                Set temp = new Set();
                if (reverse)
                {
                    temp.Add("y", path[path.Count - 1]);
                }
                else
                {
                    temp.Add("x", path[path.Count - 1]);
                }
                currInput.Add(temp);
                context.InputMultiset = currInput;

                Bgp bgp = new Bgp(new PropertyPathPattern(x, this.Path, y));
                BaseMultiset results = context.Evaluate(bgp);//bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (Set s in results.Sets)
                    {
                        if (reverse)
                        {
                            if (s["x"] != null)
                            {
                                if (!path.Contains(s["x"]))
                                {
                                    nodes.Add(s["x"]);
                                }
                            }
                        }
                        else
                        {
                            if (s["y"] != null)
                            {
                                if (!path.Contains(s["y"]))
                                {
                                    nodes.Add(s["y"]);
                                }
                            }
                        }
                    }
                }

                return nodes;
            }
        }