/// <summary> /// Creates a new Evaluation Context for the given Query over the given Dataset /// </summary> /// <param name="q">Query</param> /// <param name="data">Dataset</param> public SparqlEvaluationContext(SparqlQuery q, ISparqlDataset data) { this._query = q; this._data = data; this._inputSet = new IdentityMultiset(); this._binder = new LeviathanResultBinder(this); this.CalculateTimeout(); }
private void ShowMultiset(BaseMultiset multiset) { Console.WriteLine(multiset.GetType().ToString()); foreach (ISet s in multiset.Sets) { Console.WriteLine(s.ToString()); } Console.WriteLine(); }
/// <summary> /// Evaluates a property path pattern /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlEvaluationContext context) { // Try and generate an Algebra expression // Make sure we don't generate clashing temporary variable IDs over the life of the // Evaluation PathTransformContext transformContext = new PathTransformContext(_subj, _obj); if (context["PathTransformID"] != null) { transformContext.NextID = (int)context["PathTransformID"]; } ISparqlAlgebra algebra = _path.ToAlgebra(transformContext); context["PathTransformID"] = transformContext.NextID + 1; // Now we can evaluate the resulting algebra BaseMultiset initialInput = context.InputMultiset; bool trimMode = context.TrimTemporaryVariables; bool rigMode = Options.RigorousEvaluation; try { // Must enable rigorous evaluation or we get incorrect interactions between property and non-property path patterns Options.RigorousEvaluation = true; // Note: We may need to preserve Blank Node variables across evaluations // which we usually don't do BUT because of the way we translate only part of the path // into an algebra at a time and may need to do further nested translate calls we do // need to do this here context.TrimTemporaryVariables = false; BaseMultiset result = context.Evaluate(algebra);//algebra.Evaluate(context); // Also note that we don't trim temporary variables here even if we've set the setting back // to enabled since a Trim will be done at the end of whatever BGP we are being evaluated in // Once we have our results can join then into our input if (result is NullMultiset) { context.OutputMultiset = new NullMultiset(); } else { context.OutputMultiset = initialInput.Join(result); } // If we reach here we've successfully evaluated the simple pattern and can return return; } finally { context.TrimTemporaryVariables = trimMode; Options.RigorousEvaluation = rigMode; } }
public void SparqlPropertyPathEvaluationZeroLengthWithTermStart() { EnsureTestData(); FixedCardinality path = new FixedCardinality(new Property(this._factory.CreateUriNode(new Uri(RdfSpecsHelper.RdfType))), 0); ISparqlAlgebra algebra = this.GetAlgebra(path, new Graph().CreateUriNode(UriFactory.Create(ConfigurationLoader.ClassHttpHandler)), null); SparqlEvaluationContext context = new SparqlEvaluationContext(null, this._data); BaseMultiset results = algebra.Evaluate(context); TestTools.ShowMultiset(results); Assert.IsFalse(results.IsEmpty, "Results should not be empty"); }
public void SparqlPropertyPathEvaluationInverseNegatedPropertySet() { EnsureTestData(); NegatedSet path = new NegatedSet(Enumerable.Empty <Property>(), new Property[] { new Property(this._factory.CreateUriNode(new Uri(RdfSpecsHelper.RdfType))) }); ISparqlAlgebra algebra = this.GetAlgebra(path); SparqlEvaluationContext context = new SparqlEvaluationContext(null, this._data); BaseMultiset results = algebra.Evaluate(context); TestTools.ShowMultiset(results); Assert.IsFalse(results.IsEmpty, "Results should not be empty"); }
public void SparqlPropertyPathEvaluationZeroLength() { EnsureTestData(); FixedCardinality path = new FixedCardinality(new Property(this._factory.CreateUriNode(new Uri(RdfSpecsHelper.RdfType))), 0); ISparqlAlgebra algebra = this.GetAlgebra(path); SparqlEvaluationContext context = new SparqlEvaluationContext(null, this._data); BaseMultiset results = algebra.Evaluate(context); TestTools.ShowMultiset(results); Assert.False(results.IsEmpty, "Results should not be empty"); }
public void SparqlPropertyPathEvaluationSequencedAlternatives() { EnsureTestData(); INode a = this._factory.CreateUriNode(new Uri(RdfSpecsHelper.RdfType)); INode b = this._factory.CreateUriNode(new Uri(NamespaceMapper.RDFS + "range")); SequencePath path = new SequencePath(new AlternativePath(new Property(a), new Property(b)), new AlternativePath(new Property(a), new Property(a))); ISparqlAlgebra algebra = this.GetAlgebraUntransformed(path); SparqlEvaluationContext context = new SparqlEvaluationContext(null, this._data); BaseMultiset results = algebra.Evaluate(context); TestTools.ShowMultiset(results); Assert.IsFalse(results.IsEmpty, "Results should not be empty"); }
private void EvalExtend(SparqlEvaluationContext context, BaseMultiset results, ISparqlExpression expr, String var, int id) { ISet s = results[id].Copy(); try { //Make a new assignment INode temp = expr.Evaluate(context, id); s.Add(var, temp); } catch { //No assignment if there's an error but the solution is preserved } context.OutputMultiset.Add(s); }
public void SparqlPropertyPathEvaluationZeroLengthWithTermEnd() { EnsureTestData(); FixedCardinality path = new FixedCardinality(new Property(this._factory.CreateUriNode(new Uri(RdfSpecsHelper.RdfType))), 0); INode rdfsClass = this._factory.CreateUriNode(new Uri(NamespaceMapper.RDFS + "Class")); ISparqlAlgebra algebra = this.GetAlgebra(path, null, rdfsClass); SparqlEvaluationContext context = new SparqlEvaluationContext(null, this._data); BaseMultiset results = algebra.Evaluate(context); TestTools.ShowMultiset(results); Assert.IsFalse(results.IsEmpty, "Results should not be empty"); Assert.AreEqual(1, results.Count, "Expected 1 Result"); Assert.AreEqual(rdfsClass, results[1]["x"], "Expected 1 Result set to rdfs:Class"); }
/// <summary> /// Executes a Graph Pattern style query against the Source /// </summary> /// <param name="graph">Graph Pattern</param> /// <param name="options">Query Options</param> /// <param name="sink">Results Sink</param> /// <remarks> /// <para> /// This is implemented by transforming the Graph Pattern which is a set of SemWeb Statement templates into a SPARQL Algebra BGP. The resulting algebra is then executed using the Leviathan engine and the results converted into VariableBindings for SemWeb /// </para> /// <para> /// The only Query Option that is supported is the Limit option /// </para> /// </remarks> public void Query(Statement[] graph, SW.Query.QueryOptions options, SW.Query.QueryResultSink sink) { ISparqlAlgebra algebra = this.ToAlgebra(graph); if (this._store == null) { this._store = new TripleStore(); this._store.Add(this._g); } SparqlEvaluationContext context = new SparqlEvaluationContext(null, new InMemoryDataset(this._store)); BaseMultiset results = context.Evaluate(algebra);//algebra.Evaluate(context); sink.Init(results.Variables.Select(v => new Variable(v)).ToArray()); if (results.Count > 0) { int c = 0; foreach (ISet s in results.Sets) { //Apply Limit if applicable if (options.Limit > 0 && c >= options.Limit) { sink.Finished(); return; } //Convert the Set to VariableBindings for SemWeb Variable[] vars = s.Variables.Select(v => new Variable(v)).ToArray(); Resource[] resources = s.Variables.Select(v => SemWebConverter.ToSemWeb(s[v], this._mapping)).ToArray(); SW.Query.VariableBindings bindings = new SW.Query.VariableBindings(vars, resources); //Keep adding results until the sink tells us to stop if (!sink.Add(bindings)) { sink.Finished(); return; } c++; } sink.Finished(); } else { sink.Finished(); } }
public void SparqlPropertyPathEvaluationZeroOrMorePath() { TripleStore store = new TripleStore(); Graph g = new Graph(); g.LoadFromFile("InferenceTest.ttl"); store.Add(g); InMemoryDataset dataset = new InMemoryDataset(store, g.BaseUri); ZeroOrMore path = new ZeroOrMore(new Property(this._factory.CreateUriNode(new Uri(NamespaceMapper.RDFS + "subClassOf")))); ISparqlAlgebra algebra = this.GetAlgebra(path); BaseMultiset results = algebra.Evaluate(new SparqlEvaluationContext(null, dataset)); TestTools.ShowMultiset(results); Assert.IsFalse(results.IsEmpty, "Results should not be empty"); }
public static void ShowMultiset(BaseMultiset multiset) { if (multiset is NullMultiset) { Console.WriteLine("NULL"); } else if (multiset is IdentityMultiset) { Console.WriteLine("IDENTITY"); } else { foreach (ISet s in multiset.Sets) { Console.WriteLine(s.ToString()); } } }
/// <summary> /// Internal method which evaluates the Graph Pattern /// </summary> /// <param name="context">Evaluation Context</param> /// <remarks> /// We only ever need to evaluate the Graph Pattern once to get the Results /// </remarks> private void EvaluateInternal(SparqlEvaluationContext context) { if (this._lastInput != context.InputMultiset.GetHashCode()) { this._result = null; this._lastInput = context.InputMultiset.GetHashCode(); } if (this._result != null) { return; } //REQ: Optimise the algebra here ISparqlAlgebra existsClause = this._pattern.ToAlgebra(); BaseMultiset initialInput = context.InputMultiset; this._result = context.Evaluate(existsClause);//existsClause.Evaluate(context); context.InputMultiset = initialInput; }
public void SparqlPropertyPathEvaluationZeroOrMorePathForward() { TripleStore store = new TripleStore(); Graph g = new Graph(); g.LoadFromFile("resources\\InferenceTest.ttl"); store.Add(g); InMemoryDataset dataset = new InMemoryDataset(store); ZeroOrMore path = new ZeroOrMore(new Property(this._factory.CreateUriNode(new Uri(NamespaceMapper.RDFS + "subClassOf")))); INode sportsCar = this._factory.CreateUriNode(new Uri("http://example.org/vehicles/SportsCar")); ISparqlAlgebra algebra = this.GetAlgebra(path, sportsCar, null); BaseMultiset results = algebra.Evaluate(new SparqlEvaluationContext(null, dataset)); TestTools.ShowMultiset(results); Assert.False(results.IsEmpty, "Results should not be empty"); }
/// <summary> /// Creates a new LeftJoin Binder /// </summary> /// <param name="multiset">Input Multiset</param> public LeviathanLeftJoinBinder(BaseMultiset multiset) : base() { this._input = multiset; }
/// <summary> /// Internal method which evaluates the Graph Pattern /// </summary> /// <param name="context">Evaluation Context</param> /// <remarks> /// We only ever need to evaluate the Graph Pattern once to get the Results /// </remarks> private void EvaluateInternal(SparqlEvaluationContext context) { this._result = null; this._lastInput = context.InputMultiset.GetHashCode(); this._lastCount = context.InputMultiset.Count; //REQ: Optimise the algebra here ISparqlAlgebra existsClause = this._pattern.ToAlgebra(); BaseMultiset initialInput = context.InputMultiset; this._result = context.Evaluate(existsClause); context.InputMultiset = initialInput; //This is the new algorithm which is also correct but is O(3n) so much faster and scalable //Downside is that it does require more memory than the old algorithm this._joinVars = context.InputMultiset.Variables.Where(v => this._result.Variables.Contains(v)).ToList(); if (this._joinVars.Count == 0) { return; } List <HashTable <INode, int> > values = new List <HashTable <INode, int> >(); List <List <int> > nulls = new List <List <int> >(); foreach (System.String var in this._joinVars) { values.Add(new HashTable <INode, int>(HashTableBias.Enumeration)); nulls.Add(new List <int>()); } //First do a pass over the LHS Result to find all possible values for joined variables foreach (ISet x in context.InputMultiset.Sets) { int i = 0; foreach (System.String var in this._joinVars) { INode value = x[var]; if (value != null) { values[i].Add(value, x.ID); } else { nulls[i].Add(x.ID); } i++; } } //Then do a pass over the RHS and work out the intersections this._exists = new HashSet <int>(); foreach (ISet y in this._result.Sets) { IEnumerable <int> possMatches = null; int i = 0; foreach (System.String var in this._joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i]))); } else { possMatches = Enumerable.Empty <int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? context.InputMultiset.SetIDs : possMatches.Intersect(context.InputMultiset.SetIDs)); } i++; } if (possMatches == null) { continue; } //Look at possible matches, if is a valid match then mark the set as having an existing match //Don't reconsider sets which have already been marked as having an existing match foreach (int poss in possMatches) { if (this._exists.Contains(poss)) { continue; } if (context.InputMultiset[poss].IsCompatibleWith(y, this._joinVars)) { this._exists.Add(poss); } } } }
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { bool datasetOk = false; bool defGraphOk = false; try { //First evaluate the WHERE pattern to get the affected bindings ISparqlAlgebra where = this._wherePattern.ToAlgebra(); if (context.Commands != null) { where = context.Commands.ApplyAlgebraOptimisers(where); } //Set Active Graph for the WHERE //Don't bother if there are USING URIs as these would override any Active Graph we set here //so we can save ourselves the effort of doing this if (!this.UsingUris.Any()) { if (this._graphUri != null) { context.Data.SetActiveGraph(this._graphUri); defGraphOk = true; } else { context.Data.SetActiveGraph((Uri)null); defGraphOk = true; } } //We need to make a dummy SparqlQuery object since if the Command has used any //USING NAMEDs along with GRAPH clauses then the algebra needs to have the //URIs available to it which it gets from the Query property of the Context //object SparqlQuery query = new SparqlQuery(); foreach (Uri u in this.UsingUris) { query.AddDefaultGraph(u); } foreach (Uri u in this.UsingNamedUris) { query.AddNamedGraph(u); } SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data, context.QueryProcessor); if (this.UsingUris.Any()) { //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs context.Data.SetActiveGraph(this._usingUris); datasetOk = true; } BaseMultiset results = queryContext.Evaluate(where); if (results is IdentityMultiset) { queryContext.OutputMultiset = new SingletonMultiset(results.Variables); } if (this.UsingUris.Any()) { //If there are USING URIs reset the Active Graph afterwards //Also flag the dataset as no longer being OK as this flag is used in the finally //block to determine whether the Active Graph needs resetting which it may do if the //evaluation of the query fails for any reason context.Data.ResetActiveGraph(); datasetOk = false; } //Reset Active Graph for the WHERE if (defGraphOk) { context.Data.ResetActiveGraph(); defGraphOk = false; } //TODO: Need to detect when we create a Graph for Insertion but then fail to insert anything since in this case the Inserted Graph should be removed //Get the Graph to which we are inserting Triples with no explicit Graph clause IGraph g = null; if (this._insertPattern.TriplePatterns.Count > 0) { if (context.Data.HasGraph(this._graphUri)) { g = context.Data.GetModifiableGraph(this._graphUri); } else { //insertedGraphs.Add(this._graphUri); g = new Graph(); g.BaseUri = this._graphUri; context.Data.AddGraph(g); g = context.Data.GetModifiableGraph(this._graphUri); } } //Keep a record of graphs to which we insert MultiDictionary <Uri, IGraph> graphs = new MultiDictionary <Uri, IGraph>(u => (u != null ? u.GetEnhancedHashCode() : 0), true, new UriComparer(), MultiDictionaryMode.AVL); //Insert the Triples for each Solution foreach (ISet s in queryContext.OutputMultiset.Sets) { List <Triple> insertedTriples = new List <Triple>(); try { //Create a new Construct Context for each Solution ConstructContext constructContext = new ConstructContext(null, s, true); //Triples from raw Triple Patterns if (this._insertPattern.TriplePatterns.Count > 0) { foreach (IConstructTriplePattern p in this._insertPattern.TriplePatterns.OfType <IConstructTriplePattern>()) { try { insertedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct a specific Triple //so we continue anyway } } g.Assert(insertedTriples); } //Triples from GRAPH clauses foreach (GraphPattern gp in this._insertPattern.ChildGraphPatterns) { insertedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: String graphVar = gp.GraphSpecifier.Value.Substring(1); if (s.ContainsVariable(graphVar)) { INode temp = s[graphVar]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } //Ensure the Graph we're inserting to exists in the dataset creating it if necessary IGraph h; Uri destUri = UriFactory.Create(graphUri); if (graphs.ContainsKey(destUri)) { h = graphs[destUri]; } else { if (context.Data.HasGraph(destUri)) { h = context.Data.GetModifiableGraph(destUri); } else { //insertedGraphs.Add(destUri); h = new Graph(); h.BaseUri = destUri; context.Data.AddGraph(h); h = context.Data.GetModifiableGraph(destUri); } graphs.Add(destUri, h); } //Do the actual Insertions foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType <IConstructTriplePattern>()) { try { insertedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct a specific Triple //so we continue anyway } } h.Assert(insertedTriples); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored for this Graph } } } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored for this graph } } } finally { //If the Dataset was set and an error occurred in doing the WHERE clause then //we'll need to Reset the Active Graph if (datasetOk) { context.Data.ResetActiveGraph(); } if (defGraphOk) { context.Data.ResetActiveGraph(); } } }
public void SparqlMultisetLeftJoin() { //Create a load of Nodes to use in the tests Graph g = new Graph(); g.NamespaceMap.AddNamespace(String.Empty, new Uri("http://example.org")); IUriNode s1 = g.CreateUriNode(":s1"); IUriNode s2 = g.CreateUriNode(":s2"); IUriNode p1 = g.CreateUriNode(":p1"); IUriNode p2 = g.CreateUriNode(":p2"); IUriNode rdfsLabel = g.CreateUriNode("rdfs:label"); ILiteralNode o1 = g.CreateLiteralNode("Some Text"); ILiteralNode o2 = g.CreateLiteralNode("1", new Uri(XmlSpecsHelper.XmlSchemaDataTypeInteger)); //Create an ID and Null Multiset IdentityMultiset id = new IdentityMultiset(); NullMultiset nullset = new NullMultiset(); //Create and Populate a Multiset Multiset m = new Multiset(); Set s = new Set(); s.Add("s", s1); s.Add("p", p1); s.Add("o", o1); m.Add(s); s = new Set(); s.Add("s", s2); s.Add("p", p2); s.Add("o", o2); m.Add(s); //Create and Populate another Multiset Multiset n = new Multiset(); s = new Set(); s.Add("s", s1); s.Add("label", o1); n.Add(s); //Create and Populate another Multiset Multiset d = new Multiset(); s = new Set(); s.Add("s1", s1); s.Add("p1", p1); s.Add("o1", o1); d.Add(s); s = new Set(); s.Add("s1", s2); s.Add("p1", p2); s.Add("o1", o2); d.Add(s); //Show the Sets Console.WriteLine("LHS"); foreach (ISet set in m.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); Console.WriteLine("RHS"); foreach (ISet set in n.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); Console.WriteLine("D"); foreach (ISet set in d.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join to Identity Console.WriteLine("Join ID-LHS"); BaseMultiset join = id.Join(m); foreach (ISet set in join.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join to Identity Console.WriteLine("Join LHS-ID"); join = m.Join(id); foreach (ISet set in join.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join to Null Console.WriteLine("Join NULL-LHS"); join = nullset.Join(m); foreach (ISet set in join.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join to Null Console.WriteLine("Join LHS-NULL"); join = m.Join(nullset); foreach (ISet set in join.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a LeftJoin Console.WriteLine("LeftJoin NULL-LHS"); BaseMultiset leftjoin = nullset.LeftJoin(m, new ConstantTerm(new BooleanNode(null, true))); foreach (ISet set in leftjoin.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a LeftJoin Console.WriteLine("LeftJoin LHS-NULL"); leftjoin = m.LeftJoin(nullset, new ConstantTerm(new BooleanNode(null, true))); foreach (ISet set in leftjoin.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join Console.WriteLine("Join LHS-RHS"); join = m.Join(n); foreach (ISet set in join.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a LeftOuterJoin Console.WriteLine("LeftJoin LHS-RHS"); leftjoin = m.LeftJoin(n, new ConstantTerm(new BooleanNode(null, true))); foreach (ISet set in leftjoin.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Produce Console.WriteLine("Product LHS-RHS"); BaseMultiset product = m.Product(n); foreach (ISet set in product.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Join to Self Console.WriteLine("Product LHS-D"); product = m.Product(d); foreach (ISet set in product.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); //Try a Union Console.WriteLine("Union LHS-RHS"); BaseMultiset union = m.Union(n); foreach (ISet set in union.Sets) { Console.WriteLine(set.ToString()); } Console.WriteLine(); }
/// <summary> /// Internal method which evaluates the Graph Pattern /// </summary> /// <param name="origContext">Evaluation Context</param> /// <remarks> /// We only ever need to evaluate the Graph Pattern once to get the Results /// </remarks> private void EvaluateInternal(SparqlEvaluationContext origContext) { this._result = null; //We must take a copy of the original context as otherwise we can have strange results SparqlEvaluationContext context = new SparqlEvaluationContext(origContext.Query, origContext.Data); context.InputMultiset = origContext.InputMultiset; context.OutputMultiset = new Multiset(); this._lastInput = context.InputMultiset.GetHashCode(); this._lastCount = context.InputMultiset.Count; //REQ: Optimise the algebra here ISparqlAlgebra existsClause = this._pattern.ToAlgebra(); this._result = context.Evaluate(existsClause); //This is the new algorithm which is also correct but is O(3n) so much faster and scalable //Downside is that it does require more memory than the old algorithm this._joinVars = origContext.InputMultiset.Variables.Where(v => this._result.Variables.Contains(v)).ToList(); if (this._joinVars.Count == 0) { return; } List <MultiDictionary <INode, List <int> > > values = new List <MultiDictionary <INode, List <int> > >(); List <List <int> > nulls = new List <List <int> >(); foreach (System.String var in this._joinVars) { values.Add(new MultiDictionary <INode, List <int> >(new FastVirtualNodeComparer())); nulls.Add(new List <int>()); } //First do a pass over the LHS Result to find all possible values for joined variables foreach (ISet x in origContext.InputMultiset.Sets) { int i = 0; foreach (System.String var in this._joinVars) { INode value = x[var]; if (value != null) { List <int> ids; if (values[i].TryGetValue(value, out ids)) { ids.Add(x.ID); } else { values[i].Add(value, new List <int> { x.ID }); } } else { nulls[i].Add(x.ID); } i++; } } //Then do a pass over the RHS and work out the intersections this._exists = new HashSet <int>(); foreach (ISet y in this._result.Sets) { IEnumerable <int> possMatches = null; int i = 0; foreach (System.String var in this._joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i][value].Concat(nulls[i]) : possMatches.Intersect(values[i][value].Concat(nulls[i]))); } else { possMatches = Enumerable.Empty <int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? origContext.InputMultiset.SetIDs : possMatches.Intersect(origContext.InputMultiset.SetIDs)); } i++; } if (possMatches == null) { continue; } //Look at possible matches, if is a valid match then mark the set as having an existing match //Don't reconsider sets which have already been marked as having an existing match foreach (int poss in possMatches) { if (this._exists.Contains(poss)) { continue; } if (origContext.InputMultiset[poss].IsCompatibleWith(y, this._joinVars)) { this._exists.Add(poss); } } } }
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { bool defGraphOk = false; bool datasetOk = false; try { //First evaluate the WHERE pattern to get the affected bindings ISparqlAlgebra where = this._wherePattern.ToAlgebra(); if (context.Commands != null) { where = context.Commands.ApplyAlgebraOptimisers(where); } //Set Active Graph for the WHERE based upon the WITH clause //Don't bother if there are USING URIs as these would override any Active Graph we set here //so we can save ourselves the effort of doing this if (!this.UsingUris.Any()) { if (this._graphUri != null) { context.Data.SetActiveGraph(this._graphUri); defGraphOk = true; } else { context.Data.SetActiveGraph((Uri)null); defGraphOk = true; } } //We need to make a dummy SparqlQuery object since if the Command has used any //USING/USING NAMEDs along with GRAPH clauses then the algebra needs to have the //URIs available to it which it gets from the Query property of the Context //object SparqlQuery query = new SparqlQuery(); foreach (Uri u in this.UsingUris) { query.AddDefaultGraph(u); } foreach (Uri u in this.UsingNamedUris) { query.AddNamedGraph(u); } SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data, context.QueryProcessor); if (this.UsingUris.Any()) { //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs context.Data.SetActiveGraph(this._usingUris); datasetOk = true; } BaseMultiset results = queryContext.Evaluate(where); if (results is IdentityMultiset) { results = new SingletonMultiset(results.Variables); } if (this.UsingUris.Any()) { //If there are USING URIs reset the Active Graph afterwards //Also flag the dataset as no longer being OK as this flag is used in the finally //block to determine whether the Active Graph needs resetting which it may do if the //evaluation of the context.Data.ResetActiveGraph(); datasetOk = false; } //Reset Active Graph for the WHERE if (defGraphOk) { context.Data.ResetActiveGraph(); defGraphOk = false; } //Get the Graph from which we are deleting IGraph g = context.Data.GetModifiableGraph(this._graphUri); //Delete the Triples for each Solution foreach (ISet s in results.Sets) { List <Triple> deletedTriples = new List <Triple>(); //Triples from raw Triple Patterns try { ConstructContext constructContext = new ConstructContext(g, s, true); foreach (IConstructTriplePattern p in this._deletePattern.TriplePatterns.OfType <IConstructTriplePattern>()) { try { deletedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we get an error here then we couldn't construct a specific Triple //so we continue anyway } } g.Retract(deletedTriples); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in this._deletePattern.ChildGraphPatterns) { deletedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: String graphVar = gp.GraphSpecifier.Value.Substring(1); if (s.ContainsVariable(graphVar)) { INode temp = s[graphVar]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } //If the Dataset doesn't contain the Graph then no need to do the Deletions if (!context.Data.HasGraph(UriFactory.Create(graphUri))) { continue; } //Do the actual Deletions IGraph h = context.Data.GetModifiableGraph(UriFactory.Create(graphUri)); ConstructContext constructContext = new ConstructContext(h, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType <IConstructTriplePattern>()) { try { deletedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we get an error here then we couldn't construct a specific //triple so we continue anyway } } h.Retract(deletedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } } } } finally { //If the Dataset was set and an error occurred in doing the WHERE clause then //we'll need to Reset the Active Graph if (datasetOk) { context.Data.ResetActiveGraph(); } if (defGraphOk) { context.Data.ResetActiveGraph(); } } }
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(); } }