public string ProcessBGP(Bgp bgp) { List <ITriplePattern> patterns = bgp.TriplePatterns.ToList(); if (patterns.Count == 2) { TriplePattern p1 = patterns[0] as TriplePattern; TriplePattern p2 = patterns[1] as TriplePattern; MapNode mNode1 = mapping.GetMapNodeForTripple(p1.Subject.ToString(), p1.Predicate.ToString(), p1.Object.ToString()); MapNode mNode2 = mapping.GetMapNodeForTripple(p2.Subject.ToString(), p2.Predicate.ToString(), p2.Object.ToString()); //perform inner joins between them string sql1 = mapping.MergeSqlDBString(mNode1); string sql2 = mapping.MergeSqlDBString(mNode2); string sql = $"{InnerJoin(sql1, sql2)}"; return(sql); //sql += $"{InnerJoin(patterns[0], patterns[1])}"; } else if (patterns.Count == 1) { TriplePattern p = patterns[0] as TriplePattern; MapNode mNode = mapping.GetMapNodeForTripple(p.Subject.ToString(), p.Predicate.ToString(), p.Object.ToString()); string sqlTripple = mapping.MergeSqlDBString(mNode); string sql = $"({sqlTripple})"; return(sql); } else if (patterns.Count > 2) { //here we run the cyclic joins on each 2 queries, //optimizing the queries after each join } return(null); }
private bool IsDisjointOperation(ISparqlAlgebra algebra, String lhsVar, String rhsVar, out int splitPoint) { splitPoint = -1; if (algebra is IBgp) { // Get Triple Patterns, can't split into a product if there are blank variables present List <ITriplePattern> ps = ((IBgp)algebra).TriplePatterns.ToList(); if (ps.Any(p => !p.HasNoBlankVariables)) { return(false); } // Iterate over the Triple Patterns to see if we can split into a Product List <String> vars = new List <String>(); for (int i = 0; i < ps.Count; i++) { // Not a product if we've seen both variables already if (vars.Contains(lhsVar) && vars.Contains(rhsVar)) { return(false); } ITriplePattern p = ps[i]; switch (p.PatternType) { case TriplePatternType.Match: case TriplePatternType.SubQuery: if (vars.Count > 0 && vars.IsDisjoint(p.Variables)) { // May be a filterable product if we've seen only one variable so far and have hit a point where a product occurs if (vars.Contains(lhsVar) && !vars.Contains(rhsVar)) { Bgp rhs = new Bgp(ps.Skip(i)); if (rhs.Variables.Contains(rhsVar)) { splitPoint = i; return(true); } } else if (vars.Contains(rhsVar) && !vars.Contains(lhsVar)) { Bgp rhs = new Bgp(ps.Skip(i)); if (rhs.Variables.Contains(lhsVar)) { splitPoint = i; return(true); } } } vars.AddRange(p.Variables); break; case TriplePatternType.BindAssignment: case TriplePatternType.LetAssignment: vars.Add(((IAssignmentPattern)p).VariableName); break; case TriplePatternType.Filter: continue; default: // Can't determine if it is a disjoint operation if other pattern types are involved return(false); } } // If we get all the way here then not a product return(false); } else if (algebra is IJoin) { IJoin join = (IJoin)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { // There a product between the two sides of the join but are the two variables on different sides of that join return(!(join.Lhs.Variables.Contains(lhsVar) && join.Lhs.Variables.Contains(rhsVar)) && !(join.Rhs.Variables.Contains(lhsVar) && join.Rhs.Variables.Contains(rhsVar))); } else { return(false); } } else { return(false); } }
/// <summary> /// Gets the Algebra representation of the Graph Pattern /// </summary> /// <returns></returns> public ISparqlAlgebra ToAlgebra() { if (_isUnion) { // If this Graph Pattern represents a UNION of Graph Patterns turn into a series of UNIONs ISparqlAlgebra union = new Union(_graphPatterns[0].ToAlgebra(), _graphPatterns[1].ToAlgebra()); if (_graphPatterns.Count > 2) { for (int i = 2; i < _graphPatterns.Count; i++) { union = new Union(union, _graphPatterns[i].ToAlgebra()); } } // Apply Inline Data if (HasInlineData) { union = Join.CreateJoin(union, new Bindings(_data)); } // If there's a FILTER apply it over the Union if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { return(new Filter(union, Filter)); } return(union); } // Terminal graph pattern if (_graphPatterns.Count == 0) { // If there are no Child Graph Patterns then this is a BGP ISparqlAlgebra bgp = new Bgp(_triplePatterns); if (_unplacedAssignments.Count > 0) { // If we have any unplaced LETs these get Extended onto the BGP foreach (IAssignmentPattern p in _unplacedAssignments) { bgp = new Extend(bgp, p.AssignExpression, p.VariableName); } } if (IsGraph) { bgp = Algebra.Graph.ApplyGraph(bgp, GraphSpecifier); } else if (IsService) { bgp = new Service(GraphSpecifier, this, IsSilent); } // Apply Inline Data if (HasInlineData) { bgp = Join.CreateJoin(bgp, new Bindings(_data)); } if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { if (_isOptional && !(_isExists || _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); } // If we contain an unplaced FILTER and we're not an OPTIONAL the FILTER // applies here return(new Filter(bgp, Filter)); } // We're not filtered (or all FILTERs were placed in the BGP) so we're just a BGP return(bgp); } // Create a basic BGP to start with ISparqlAlgebra complex = new Bgp(); if (_triplePatterns.Count > 0) { complex = new Bgp(_triplePatterns); } // Apply Inline Data // If this Graph Pattern had child patterns before this Graph Pattern then we would // have broken the BGP and not added the Inline Data here so it's always safe to apply this here if (HasInlineData) { complex = Join.CreateJoin(complex, new Bindings(_data)); } // Then Join each of the Graph Patterns as appropriate foreach (GraphPattern gp in _graphPatterns) { if (gp.IsGraph) { // A GRAPH clause means a Join of the current pattern to a Graph clause ISparqlAlgebra gpAlgebra = gp.ToAlgebra(); complex = Join.CreateJoin(complex, Algebra.Graph.ApplyGraph(gpAlgebra, 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 (_unplacedAssignments.Count > 0) { // Unplaced assignments get Extended over the algebra so far here // complex = Join.CreateJoin(complex, new Bgp(this._unplacedAssignments.OfType<ITriplePattern>())); foreach (IAssignmentPattern p in _unplacedAssignments) { complex = new Extend(complex, p.AssignExpression, p.VariableName); } } if (IsGraph) { complex = Algebra.Graph.ApplyGraph(complex, GraphSpecifier); } if (_isFiltered && (_filter != null || _unplacedFilters.Count > 0)) { if (_isOptional && !(_isExists || _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 (_filter != null || _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, Filter)); } else { return(complex); } } } else { // If no FILTER just return the transform return(complex); } }
/// <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 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 all Node terms are virtualised. /// </summary> /// <param name="algebra">Algebra.</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()); TNodeID nullID = _provider.NullID; for (int i = 0; i < current.PatternCount; i++) { if (ps[i].PatternType == TriplePatternType.Filter || ps[i].PatternType == TriplePatternType.BindAssignment || ps[i].PatternType == TriplePatternType.LetAssignment) { // 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].PatternType == TriplePatternType.Filter) { result = new Filter(result, new UnaryExpressionFilter(Transform(((IFilterPattern)ps[i]).Filter.Expression))); } else { IAssignmentPattern bind = (IAssignmentPattern)ps[i]; result = new Extend(result, Transform(bind.AssignExpression), bind.VariableName); } } else if (ps[i].PatternType == TriplePatternType.Match) { // Convert Terms in the Pattern into Virtual Nodes IMatchTriplePattern tp = (IMatchTriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } else { // Can't optimize if other pattern types involved return(current); } } if (result is NullOperator) { return(result); } 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> /// 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> /// Processes SPARQL Algebra /// </summary> /// <param name="algebra">Algebra</param> /// <param name="context">SPARQL Evaluation Context</param> public string ProcessAlgebra(ISparqlAlgebra algebra) { string sql = ""; if (algebra is IBgp) //a tripple pattern { //here use the value from mapping Bgp bgp = algebra as Bgp; //foreach(TriplePattern triplePattern in bgp.TriplePatterns) //{ // sql += this.mapping.GetMappingForTripple(triplePattern.Subject.ToString(), triplePattern.Predicate.ToString(), triplePattern.Object.ToString()); //} List <ITriplePattern> patterns = bgp.TriplePatterns.ToList(); if (patterns.Count >= 2) { TriplePattern p1 = patterns[0] as TriplePattern; TriplePattern p2 = patterns[1] as TriplePattern; MapNode mNode1 = mapping.GetMapNodeForTripple(p1.Subject.ToString(), p1.Predicate.ToString(), p1.Object.ToString()); MapNode mNode2 = mapping.GetMapNodeForTripple(p2.Subject.ToString(), p2.Predicate.ToString(), p2.Object.ToString()); //perform inner joins between them string sql1 = mapping.MergeSqlDBString(mNode1); string sql2 = mapping.MergeSqlDBString(mNode2); sql = $"{InnerJoin(sql1, sql2)}"; Console.WriteLine("\n\n{0}", sql); //sql += $"{InnerJoin(patterns[0], patterns[1])}"; } else { sql += $"({patterns[0]})"; } } else if (algebra is Select) { Select select = algebra as Select; string variables = select.IsSelectAll ? "*" : string.Join(",", select.FixedVariables); string from = ProcessAlgebra(select.InnerAlgebra); sql = $"SELECT {variables}\nFROM ({from}) \nWHERE *"; } //else if (algebra is IFilter) //{ // return this.ProcessFilter((IFilter)algebra); //} ////else if (algebra is Algebra.Graph) ////{ //// return this.ProcessGraph((Algebra.Graph)algebra, context); ////} //else if (algebra is IJoin) //{ // return this.ProcessJoin((IJoin)algebra); //} //else if (algebra is ILeftJoin) //{ // return this.ProcessLeftJoin((ILeftJoin)algebra); //} //else if (algebra is IUnion) //{ // return this.ProcessUnion((IUnion)algebra); //} //else //{ // //Unknown Algebra // throw new Exception("ProcessAlgebra(): Unknown algebra!"); //} return(sql); }
public void SparqlBgpEvaluation() { //Prepare the Store TripleStore store = new TripleStore(); Graph g = new Graph(); FileLoader.Load(g, "resources\\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 VariableTerm("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)))); }
public void SparqlStreamingBgpSelectEvaluation() { //Get the Data we want to query TripleStore store = new TripleStore(); Graph g = new Graph(); FileLoader.Load(g, "resources\\InferenceTest.ttl"); store.Add(g); //g = new Graph(); //g.LoadFromFile("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 VariableTerm("?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 (ISet 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(); } }
/// <summary> /// Converts the Query into it's SPARQL Algebra representation (as represented in the Leviathan API) /// </summary> /// <returns></returns> public ISparqlAlgebra ToAlgebra() { //Depending on how the query gets built we may not have had graph pattern optimization applied //which we should do here if query optimization is enabled if (!this.IsOptimised && Options.QueryOptimisation) { this.Optimise(); } //Firstly Transform the Root Graph Pattern to SPARQL Algebra ISparqlAlgebra algebra; 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: algebra = new SelectDistinctGraphs(this.Variables.First(v => v.IsResultVariable).Name); break; case SparqlSpecialQueryType.AskAnyTriples: algebra = new AskAnyTriples(); break; case SparqlSpecialQueryType.NotApplicable: default: //If not just use the standard transform algebra = this._rootGraphPattern.ToAlgebra(); break; } } else { //If not using Algebra Optimisation just use the standard transform algebra = this._rootGraphPattern.ToAlgebra(); } } else { //No root graph pattern means empty BGP algebra = new Bgp(); } //If we have a top level VALUES clause then we'll add it into the algebra here if (this._bindings != null) { algebra = Join.CreateJoin(algebra, new Bindings(this._bindings)); } //Then we apply any optimisers followed by relevant solution modifiers switch (this._type) { case SparqlQueryType.Ask: //Apply Algebra Optimisation is enabled if (Options.AlgebraOptimisation) { algebra = this.ApplyAlgebraOptimisations(algebra); } return(new Ask(algebra)); 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) { algebra = this.ApplyAlgebraOptimisations(algebra); } //GROUP BY is the first thing applied //This applies if there is a GROUP BY or if there are aggregates //With no GROUP BY it produces a single group of all results if (this._groupBy != null || this._vars.Any(v => v.IsAggregate)) { algebra = new GroupBy(algebra, this._groupBy, this._vars.Where(v => v.IsAggregate)); } //After grouping we do projection //We introduce an Extend for each Project Expression foreach (SparqlVariable var in this._vars) { if (var.IsProjection) { algebra = new Extend(algebra, var.Projection, var.Name); } } //Add HAVING clause after the projection if (this._having != null) { algebra = new Having(algebra, 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) { algebra = new OrderBy(algebra, 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) { algebra = new Select(algebra, this.Variables); } //If we have a Distinct/Reduced then we'll apply those after Selection if (this._type == SparqlQueryType.SelectAllDistinct || this._type == SparqlQueryType.SelectDistinct) { algebra = new Distinct(algebra); } else if (this._type == SparqlQueryType.SelectAllReduced || this._type == SparqlQueryType.SelectReduced) { algebra = new Reduced(algebra); } //Finally we can apply any limit and/or offset if (this._limit >= 0 || this._offset > 0) { algebra = new Slice(algebra, this._limit, this._offset); } return(algebra); default: throw new RdfQueryException("Unable to convert unknown Query Types to SPARQL Algebra"); } }
/// <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 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 the algebra so that all Node terms are virtualised /// </summary> /// <param name="algebra">Algebra</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()); TNodeID nullID = this._provider.NullID; 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 { //Convert Terms in the Pattern into Virtual Nodes TriplePattern tp = (TriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } } if (result is NullOperator) { return(result); } else 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) { // 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].PatternType != TriplePatternType.Match) { // 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 switch (ps[i].PatternType) { case TriplePatternType.Filter: result = new Filter(result, ((IFilterPattern)ps[i]).Filter); break; case TriplePatternType.BindAssignment: case TriplePatternType.LetAssignment: IAssignmentPattern assignment = (IAssignmentPattern)ps[i]; result = new Extend(result, assignment.AssignExpression, assignment.VariableName); break; case TriplePatternType.SubQuery: ISubQueryPattern sq = (ISubQueryPattern)ps[i]; result = Join.CreateJoin(result, new SubQuery(sq.SubQuery)); break; case TriplePatternType.Path: IPropertyPathPattern pp = (IPropertyPathPattern)ps[i]; result = Join.CreateJoin(result, new PropertyPath(pp.Subject, pp.Path, pp.Object)); break; case TriplePatternType.PropertyFunction: IPropertyFunctionPattern pf = (IPropertyFunctionPattern)ps[i]; result = new PropertyFunction(result, pf.PropertyFunction); break; default: throw new RdfQueryException("Cannot apply strict algebra form to a BGP containing a unknown triple pattern type"); } } 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); } }
private bool IsDisjointOperation(ISparqlAlgebra algebra, List <String> filterVars, out int splitPoint) { splitPoint = -1; if (algebra is IBgp) { // Get Triple Patterns, can't split into a product if there are blank variables present List <ITriplePattern> ps = ((IBgp)algebra).TriplePatterns.ToList(); if (ps.Any(p => !p.HasNoBlankVariables)) { return(false); } // Iterate over the Triple Patterns to see if we can split into a Product List <String> vars = new List <String>(); for (int i = 0; i < ps.Count; i++) { // Not a product if we've seen both variables already if (filterVars.All(v => vars.Contains(v))) { return(false); } ITriplePattern p = ps[i]; if (p.PatternType == TriplePatternType.Match || p.PatternType == TriplePatternType.SubQuery) { if (vars.Count > 0 && vars.IsDisjoint(p.Variables)) { // Is a filterable product if we've not seen all the variables so far and have hit a point where a product occurs // and all the variables are not in the RHS Bgp rhs = new Bgp(ps.Skip(i)); if (!filterVars.All(v => rhs.Variables.Contains(v))) { splitPoint = i; return(true); } } vars.AddRange(p.Variables); } else if (p.PatternType == TriplePatternType.BindAssignment || p.PatternType == TriplePatternType.LetAssignment) { vars.Add(((IAssignmentPattern)p).VariableName); } else if (p.PatternType == TriplePatternType.Filter) { continue; } else { return(false); } } // If we get all the way here then not a product return(false); } else if (algebra is IJoin) { IJoin join = (IJoin)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { // There a product between the two sides of the join but are the variables spead over different sides of that join? // If all variables occur on one side then this is not a filtered product return(!filterVars.All(v => join.Lhs.Variables.Contains(v)) && !filterVars.All(v => join.Rhs.Variables.Contains(v))); } else { return(false); } } else { return(false); } }
/// <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); } }