Removes GraphPattern::Sequence

Redundant with GraphPattern::Join.
Let's keep optimization related structs in the evaluation plan.
pull/171/head
Tpt 3 years ago
parent bb5431b545
commit 27d73f7ee2
  1. 14
      lib/src/sparql/plan_builder.rs
  2. 22
      spargebra/src/algebra.rs
  3. 46
      spargebra/src/parser.rs

@ -69,20 +69,6 @@ impl<'a> PlanBuilder<'a> {
object: self.pattern_value_from_term_or_variable(object, variables), object: self.pattern_value_from_term_or_variable(object, variables),
graph_name: graph_name.clone(), graph_name: graph_name.clone(),
}, },
GraphPattern::Sequence(elements) => elements
.iter()
.map(|e| self.build_for_graph_pattern(e, variables, graph_name))
.reduce(|left, right| {
Ok(PlanNode::ForLoopJoin {
left: Rc::new(left?),
right: Rc::new(right?),
})
})
.unwrap_or_else(|| {
Ok(PlanNode::StaticBindings {
tuples: vec![EncodedTuple::with_capacity(variables.len())],
})
})?,
GraphPattern::Join { left, right } => PlanNode::HashJoin { GraphPattern::Join { left, right } => PlanNode::HashJoin {
left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?), left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?),
right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?), right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?),

@ -522,9 +522,6 @@ pub enum GraphPattern {
path: PropertyPathExpression, path: PropertyPathExpression,
object: TermPattern, object: TermPattern,
}, },
/// A set of SPARQL patterns that can be evaluated sequentially
/// It is a safe case of [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin)
Sequence(Vec<GraphPattern>),
/// [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin) /// [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin)
Join { left: Box<Self>, right: Box<Self> }, Join { left: Box<Self>, right: Box<Self> },
/// [LeftJoin](https://www.w3.org/TR/sparql11-query/#defn_algLeftJoin) /// [LeftJoin](https://www.w3.org/TR/sparql11-query/#defn_algLeftJoin)
@ -613,14 +610,6 @@ impl GraphPattern {
object.fmt_sse(f)?; object.fmt_sse(f)?;
write!(f, ")") write!(f, ")")
} }
Self::Sequence(elements) => {
write!(f, "(sequence")?;
for e in elements {
write!(f, " ")?;
e.fmt_sse(f)?;
}
write!(f, ")")
}
Self::Join { left, right } => { Self::Join { left, right } => {
write!(f, "(join ")?; write!(f, "(join ")?;
left.fmt_sse(f)?; left.fmt_sse(f)?;
@ -815,12 +804,6 @@ impl fmt::Display for GraphPattern {
path, path,
object, object,
} => write!(f, "{} {} {} .", subject, path, object), } => write!(f, "{} {} {} .", subject, path, object),
Self::Sequence(elements) => {
for e in elements {
write!(f, "{} ", e)?;
}
Ok(())
}
Self::Join { left, right } => { Self::Join { left, right } => {
if matches!( if matches!(
right.as_ref(), right.as_ref(),
@ -963,11 +946,6 @@ impl GraphPattern {
lookup_triple_pattern_variables(o, callback) lookup_triple_pattern_variables(o, callback)
} }
} }
Self::Sequence(elements) => {
for e in elements {
e.lookup_in_scope_variables(callback);
}
}
Self::Join { left, right } Self::Join { left, right }
| Self::LeftJoin { left, right, .. } | Self::LeftJoin { left, right, .. }
| Self::Union { left, right } => { | Self::Union { left, right } => {

@ -277,7 +277,10 @@ fn build_bgp(patterns: Vec<TripleOrPathPattern>) -> GraphPattern {
if !bgp.is_empty() { if !bgp.is_empty() {
elements.push(GraphPattern::Bgp { patterns: bgp }); elements.push(GraphPattern::Bgp { patterns: bgp });
} }
new_sequence(elements) elements
.into_iter()
.reduce(new_join)
.unwrap_or_else(GraphPattern::default)
} }
enum TripleOrPathPattern { enum TripleOrPathPattern {
@ -368,38 +371,15 @@ fn new_join(l: GraphPattern, r: GraphPattern) -> GraphPattern {
} }
} }
// Some optimizations
// TODO: move to a specific optimizer pass
match (l, r) { match (l, r) {
(GraphPattern::Bgp { patterns: mut pl }, GraphPattern::Bgp { patterns: pr }) => { (GraphPattern::Bgp { patterns: mut pl }, GraphPattern::Bgp { patterns: pr }) => {
pl.extend(pr); pl.extend(pr);
GraphPattern::Bgp { patterns: pl } GraphPattern::Bgp { patterns: pl }
} }
(GraphPattern::Sequence(mut e1), GraphPattern::Sequence(e2)) => { (GraphPattern::Bgp { patterns }, other) | (other, GraphPattern::Bgp { patterns })
e1.extend_from_slice(&e2); if patterns.is_empty() =>
GraphPattern::Sequence(e1)
}
(GraphPattern::Sequence(mut e), r)
if matches!(r, GraphPattern::Bgp { .. } | GraphPattern::Path { .. }) =>
{ {
e.push(r); other
GraphPattern::Sequence(e)
}
(l, GraphPattern::Sequence(mut e))
if matches!(l, GraphPattern::Bgp { .. } | GraphPattern::Path { .. }) =>
{
e.insert(0, l);
GraphPattern::Sequence(e)
}
(
GraphPattern::Graph { name: g1, inner: l },
GraphPattern::Graph { name: g2, inner: r },
) if g1 == g2 => {
// We merge identical graphs
GraphPattern::Graph {
name: g1,
inner: Box::new(new_join(*l, *r)),
}
} }
(l, r) => GraphPattern::Join { (l, r) => GraphPattern::Join {
left: Box::new(l), left: Box::new(l),
@ -408,14 +388,6 @@ fn new_join(l: GraphPattern, r: GraphPattern) -> GraphPattern {
} }
} }
fn new_sequence(elements: Vec<GraphPattern>) -> GraphPattern {
match elements.len() {
0 => GraphPattern::default(),
1 => elements.into_iter().next().unwrap(),
_ => GraphPattern::Sequence(elements),
}
}
fn not_empty_fold<T>( fn not_empty_fold<T>(
iter: impl Iterator<Item = T>, iter: impl Iterator<Item = T>,
combine: impl Fn(T, T) -> T, combine: impl Fn(T, T) -> T,
@ -1219,14 +1191,14 @@ parser! {
//[40] //[40]
rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {? rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {?
let pattern = new_sequence(d.iter().map(|q| { let pattern = d.iter().map(|q| {
let bgp = GraphPattern::Bgp { patterns: vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())] }; let bgp = GraphPattern::Bgp { patterns: vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())] };
match &q.graph_name { match &q.graph_name {
GraphNamePattern::NamedNode(graph_name) => GraphPattern::Graph { name: graph_name.clone().into(), inner: Box::new(bgp) }, GraphNamePattern::NamedNode(graph_name) => GraphPattern::Graph { name: graph_name.clone().into(), inner: Box::new(bgp) },
GraphNamePattern::DefaultGraph => bgp, GraphNamePattern::DefaultGraph => bgp,
GraphNamePattern::Variable(graph_name) => GraphPattern::Graph { name: graph_name.clone().into(), inner: Box::new(bgp) }, GraphNamePattern::Variable(graph_name) => GraphPattern::Graph { name: graph_name.clone().into(), inner: Box::new(bgp) },
} }
}).collect()); }).reduce(new_join).unwrap_or_else(GraphPattern::default);
let delete = d.into_iter().map(GroundQuadPattern::try_from).collect::<Result<Vec<_>,_>>().map_err(|_| "Blank nodes are not allowed in DELETE WHERE")?; let delete = d.into_iter().map(GroundQuadPattern::try_from).collect::<Result<Vec<_>,_>>().map_err(|_| "Blank nodes are not allowed in DELETE WHERE")?;
Ok(vec![GraphUpdateOperation::DeleteInsert { Ok(vec![GraphUpdateOperation::DeleteInsert {
delete, delete,

Loading…
Cancel
Save