Adds support for SPARQL 1.1 MINUS

pull/10/head
Tpt 5 years ago
parent 58aa9c2090
commit 0577b644c0
  1. 53
      lib/src/sparql/eval.rs
  2. 12
      lib/src/sparql/plan.rs
  3. 10
      lib/src/sparql/plan_builder.rs
  4. 1
      lib/tests/sparql_test_cases.rs

@ -20,6 +20,7 @@ use rio_api::model as rio;
use rust_decimal::{Decimal, RoundingStrategy};
use sha1::Sha1;
use sha2::{Sha256, Sha384, Sha512};
use std::cmp::min;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::collections::HashSet;
@ -207,6 +208,17 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
buffered_results: errors,
})
}
PlanNode::AntiJoin { left, right } => {
//TODO: dumb implementation
let right: Vec<_> = self
.eval_plan(&*right, from.clone())
.filter_map(|result| result.ok())
.collect();
Box::new(AntiJoinIterator {
left_iter: self.eval_plan(&*left, from),
right,
})
}
PlanNode::LeftJoin {
left,
right,
@ -1713,6 +1725,22 @@ fn combine_tuples(a: &[Option<EncodedTerm>], b: &[Option<EncodedTerm>]) -> Optio
}
}
fn are_tuples_compatible_and_not_disjointed(
a: &[Option<EncodedTerm>],
b: &[Option<EncodedTerm>],
) -> bool {
let mut found_intersection = false;
for i in 0..min(a.len(), b.len()) {
if let (Some(a_value), Some(b_value)) = (a[i], b[i]) {
if a_value != b_value {
return false;
}
found_intersection = true;
}
}
found_intersection
}
struct JoinIterator<'a> {
left: Vec<EncodedTuple>,
right_iter: EncodedTuplesIterator<'a>,
@ -1739,6 +1767,31 @@ impl<'a> Iterator for JoinIterator<'a> {
}
}
struct AntiJoinIterator<'a> {
left_iter: EncodedTuplesIterator<'a>,
right: Vec<EncodedTuple>,
}
impl<'a> Iterator for AntiJoinIterator<'a> {
type Item = Result<EncodedTuple>;
fn next(&mut self) -> Option<Result<EncodedTuple>> {
loop {
match self.left_iter.next()? {
Ok(left_tuple) => {
let exists_compatible_right = self.right.iter().any(|right_tuple| {
are_tuples_compatible_and_not_disjointed(&left_tuple, right_tuple)
});
if !exists_compatible_right {
return Some(Ok(left_tuple));
}
}
Err(error) => return Some(Err(error)),
}
}
}
}
struct LeftJoinIterator<'a, S: StoreConnection + 'a> {
eval: SimpleEvaluator<S>,
right_plan: &'a PlanNode,

@ -20,6 +20,10 @@ pub enum PlanNode {
left: Box<PlanNode>,
right: Box<PlanNode>,
},
AntiJoin {
left: Box<PlanNode>,
right: Box<PlanNode>,
},
Filter {
child: Box<PlanNode>,
expression: PlanExpression,
@ -109,11 +113,9 @@ impl PlanNode {
child.add_variables(set);
}
}
PlanNode::Join { left, right } => {
left.add_variables(set);
right.add_variables(set);
}
PlanNode::LeftJoin { left, right, .. } => {
PlanNode::Join { left, right }
| PlanNode::AntiJoin { left, right }
| PlanNode::LeftJoin { left, right, .. } => {
left.add_variables(set);
right.add_variables(set);
}

@ -113,7 +113,15 @@ impl<'a, S: StoreConnection> PlanBuilder<'a, S> {
position: variable_key(variables, &v),
expression: self.build_for_expression(e, variables, graph_name)?,
},
GraphPattern::Minus(_a, _b) => unimplemented!(),
GraphPattern::Minus(a, b) => PlanNode::AntiJoin {
left: Box::new(self.build_for_graph_pattern(
a,
input.clone(),
variables,
graph_name,
)?),
right: Box::new(self.build_for_graph_pattern(b, input, variables, graph_name)?),
},
GraphPattern::Service(_n, _p, _s) => unimplemented!(),
GraphPattern::AggregateJoin(_g, _a) => unimplemented!(),
GraphPattern::Data(bs) => PlanNode::StaticBindings {

@ -91,6 +91,7 @@ fn sparql_w3c_query_evaluation_testsuite() -> Result<()> {
"http://www.w3.org/2009/sparql/docs/tests/data-sparql11/construct/manifest.ttl",
"http://www.w3.org/2009/sparql/docs/tests/data-sparql11/exists/manifest.ttl",
"http://www.w3.org/2009/sparql/docs/tests/data-sparql11/functions/manifest.ttl",
"http://www.w3.org/2009/sparql/docs/tests/data-sparql11/negation/manifest.ttl",
];
let test_blacklist = vec![

Loading…
Cancel
Save