/// <summary> /// Optimises an Algebra to a form that uses <see cref="LazyBgp">LazyBgp</see> where possible /// </summary> /// <param name="algebra">Algebra</param> /// <param name="depth">Depth</param> /// <returns></returns> /// <remarks> /// <para> /// By transforming a query to use <see cref="LazyBgp">LazyBgp</see> we can achieve much more efficient processing of some forms of queries /// </para> /// </remarks> protected override ISparqlAlgebra OptimiseInternal(ISparqlAlgebra algebra, int depth) { try { ISparqlAlgebra temp; //Note this first test is specifically for the default BGP implementation since other optimisers //may run before us and replace with other BGP implementations which we don't want to replace hence //why we don't check for IBgp here if (algebra is Bgp) { temp = new LazyBgp(((Bgp)algebra).TriplePatterns); } //else if (algebra is ILeftJoin) //{ // ILeftJoin join = (ILeftJoin)algebra; // temp = new LeftJoin(this.OptimiseInternal(join.Lhs, depth + 1), join.Rhs, ((LeftJoin)algebra).Filter); //} else if (algebra is IUnion) { IUnion join = (IUnion)algebra; temp = new LazyUnion(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); } else if (algebra is IJoin) { IJoin join = (IJoin)algebra; if (join.Lhs.Variables.IsDisjoint(join.Rhs.Variables)) { //If the sides of the Join are disjoint then can fully transform the join since we only need to find the requisite number of //solutions on either side to guarantee a product which meets/exceeds the required results //temp = new Join(this.OptimiseInternal(join.Lhs, depth + 1), this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.Transform(this); } else { //If the sides are not disjoint then the LHS must be fully evaluated but the RHS need only produce enough //solutions that match //temp = new Join(join.Lhs, this.OptimiseInternal(join.Rhs, depth + 1)); temp = join.TransformRhs(this); } } else if (algebra is Algebra.Graph) { //Algebra.Graph g = (Algebra.Graph)algebra; //temp = new Algebra.Graph(this.OptimiseInternal(g.InnerAlgebra, depth + 1), g.GraphSpecifier); IUnaryOperator op = (IUnaryOperator)algebra; temp = op.Transform(this); } else { temp = algebra; } return temp; } catch { //If the Optimise fails return the current algebra return algebra; } }
public void SparqlStreamingBgpSelectEvaluation() { //Get the Data we want to query TripleStore store = new TripleStore(); Graph g = new Graph(); FileLoader.Load(g, "InferenceTest.ttl"); store.Add(g); //g = new Graph(); //FileLoader.Load(g, "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 VariableExpressionTerm("?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 (Set 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(); } }