/// <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); 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 (Set 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.GetMapping(s[v].Graph))).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(); } }
/// <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 (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 queryContext.OutputMultiset.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: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; 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(); } }