public void SparqlOptimiserQueryFilterPlacement5() { // given var query = new SparqlQuery { QueryType = SparqlQueryType.Select }; query.AddVariable(new SparqlVariable("s", true)); query.RootGraphPattern = new GraphPattern(); var subj = new VariablePattern("s"); var rdfType = new NodeMatchPattern(new UriNode(null, new Uri(RdfSpecsHelper.RdfType))); var type = new VariablePattern("type"); var triplePattern = new TriplePattern(subj, rdfType, type); query.RootGraphPattern.AddTriplePattern(triplePattern); query.RootGraphPattern.AddFilter(new UnaryExpressionFilter(new InFunction(new VariableTerm("type"), new[] { new ConstantTerm(new UriNode(null, new Uri("http://example.com/Type1"))), new ConstantTerm(new UriNode(null, new Uri("http://example.com/Type2"))), new ConstantTerm(new UriNode(null, new Uri("http://example.com/Type3"))) }))); // when var algebra = query.ToAlgebra(); // then Assert.IsType <Select>(algebra); Assert.IsType <Filter>(((Select)algebra).InnerAlgebra); }
/// <summary> /// Formats a Pattern Item in nicely formatted SPARQL syntax /// </summary> /// <param name="item">Pattern Item</param> /// <param name="segment">Triple Pattern Segment</param> /// <returns></returns> public virtual String Format(PatternItem item, TripleSegment?segment) { if (item is VariablePattern) { return(item.ToString()); } else if (item is NodeMatchPattern) { NodeMatchPattern match = (NodeMatchPattern)item; return(this.Format(match.Node, segment)); } else if (item is FixedBlankNodePattern) { if (segment != null) { if (segment == TripleSegment.Predicate) { throw new RdfOutputException("Cannot format a Fixed Blank Node Pattern Item as the Predicate of a Triple Pattern as Blank Nodes are not permitted as Predicates"); } } return(item.ToString()); } else if (item is BlankNodePattern) { return(item.ToString()); } else { throw new RdfOutputException("Unable to Format an unknown PatternItem implementation as a String"); } }
/// <summary> /// Used to extract the patterns that make up a <see cref="FullTextPattern">FullTextPattern</see> /// </summary> /// <param name="patterns">Triple Patterns</param> /// <returns></returns> internal static List <FullTextPattern> ExtractPatterns(IEnumerable <ITriplePattern> patterns) { //Do a first pass which simply looks to find any pf:textMatch properties Dictionary <PatternItem, List <TriplePattern> > ftPatterns = new Dictionary <PatternItem, List <TriplePattern> >(); List <TriplePattern> ps = patterns.OfType <TriplePattern>().ToList(); if (ps.Count == 0) { return(new List <FullTextPattern>()); } foreach (TriplePattern tp in ps) { NodeMatchPattern predItem = tp.Predicate as NodeMatchPattern; if (predItem == null) { continue; } IUriNode predNode = predItem.Node as IUriNode; if (predNode == null) { continue; } if (predNode.Uri.ToString().Equals(FullTextMatchPredicateUri)) { ftPatterns.Add(tp.Subject, new List <TriplePattern>()); ftPatterns[tp.Subject].Add(tp); } } //Remove any Patterns we found from the original patterns foreach (List <TriplePattern> fps in ftPatterns.Values) { fps.ForEach(tp => ps.Remove(tp)); } if (ftPatterns.Count == 0) { return(new List <FullTextPattern>()); } //Now for each pf:textMatch property we found do a further search to see if we are using //the (?match ?score) form or the {'text' threshold limit) form rather than the simple ?match form foreach (PatternItem key in ftPatterns.Keys) { if (key.VariableName != null && key.VariableName.StartsWith("_:")) { ExtractRelatedPatterns(key, key, ps, ftPatterns); } PatternItem searchKey = ftPatterns[key].First().Object; if (searchKey.VariableName != null && searchKey.VariableName.StartsWith("_:")) { ExtractRelatedPatterns(key, searchKey, ps, ftPatterns); } } return((from key in ftPatterns.Keys select new FullTextPattern(ftPatterns[key])).ToList()); }
/// <summary> /// Creates a Triple Pattern /// </summary> /// <param name="subj">Subject</param> /// <param name="path">Property Path</param> /// <param name="obj">Object</param> /// <returns></returns> public ITriplePattern GetTriplePattern(PatternItem subj, ISparqlPath path, PatternItem obj) { if (path is Property) { NodeMatchPattern nodeMatch = new NodeMatchPattern(((Property)path).Predicate); return(new TriplePattern(subj, nodeMatch, obj)); } else { return(new PropertyPathPattern(subj, path, obj)); } }
/// <summary> /// Used to help extract the patterns that make up a property function pattern. /// </summary> /// <param name="key">Key.</param> /// <param name="subj">Subject.</param> /// <param name="ps">Patterns.</param> /// <param name="funcInfo">Function Information.</param> /// <param name="argList">Argument List to add discovered arguments to.</param> static void ExtractRelatedPatterns(PatternItem key, PatternItem subj, List <IMatchTriplePattern> ps, Dictionary <PatternItem, PropertyFunctionInfo> funcInfo, List <PatternItem> argList) { bool recurse = true, any = false, argSeen = false; PatternItem nextSubj = subj; while (recurse) { any = false; foreach (IMatchTriplePattern tp in ps.ToList()) { if (tp.Subject.VariableName == nextSubj.VariableName) { NodeMatchPattern predItem = tp.Predicate as NodeMatchPattern; if (predItem == null) { continue; } IUriNode predNode = predItem.Node as IUriNode; if (predNode == null) { continue; } if (!argSeen && predNode.Uri.AbsoluteUri.Equals(RdfSpecsHelper.RdfListFirst)) { funcInfo[key].Patterns.Add(tp); argList.Add(tp.Object); ps.Remove(tp); any = true; argSeen = true; } else if (argSeen && predNode.Uri.AbsoluteUri.Equals(RdfSpecsHelper.RdfListRest)) { funcInfo[key].Patterns.Add(tp); ps.Remove(tp); recurse = tp.Object.VariableName != null; nextSubj = tp.Object; any = true; argSeen = false; } } } if (!any) { recurse = false; } if (nextSubj == null) { throw new RdfQueryException("Failed to find expected rdf:rest property"); } } }
/// <summary> /// Used to help extract the patterns that make up a <see cref="FullTextPattern">FullTextPattern</see> /// </summary> /// <param name="key">Key</param> /// <param name="subj">Subject</param> /// <param name="ps">Patterns</param> /// <param name="ftPatterns">Discovered Full Text Patterns</param> internal static void ExtractRelatedPatterns(PatternItem key, PatternItem subj, List <TriplePattern> ps, Dictionary <PatternItem, List <TriplePattern> > ftPatterns) { bool recurse = true; PatternItem nextSubj = null; foreach (TriplePattern tp in ps) { if (tp.Subject.VariableName == subj.VariableName) { NodeMatchPattern predItem = tp.Predicate as NodeMatchPattern; if (predItem == null) { continue; } IUriNode predNode = predItem.Node as IUriNode; if (predNode == null) { continue; } if (predNode.Uri.ToString().Equals(RdfSpecsHelper.RdfListFirst)) { ftPatterns[key].Add(tp); } else if (predNode.Uri.ToString().Equals(RdfSpecsHelper.RdfListRest)) { ftPatterns[key].Add(tp); recurse = tp.Object.VariableName != null; nextSubj = tp.Object; } } } ftPatterns[key].ForEach(tp => ps.Remove(tp)); if (nextSubj == null) { throw new RdfQueryException("Failed to find expected rdf:rest property"); } if (recurse) { ExtractRelatedPatterns(key, nextSubj, ps, ftPatterns); } }
private ISparqlAlgebra GetAlgebraUntransformed(ISparqlPath path, INode start, INode end) { PatternItem x, y; if (start == null) { x = new VariablePattern("?x"); } else { x = new NodeMatchPattern(start); } if (end == null) { y = new VariablePattern("?y"); } else { y = new NodeMatchPattern(end); } return(new Bgp(new PropertyPathPattern(x, path, y))); }
private ISparqlAlgebra GetAlgebra(ISparqlPath path, INode start, INode end) { PatternItem x, y; if (start == null) { x = new VariablePattern("?x"); } else { x = new NodeMatchPattern(start); } if (end == null) { y = new VariablePattern("?y"); } else { y = new NodeMatchPattern(end); } PathTransformContext context = new PathTransformContext(x, y); return(path.ToAlgebra(context)); }
/// <summary> /// Optimises the algebra so that all Node terms are virtualised /// </summary> /// <param name="algebra">Algebra</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); TNodeID nullID = this._provider.NullID; for (int i = 0; i < current.PatternCount; i++) { if (ps[i] is FilterPattern || ps[i] is BindPattern) { //First ensure that if we've found any other Triple Patterns up to this point //we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } if (ps[i] is FilterPattern) { result = new Filter(result, ((FilterPattern)ps[i]).Filter); } else { BindPattern bind = (BindPattern)ps[i]; result = new Extend(result, bind.AssignExpression, bind.VariableName); } } else { //Convert Terms in the Pattern into Virtual Nodes TriplePattern tp = (TriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = this._provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(this.CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } } if (result is NullOperator) { return(result); } else if (patterns.Count == current.PatternCount) { //If count of remaining patterns same as original pattern count there was no optimisation //to do so return as is return(current); } else if (patterns.Count > 0) { //If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
/// <summary> /// Used to extract the patterns that make up property functions. /// </summary> /// <param name="patterns">Triple Patterns.</param> /// <param name="localFactories">Locally scoped factories.</param> /// <returns></returns> public static List <IPropertyFunctionPattern> ExtractPatterns(IEnumerable <ITriplePattern> patterns, IEnumerable <IPropertyFunctionFactory> localFactories) { // Do a first pass which simply looks to find any 'magic' properties Dictionary <PatternItem, PropertyFunctionInfo> funcInfo = new Dictionary <PatternItem, PropertyFunctionInfo>(); List <IMatchTriplePattern> ps = patterns.OfType <IMatchTriplePattern>().ToList(); if (ps.Count == 0) { return(new List <IPropertyFunctionPattern>()); } foreach (IMatchTriplePattern tp in ps) { NodeMatchPattern predItem = tp.Predicate as NodeMatchPattern; if (predItem == null) { continue; } IUriNode predNode = predItem.Node as IUriNode; if (predNode == null) { continue; } if (PropertyFunctionFactory.IsPropertyFunction(predNode.Uri, localFactories)) { PropertyFunctionInfo info = new PropertyFunctionInfo(predNode.Uri); info.Patterns.Add(tp); funcInfo.Add(tp.Subject, info); } } // Remove any Patterns we found from the original patterns foreach (PropertyFunctionInfo info in funcInfo.Values) { info.Patterns.ForEach(tp => ps.Remove(tp)); } if (funcInfo.Count == 0) { return(new List <IPropertyFunctionPattern>()); } // Now for each 'magic' property we found do a further search to see if we are using // the collection forms to provide extended arguments foreach (PatternItem key in funcInfo.Keys) { if (key.VariableName != null && key.VariableName.StartsWith("_:")) { // If LHS is a blank node may be collection form int count = funcInfo[key].Patterns.Count; ExtractRelatedPatterns(key, key, ps, funcInfo, funcInfo[key].SubjectArgs); if (funcInfo[key].Patterns.Count == count) { // If no further patterns found just single LHS argument funcInfo[key].SubjectArgs.Add(key); } } else { // Otherwise key is the only LHS argument funcInfo[key].SubjectArgs.Add(key); } PatternItem searchKey = funcInfo[key].Patterns.First().Object; if (searchKey.VariableName != null && searchKey.VariableName.StartsWith("_:")) { // If RHS is a blank node may be collection form int count = funcInfo[key].Patterns.Count; ExtractRelatedPatterns(key, searchKey, ps, funcInfo, funcInfo[key].ObjectArgs); if (funcInfo[key].Patterns.Count == count) { // If no further patterns found just single RHS argument funcInfo[key].ObjectArgs.Add(searchKey); } } else { // Otherwise single RHS argument funcInfo[key].ObjectArgs.Add(searchKey); } } // Now try to create actual property functions List <IPropertyFunctionPattern> propFunctions = new List <IPropertyFunctionPattern>(); foreach (PatternItem key in funcInfo.Keys) { IPropertyFunctionPattern propFunc; if (PropertyFunctionFactory.TryCreatePropertyFunction(funcInfo[key], localFactories, out propFunc)) { propFunctions.Add(propFunc); } } return(propFunctions); }
/// <summary> /// Optimises the algebra so that all Node terms are virtualised. /// </summary> /// <param name="algebra">Algebra.</param> /// <returns></returns> public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else if (algebra is IBgp) { IBgp current = (IBgp)algebra; if (current.PatternCount == 0) { return(current); } else { ISparqlAlgebra result = new Bgp(); List <ITriplePattern> patterns = new List <ITriplePattern>(); List <ITriplePattern> ps = new List <ITriplePattern>(current.TriplePatterns.ToList()); TNodeID nullID = _provider.NullID; for (int i = 0; i < current.PatternCount; i++) { if (ps[i].PatternType == TriplePatternType.Filter || ps[i].PatternType == TriplePatternType.BindAssignment || ps[i].PatternType == TriplePatternType.LetAssignment) { // First ensure that if we've found any other Triple Patterns up to this point // we dump this into a BGP and join with the result so far if (patterns.Count > 0) { result = Join.CreateJoin(result, new Bgp(patterns)); patterns.Clear(); } if (ps[i].PatternType == TriplePatternType.Filter) { result = new Filter(result, new UnaryExpressionFilter(Transform(((IFilterPattern)ps[i]).Filter.Expression))); } else { IAssignmentPattern bind = (IAssignmentPattern)ps[i]; result = new Extend(result, Transform(bind.AssignExpression), bind.VariableName); } } else if (ps[i].PatternType == TriplePatternType.Match) { // Convert Terms in the Pattern into Virtual Nodes IMatchTriplePattern tp = (IMatchTriplePattern)ps[i]; PatternItem subj, pred, obj; if (tp.Subject is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Subject).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { subj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Subject).Node)); } } else { subj = tp.Subject; } if (tp.Predicate is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Predicate).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { pred = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Predicate).Node)); } } else { pred = tp.Predicate; } if (tp.Object is NodeMatchPattern) { TNodeID id = _provider.GetID(((NodeMatchPattern)tp.Object).Node); if (id == null || id.Equals(nullID)) { result = new NullOperator(current.Variables); break; } else { obj = new NodeMatchPattern(CreateVirtualNode(id, ((NodeMatchPattern)tp.Object).Node)); } } else { obj = tp.Object; } patterns.Add(new TriplePattern(subj, pred, obj)); } else { // Can't optimize if other pattern types involved return(current); } } if (result is NullOperator) { return(result); } else if (patterns.Count > 0) { // If any patterns left at end join as a BGP with result so far result = Join.CreateJoin(result, new Bgp(patterns)); return(result); } else { return(result); } } } else if (algebra is ITerminalOperator) { return(algebra); } else { return(algebra); } }
public ISparqlAlgebra Optimise(ISparqlAlgebra algebra) { try { if (algebra is Bgp) { var bgp = (Bgp)algebra; if (bgp.TriplePatterns.OfType <FilterPattern>().Count() == 1) { var filter = bgp.TriplePatterns.OfType <FilterPattern>().Select(fp => fp.Filter).First(); string var; INode term; bool equals; if (IsIdentityExpression(filter.Expression, out var, out term, out equals)) { if (equals) { var triplePatterns = new List <ITriplePattern>(); foreach (var tp in bgp.TriplePatterns) { if (tp is FilterPattern) { continue; } if (tp is TriplePattern) { var triplePattern = (TriplePattern)tp; if (triplePattern.Variables.Contains(var)) { PatternItem subjPattern = triplePattern.Subject, predPattern = triplePattern.Predicate, objPattern = triplePattern.Object; if (var.Equals(triplePattern.Subject.VariableName)) { subjPattern = new NodeMatchPattern(term); } if (var.Equals(triplePattern.Predicate.VariableName)) { predPattern = new NodeMatchPattern(term); } if (var.Equals(triplePattern.Object.VariableName)) { objPattern = new NodeMatchPattern(term); } triplePatterns.Add(new TriplePattern(subjPattern, predPattern, objPattern)); } else { triplePatterns.Add(triplePattern); } } else { triplePatterns.Add(tp); } } return(new Bgp(triplePatterns)); } } } } else if (algebra is IAbstractJoin) { return(((IAbstractJoin)algebra).Transform(this)); } else if (algebra is IUnaryOperator) { return(((IUnaryOperator)algebra).Transform(this)); } else { return(algebra); } } catch { return(algebra); } return(algebra); }
private bool OptimiseBgp(Bgp bgp, out ISparqlAlgebra optimisedAlgebra) { if (bgp.TriplePatterns.OfType <FilterPattern>().Count() == 1) { var filter = bgp.TriplePatterns.OfType <FilterPattern>().Select(fp => fp.Filter).First(); string var; INode term; bool equals; if (IsIdentityExpression(filter.Expression, out var, out term, out @equals)) { if (@equals) { var triplePatterns = new List <ITriplePattern>(); foreach (var tp in bgp.TriplePatterns) { if (tp is FilterPattern) { continue; } if (tp is TriplePattern) { var triplePattern = (TriplePattern)tp; if (triplePattern.Variables.Contains(var)) { PatternItem subjPattern = triplePattern.Subject, predPattern = triplePattern.Predicate, objPattern = triplePattern.Object; if (var.Equals(triplePattern.Subject.VariableName)) { subjPattern = new NodeMatchPattern(term); } if (var.Equals(triplePattern.Predicate.VariableName)) { predPattern = new NodeMatchPattern(term); } if (var.Equals(triplePattern.Object.VariableName)) { objPattern = new NodeMatchPattern(term); } triplePatterns.Add(new TriplePattern(subjPattern, predPattern, objPattern)); } else { triplePatterns.Add(triplePattern); } } else { triplePatterns.Add(tp); } } { optimisedAlgebra = new Bgp(triplePatterns); return(true); } } } } optimisedAlgebra = bgp; return(false); }