public void SparqlAlgebraVariableClassification1() { TriplePattern tp = MakeTriplePattern(this._s, this._p, this._o); IBgp bgp = new Bgp(tp); this.TestClassification(bgp, this._emptyList, this._emptyList); }
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" }); }
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 }))); }
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)))); }
/// <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; } }
/// <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 }))); }
/// <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; } } }
/// <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; } }