Implements SPARQL CONSTRUCT

pull/10/head
Tpt 6 years ago
parent e3be82e7e7
commit 9ae5f4fcb7
  1. 3
      lib/src/sparql/algebra.rs
  2. 86
      lib/src/sparql/eval.rs
  3. 24
      lib/src/sparql/mod.rs
  4. 87
      lib/src/sparql/plan.rs
  5. 4
      lib/tests/sparql_test_cases.rs

@ -3,7 +3,6 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt; use std::fmt;
use std::ops::Add; use std::ops::Add;
use store::MemoryGraph;
use utils::Escaper; use utils::Escaper;
use uuid::Uuid; use uuid::Uuid;
use Result; use Result;
@ -1577,5 +1576,5 @@ impl fmt::Display for Query {
pub enum QueryResult<'a> { pub enum QueryResult<'a> {
Bindings(BindingsIterator<'a>), Bindings(BindingsIterator<'a>),
Boolean(bool), Boolean(bool),
Graph(MemoryGraph), Graph(Box<dyn Iterator<Item = Result<Triple>> + 'a>),
} }

@ -2,6 +2,7 @@ use chrono::DateTime;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use language_tags::LanguageTag; use language_tags::LanguageTag;
use model::BlankNode; use model::BlankNode;
use model::Triple;
use num_traits::identities::Zero; use num_traits::identities::Zero;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use num_traits::One; use num_traits::One;
@ -59,6 +60,20 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
} }
} }
pub fn evaluate_construct_plan<'a>(
&'a self,
plan: &'a PlanNode,
construct: &'a [TripleTemplate],
) -> Result<QueryResult<'a>> {
Ok(QueryResult::Graph(Box::new(ConstructIterator {
store: self.store.clone(),
iter: self.eval_plan(plan, vec![]),
template: construct,
buffered_results: Vec::default(),
bnodes: Vec::default(),
})))
}
fn eval_plan<'a>(&self, node: &'a PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'a> { fn eval_plan<'a>(&self, node: &'a PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'a> {
match node { match node {
PlanNode::Init => Box::new(once(Ok(from))), PlanNode::Init => Box::new(once(Ok(from))),
@ -1017,3 +1032,74 @@ impl<'a, S: EncodedQuadsStore> Iterator for UnionIterator<'a, S> {
self.next() self.next()
} }
} }
struct ConstructIterator<'a, S: EncodedQuadsStore> {
store: Arc<S>,
iter: EncodedTuplesIterator<'a>,
template: &'a [TripleTemplate],
buffered_results: Vec<Result<Triple>>,
bnodes: Vec<BlankNode>,
}
impl<'a, S: EncodedQuadsStore> Iterator for ConstructIterator<'a, S> {
type Item = Result<Triple>;
fn next(&mut self) -> Option<Result<Triple>> {
if let Some(result) = self.buffered_results.pop() {
return Some(result);
}
{
let tuple = match self.iter.next()? {
Ok(tuple) => tuple,
Err(error) => return Some(Err(error)),
};
let encoder = self.store.encoder();
for template in self.template {
if let (Some(subject), Some(predicate), Some(object)) = (
get_triple_template_value(&template.subject, &tuple, &mut self.bnodes),
get_triple_template_value(&template.predicate, &tuple, &mut self.bnodes),
get_triple_template_value(&template.object, &tuple, &mut self.bnodes),
) {
self.buffered_results
.push(decode_triple(&encoder, subject, predicate, object));
} else {
self.buffered_results.clear(); //No match, we do not output any triple for this row
break;
}
}
self.bnodes.clear(); //We do not reuse old bnodes
}
self.next()
}
}
fn get_triple_template_value(
selector: &TripleTemplateValue,
tuple: &[Option<EncodedTerm>],
bnodes: &mut Vec<BlankNode>,
) -> Option<EncodedTerm> {
match selector {
TripleTemplateValue::Constant(term) => Some(*term),
TripleTemplateValue::Variable(v) => get_tuple_value(*v, tuple),
TripleTemplateValue::BlankNode(id) => {
//TODO use resize_with
while *id >= tuple.len() {
bnodes.push(BlankNode::default())
}
tuple[*id]
}
}
}
fn decode_triple<S: BytesStore>(
encoder: &Encoder<S>,
subject: EncodedTerm,
predicate: EncodedTerm,
object: EncodedTerm,
) -> Result<Triple> {
Ok(Triple::new(
encoder.decode_named_or_blank_node(subject)?,
encoder.decode_named_node(predicate)?,
encoder.decode_term(object)?,
))
}

@ -9,6 +9,7 @@ use sparql::eval::SimpleEvaluator;
use sparql::parser::read_sparql_query; use sparql::parser::read_sparql_query;
use sparql::plan::PlanBuilder; use sparql::plan::PlanBuilder;
use sparql::plan::PlanNode; use sparql::plan::PlanNode;
use sparql::plan::TripleTemplate;
use std::io::Read; use std::io::Read;
use store::encoded::EncodedQuadsStore; use store::encoded::EncodedQuadsStore;
use store::encoded::StoreDataset; use store::encoded::StoreDataset;
@ -51,6 +52,19 @@ impl<S: EncodedQuadsStore> SparqlDataset for StoreDataset<S> {
evaluator: SimpleEvaluator::new(store), evaluator: SimpleEvaluator::new(store),
} }
} }
Query::Construct {
construct,
algebra,
dataset,
} => {
let store = self.encoded();
let (plan, variables) = PlanBuilder::build(&*store, &algebra)?;
SimplePreparedQuery::Construct {
plan,
construct: PlanBuilder::build_graph_template(&*store, &construct, variables)?,
evaluator: SimpleEvaluator::new(store),
}
}
_ => unimplemented!(), _ => unimplemented!(),
}) })
} }
@ -66,6 +80,11 @@ pub enum SimplePreparedQuery<S: EncodedQuadsStore> {
plan: PlanNode, plan: PlanNode,
evaluator: SimpleEvaluator<S>, evaluator: SimpleEvaluator<S>,
}, },
Construct {
plan: PlanNode,
construct: Vec<TripleTemplate>,
evaluator: SimpleEvaluator<S>,
},
} }
impl<S: EncodedQuadsStore> PreparedQuery for SimplePreparedQuery<S> { impl<S: EncodedQuadsStore> PreparedQuery for SimplePreparedQuery<S> {
@ -77,6 +96,11 @@ impl<S: EncodedQuadsStore> PreparedQuery for SimplePreparedQuery<S> {
evaluator, evaluator,
} => evaluator.evaluate_select_plan(&plan, &variables), } => evaluator.evaluate_select_plan(&plan, &variables),
SimplePreparedQuery::Ask { plan, evaluator } => evaluator.evaluate_ask_plan(&plan), SimplePreparedQuery::Ask { plan, evaluator } => evaluator.evaluate_ask_plan(&plan),
SimplePreparedQuery::Construct {
plan,
construct,
evaluator,
} => evaluator.evaluate_construct_plan(&plan, &construct),
} }
} }
} }

@ -305,6 +305,20 @@ pub enum Comparator {
Desc(PlanExpression), Desc(PlanExpression),
} }
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub struct TripleTemplate {
pub subject: TripleTemplateValue,
pub predicate: TripleTemplateValue,
pub object: TripleTemplateValue,
}
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub enum TripleTemplateValue {
Constant(EncodedTerm),
BlankNode(usize),
Variable(usize),
}
pub struct PlanBuilder<'a, S: EncodedQuadsStore> { pub struct PlanBuilder<'a, S: EncodedQuadsStore> {
store: &'a S, store: &'a S,
} }
@ -321,6 +335,14 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> {
Ok((plan, variables)) Ok((plan, variables))
} }
pub fn build_graph_template(
store: &S,
template: &[TriplePattern],
mut variables: Vec<Variable>,
) -> Result<Vec<TripleTemplate>> {
PlanBuilder { store }.build_for_graph_template(template, &mut variables)
}
fn build_for_graph_pattern( fn build_for_graph_pattern(
&self, &self,
pattern: &GraphPattern, pattern: &GraphPattern,
@ -704,6 +726,71 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> {
Ok(result) Ok(result)
}).collect() }).collect()
} }
fn build_for_graph_template(
&self,
template: &[TriplePattern],
variables: &mut Vec<Variable>,
) -> Result<Vec<TripleTemplate>> {
let mut bnodes = Vec::default();
template
.into_iter()
.map(|triple| {
Ok(TripleTemplate {
subject: self.template_value_from_term_or_variable(
&triple.subject,
variables,
&mut bnodes,
)?,
predicate: self.template_value_from_named_node_or_variable(
&triple.predicate,
variables,
&mut bnodes,
)?,
object: self.template_value_from_term_or_variable(
&triple.object,
variables,
&mut bnodes,
)?,
})
}).collect()
}
fn template_value_from_term_or_variable(
&self,
term_or_variable: &TermOrVariable,
variables: &mut Vec<Variable>,
bnodes: &mut Vec<Variable>,
) -> Result<TripleTemplateValue> {
Ok(match term_or_variable {
TermOrVariable::Term(term) => {
TripleTemplateValue::Constant(self.store.encoder().encode_term(term)?)
}
TermOrVariable::Variable(variable) => if variable.has_name() {
TripleTemplateValue::Variable(variable_key(variables, variable))
} else {
TripleTemplateValue::BlankNode(variable_key(bnodes, variable))
},
})
}
fn template_value_from_named_node_or_variable(
&self,
named_node_or_variable: &NamedNodeOrVariable,
variables: &mut Vec<Variable>,
bnodes: &mut Vec<Variable>,
) -> Result<TripleTemplateValue> {
Ok(match named_node_or_variable {
NamedNodeOrVariable::NamedNode(term) => {
TripleTemplateValue::Constant(self.store.encoder().encode_named_node(term)?)
}
NamedNodeOrVariable::Variable(variable) => if variable.has_name() {
TripleTemplateValue::Variable(variable_key(variables, variable))
} else {
TripleTemplateValue::BlankNode(variable_key(bnodes, variable))
},
})
}
} }
fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize { fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize {

@ -99,6 +99,8 @@ fn sparql_w3c_query_evaluation_testsuite() {
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/bound/manifest.ttl", "http://www.w3.org/2001/sw/DataAccess/tests/data-r2/bound/manifest.ttl",
).unwrap(), ).unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/cast/manifest.ttl").unwrap(), Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/cast/manifest.ttl").unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest.ttl")
.unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest.ttl")
.unwrap(), .unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/expr-builtin/manifest.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/expr-builtin/manifest.ttl")
@ -341,7 +343,7 @@ mod rs {
fn to_graph(result: QueryResult, with_order: bool) -> Result<MemoryGraph> { fn to_graph(result: QueryResult, with_order: bool) -> Result<MemoryGraph> {
match result { match result {
QueryResult::Graph(graph) => Ok(graph), QueryResult::Graph(graph) => graph.collect(),
QueryResult::Boolean(value) => { QueryResult::Boolean(value) => {
let graph = MemoryGraph::default(); let graph = MemoryGraph::default();
let result_set = BlankNode::default(); let result_set = BlankNode::default();

Loading…
Cancel
Save