Ejemplo n.º 1
0
        /// <summary>
        /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations
        /// </summary>
        /// <param name="multiset">Multiset</param>
        /// <param name="other">Other Multiset</param>
        /// <param name="timeout">Timeout, if &lt;=0 no timeout is used and product will be computed sychronously</param>
        /// <returns></returns>
        public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout)
        {
            if (other is IdentityMultiset) return multiset;
            if (other is NullMultiset) return other;
            if (other.IsEmpty) return new NullMultiset();

            if (timeout <= 0)
            {
                return multiset.Product(other);
            }

            //Invoke using an Async call
            Multiset productSet = new Multiset();
            StopToken stop = new StopToken();
            GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct);
            IAsyncResult r = d.BeginInvoke(multiset, other, productSet, stop, null, null);

            //Wait
            int t = (int)Math.Min(timeout, Int32.MaxValue);
            r.AsyncWaitHandle.WaitOne(t);
            if (!r.IsCompleted)
            {
                stop.ShouldStop = true;
                r.AsyncWaitHandle.WaitOne();
            }
            return productSet;
        }
Ejemplo n.º 2
0
        public void SparqlAlgebraJoinMultiVariable1()
        {
            ISet x = new Set();

            x.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x")));
            x.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y")));

            ISet y1 = new Set();

            y1.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x")));
            y1.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y")));
            ISet y2 = new Set();

            y2.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x")));
            y2.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y")));

            BaseMultiset lhs = new Multiset();

            lhs.Add(x);
            BaseMultiset rhs = new Multiset();

            rhs.Add(y1);
            rhs.Add(y2);

            BaseMultiset joined = lhs.Join(rhs);

            Assert.AreEqual(2, joined.Count);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Does a Product of this Multiset and another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Product(BaseMultiset other)
        {
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            Multiset productSet = new Multiset();

            foreach (ISet x in this.Sets)
            {
                foreach (ISet y in other.Sets)
                {
                    productSet.Add(x.Join(y));
                }
            }
            return(productSet);
        }
Ejemplo n.º 4
0
        public void SparqlAlgebraJoinMultiVariable4()
        {
            ISet x1 = new Set();

            x1.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x1")));
            x1.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y1")));
            ISet x2 = new Set();

            x2.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x2")));
            x2.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y2")));

            ISet y1 = new Set();

            y1.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x1")));
            y1.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y2")));
            ISet y2 = new Set();

            y2.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x2")));
            y2.Add("b", this._factory.CreateUriNode(UriFactory.Create("http://y1")));

            BaseMultiset lhs = new Multiset();

            lhs.Add(x1);
            lhs.Add(x2);
            BaseMultiset rhs = new Multiset();

            rhs.Add(y1);
            rhs.Add(y2);

            BaseMultiset joined = lhs.Join(rhs);

            Assert.Equal(0, joined.Count);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Does a Union of this Multiset and another Multiset.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <returns></returns>
        public override BaseMultiset Union(BaseMultiset other)
        {
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            if (other.IsEmpty)
            {
                return(this);
            }

            Multiset m = new Multiset();

            foreach (ISet s in this.Sets)
            {
                m.Add(s.Copy());
            }
            foreach (ISet s in other.Sets)
            {
                m.Add(s.Copy());
            }
            return(m);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Does a Product of this Multiset and another Multiset.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <returns></returns>
        public virtual BaseMultiset Product(BaseMultiset other)
        {
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

#if NET40
            if (Options.UsePLinqEvaluation)
            {
                // Determine partition sizes so we can do a parallel product
                // Want to parallelize over whichever side is larger
                PartitionedMultiset partitionedSet;
                if (this.Count >= other.Count)
                {
                    partitionedSet = new PartitionedMultiset(this.Count, other.Count);
                    this.Sets.AsParallel().ForAll(x => this.EvalProduct(x, other, partitionedSet));
                }
                else
                {
                    partitionedSet = new PartitionedMultiset(other.Count, this.Count);
                    other.Sets.AsParallel().ForAll(y => this.EvalProduct(y, this, partitionedSet));
                }
                return(partitionedSet);
            }
            else
            {
                // Use serial calculation which is likely to really suck for big products
                Multiset productSet = new Multiset();
                foreach (ISet x in this.Sets)
                {
                    foreach (ISet y in other.Sets)
                    {
                        productSet.Add(x.Join(y));
                    }
                }
                return(productSet);
            }
#else
            // Use serial calculation which is likely to really suck for big products
            var productSet = new Multiset();
            foreach (var x in Sets)
            {
                foreach (var y in other.Sets)
                {
                    productSet.Add(x.Join(y));
                }
            }
            return(productSet);
#endif
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations
        /// </summary>
        /// <param name="multiset">Multiset</param>
        /// <param name="other">Other Multiset</param>
        /// <param name="timeout">Timeout, if &lt;=0 no timeout is used and product will be computed sychronously</param>
        /// <returns></returns>
        public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout)
        {
            if (other is IdentityMultiset)
            {
                return(multiset);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            //If no timeout use default implementation
            if (timeout <= 0)
            {
                return(multiset.Product(other));
            }

            //Otherwise Invoke using an Async call
            BaseMultiset productSet;

#if NET40 && !SILVERLIGHT
            if (Options.UsePLinqEvaluation)
            {
                if (multiset.Count >= other.Count)
                {
                    productSet = new PartitionedMultiset(multiset.Count, other.Count);
                }
                else
                {
                    productSet = new PartitionedMultiset(other.Count, multiset.Count);
                }
            }
            else
            {
#endif
            productSet = new Multiset();
#if NET40 && !SILVERLIGHT
        }
#endif
            StopToken stop            = new StopToken();
            GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct);
            IAsyncResult r            = d.BeginInvoke(multiset, other, productSet, stop, null, null);

            //Wait
            int t = (int)Math.Min(timeout, Int32.MaxValue);
            r.AsyncWaitHandle.WaitOne(t);
            if (!r.IsCompleted)
            {
                stop.ShouldStop = true;
                r.AsyncWaitHandle.WaitOne();
            }
            return(productSet);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Calculates the product of two multi-sets asynchronously with a timeout to restrict long running computations.
        /// </summary>
        /// <param name="multiset">Multiset.</param>
        /// <param name="other">Other Multiset.</param>
        /// <param name="timeout">Timeout, if &lt;=0 no timeout is used and product will be computed synchronously.</param>
        /// <returns></returns>
        public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout)
        {
            if (other is IdentityMultiset)
            {
                return(multiset);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            // If no timeout use default implementation
            if (timeout <= 0)
            {
                return(multiset.Product(other));
            }

            // Otherwise Invoke using an Async call
            BaseMultiset productSet;

            if (Options.UsePLinqEvaluation)
            {
                if (multiset.Count >= other.Count)
                {
                    productSet = new PartitionedMultiset(multiset.Count, other.Count);
                }
                else
                {
                    productSet = new PartitionedMultiset(other.Count, multiset.Count);
                }
            }
            else
            {
                productSet = new Multiset();
            }

            var stop        = new StopToken();
            var t           = (int)Math.Min(timeout, int.MaxValue);
            var productTask = Task.Factory.StartNew(() => GenerateProduct(multiset, other, productSet, stop));

            if (!productTask.Wait(t))
            {
                stop.ShouldStop = true;
                productTask.Wait();
            }

            return(productSet);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Joins this Multiset to another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Join(BaseMultiset other)
        {
            //If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            //If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset)
            {
                return(other);
            }
            //If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(this.Product(other));
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            foreach (ISet x in this.Sets)
            {
                //For sets to be compatible for every joinable variable they must either have a null for the
                //variable in one of the sets or if they have values the values must be equal

                ////This first check is to try speed things up, it looks whether there are solutions that may match
                ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do
                ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue;

                IEnumerable <ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));

                foreach (ISet y in ys)
                {
                    joinedSet.Add(x.Join(y));
                }
            }
            return(joinedSet);
        }
Ejemplo n.º 10
0
        public void SparqlAlgebraJoinSingleVariable1()
        {
            ISet x = new Set();

            x.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x")));

            BaseMultiset lhs = new Multiset();

            lhs.Add(x);
            BaseMultiset rhs = new Multiset();

            rhs.Add(x);

            BaseMultiset joined = lhs.Join(rhs);

            Assert.AreEqual(1, joined.Count);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset MinusJoin(BaseMultiset other)
        {
            //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            //If the other Multiset is disjoint then minus-ing it also doesn't alter this set
            if (this.IsDisjointWith(other))
            {
                return(this);
            }

            //Find the Variables that are to be used for Joining
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(this.Product(other));
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            foreach (ISet x in this.Sets)
            {
                //New Minus logic based on the improved Join() logic
                bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));

                //If no compatible sets then this set is preserved
                if (!minus)
                {
                    joinedSet.Add(x);
                }
            }
            return(joinedSet);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations
        /// </summary>
        /// <param name="multiset">Multiset</param>
        /// <param name="other">Other Multiset</param>
        /// <param name="timeout">Timeout, if &lt;=0 no timeout is used and product will be computed sychronously</param>
        /// <returns></returns>
        public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout)
        {
            if (other is IdentityMultiset)
            {
                return(multiset);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            if (timeout <= 0)
            {
                return(multiset.Product(other));
            }

            //Invoke using an Async call
            Multiset  productSet      = new Multiset();
            StopToken stop            = new StopToken();
            GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct);
            IAsyncResult            r = d.BeginInvoke(multiset, other, productSet, stop, null, null);

            //Wait
            int t = (int)Math.Min(timeout, Int32.MaxValue);

            r.AsyncWaitHandle.WaitOne(t);
            if (!r.IsCompleted)
            {
                stop.ShouldStop = true;
                r.AsyncWaitHandle.WaitOne();
            }
            return(productSet);
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Creates a new Multiset Handler
 /// </summary>
 /// <param name="mset">Multiset</param>
 public MultisetHandler(Multiset mset)
 {
     if (mset == null) throw new ArgumentNullException("mset", "Multiset to load into cannot be null");
     this._mset = mset;
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="expr">Expression</param>
        /// <returns></returns>
        public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr)
        {
            //If the Other is the Identity/Null Multiset the result is this Multiset
            if (other is IdentityMultiset) return this;
            if (other is NullMultiset) return this;
            if (other.IsEmpty) return this;

            Multiset joinedSet = new Multiset();
            LeviathanLeftJoinBinder binder = new LeviathanLeftJoinBinder(joinedSet);
            SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder);

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0)
            {
                //Calculate a Product filtering as we go
                foreach (ISet x in this.Sets)
                {
                    bool standalone = false;
                    foreach (ISet y in other.Sets)
                    {
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone) joinedSet.Add(x.Copy());
                }
            }
            else
            {
                //This is the old algorithm which is correct but has complexity O(n^2) so it scales terribly
                //foreach (ISet x in this.Sets)
                //{
                //    IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));
                //    bool standalone = false;
                //    int i = 0;
                //    foreach (ISet y in ys)
                //    {
                //        i++;
                //        ISet z = x.Join(y);
                //        try
                //        {
                //            joinedSet.Add(z);
                //            if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                //            {
                //                joinedSet.Remove(z.ID);
                //                standalone = true;
                //            }
                //        }
                //        catch
                //        {
                //            joinedSet.Remove(z.ID);
                //            standalone = true;
                //        }
                //    }
                //    if (standalone || i == 0) joinedSet.Add(x);
                //}

                //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable
                //Downside is that it does require more memory than the old algorithm
                List<HashTable<INode, int>> values = new List<HashTable<INode, int>>();
                List<List<int>> nulls = new List<List<int>>();
                foreach (String var in joinVars)
                {
                    values.Add(new HashTable<INode, int>(HashTableBias.Enumeration));
                    nulls.Add(new List<int>());
                }

                //First do a pass over the LHS Result to find all possible values for joined variables
                HashSet<int> matched = new HashSet<int>();
                HashSet<int> standalone = new HashSet<int>();
                foreach (ISet x in this.Sets)
                {
                    int i = 0;
                    foreach (String var in joinVars)
                    {
                        INode value = x[var];
                        if (value != null)
                        {
                            values[i].Add(value, x.ID);
                        }
                        else
                        {
                            nulls[i].Add(x.ID);
                        }
                        i++;
                    }
                }

                //Then do a pass over the RHS and work out the intersections
                foreach (ISet y in other.Sets)
                {
                    IEnumerable<int> possMatches = null;
                    int i = 0;
                    foreach (String var in joinVars)
                    {
                        INode value = y[var];
                        if (value != null)
                        {
                            if (values[i].ContainsKey(value))
                            {
                                possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                            }
                            else
                            {
                                possMatches = Enumerable.Empty<int>();
                                break;
                            }
                        }
                        else
                        {
                            //Don't forget that a null will be potentially compatible with everything
                            possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                        }
                        i++;
                    }
                    if (possMatches == null) continue;

                    //Now do the actual joins for the current set
                    //Note - We access the dictionary directly here because going through the this[int id] method
                    //incurs a Contains() call each time and we know the IDs must exist because they came from
                    //our dictionary originally!
                    foreach (int poss in possMatches)
                    {
                        if (this._sets[poss].IsCompatibleWith(y, joinVars))
                        {
                            ISet z = this._sets[poss].Join(y);
                            joinedSet.Add(z);
                            try
                            {
                                if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                                {
                                    joinedSet.Remove(z.ID);
                                    standalone.Add(poss);
                                }
                                else
                                {
                                    matched.Add(poss);
                                }
                            }
                            catch
                            {
                                joinedSet.Remove(z.ID);
                                standalone.Add(poss);
                            }
                        }
                    }
                }

                //Finally add in unmatched sets from LHS
                foreach (int id in this.SetIDs)
                {
                    if (!matched.Contains(id) || standalone.Contains(id)) joinedSet.Add(this._sets[id].Copy());
                }
            }
            return joinedSet;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Does a Product of this Multiset and another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Product(BaseMultiset other)
        {
            if (other is IdentityMultiset) return this;
            if (other is NullMultiset) return other;
            if (other.IsEmpty) return new NullMultiset();

            Multiset productSet = new Multiset();
            foreach (ISet x in this.Sets)
            {
                foreach (ISet y in other.Sets)
                {
                    productSet.Add(x.Join(y));
                }
            }
            return productSet;
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset result;

            //Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset?

            if (this._pattern is Bgp && ((Bgp)this._pattern).IsEmpty)
            {
                //Optimise the case where we have GRAPH ?g {} by not setting the Graph and just returning
                //a Null Multiset
                result = new NullMultiset();
            }
            else
            {
                bool datasetOk = false;
                try
                {
                    List<String> activeGraphs = new List<string>();

                    //Get the URIs of Graphs that should be evaluated over
                    if (this._graphSpecifier.TokenType != Token.VARIABLE)
                    {
                        switch (this._graphSpecifier.TokenType)
                        {
                            case Token.URI:
                            case Token.QNAME:
                                Uri activeGraphUri = UriFactory.Create(Tools.ResolveUriOrQName(this._graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri));
                                if (context.Data.HasGraph(activeGraphUri))
                                {
                                    //If the Graph is explicitly specified and there are FROM NAMED present then the Graph
                                    //URI must be in the graphs specified by a FROM NAMED or the result is null
                                    if (context.Query == null || !context.Query.NamedGraphs.Any() || context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u)))
                                    {
                                        //Either there was no Query
                                        //OR there were no Named Graphs (hence any Graph URI is permitted)
                                        //OR the specified URI was a Named Graph URI
                                        //In any case we can go ahead and set the active Graph
                                        activeGraphs.Add(activeGraphUri.ToString());
                                    }
                                    else
                                    {
                                        //The specified URI was not present in the Default/Named Graphs so return null
                                        context.OutputMultiset = new NullMultiset();
                                        return context.OutputMultiset;
                                    }
                                }
                                else
                                {
                                    //If specifies a specific Graph and not in the Dataset result is a null multiset
                                    context.OutputMultiset = new NullMultiset();
                                    return context.OutputMultiset;
                                }
                                break;
                            default:
                                throw new RdfQueryException("Cannot use a '" + this._graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause");
                        }
                    }
                    else
                    {
                        String gvar = this._graphSpecifier.Value.Substring(1);

                        //Watch out for the case in which the Graph Variable is not bound for all Sets in which case
                        //we still need to operate over all Graphs
                        if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null))
                        {
                            //If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs
                            List<Uri> graphUris = new List<Uri>();
                            foreach (ISet s in context.InputMultiset.Sets)
                            {
                                INode temp = s[gvar];
                                if (temp != null)
                                {
                                    if (temp.NodeType == NodeType.Uri)
                                    {
                                        activeGraphs.Add(temp.ToString());
                                        graphUris.Add(((IUriNode)temp).Uri);
                                    }
                                }
                            }
                        }
                        else
                        {
                            //Nothing yet bound to the Graph Variable so the Query is over all the named Graphs
                            if (context.Query != null && context.Query.NamedGraphs.Any())
                            {
                                //Query specifies one/more named Graphs
                                activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.ToString()));
                            }
                            else
                            {
                                //Query is over entire dataset/default Graph since no named Graphs are explicitly specified
                                activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString()));
                            }
                        }
                    }

                    //Remove all duplicates from Active Graphs to avoid duplicate results
                    activeGraphs = activeGraphs.Distinct().ToList();

                    //Evaluate the inner pattern
                    BaseMultiset initialInput = context.InputMultiset;
                    BaseMultiset finalResult = new Multiset();

                    //Evalute for each Graph URI and union the results
                    foreach (String uri in activeGraphs)
                    {
                        //Always use the same Input for each Graph URI and set that Graph to be the Active Graph
                        //Be sure to translate String.Empty back to the null URI to select the default graph
                        //correctly
                        context.InputMultiset = initialInput;
                        Uri currGraphUri = (uri.Equals(String.Empty)) ? null : UriFactory.Create(uri);

                        //Set Active Graph
                        if (currGraphUri == null)
                        {
                            //GRAPH operates over named graphs only so default graph gets skipped
                            continue;
                        }
                        else
                        {
                            //The result of the HasGraph() call is ignored we just make it so datasets with any kind of
                            //load on demand behaviour work properly
                            context.Data.HasGraph(currGraphUri);
                            //All we actually care about is setting the active graph
                            context.Data.SetActiveGraph(currGraphUri);
                        }
                        datasetOk = true;

                        //Evaluate for the current Active Graph
                        result = context.Evaluate(this._pattern);

                        //Merge the Results into our overall Results
                        if (result is NullMultiset || result is IdentityMultiset)
                        {
                            //Don't do anything
                        }
                        else
                        {
                            //If the Graph Specifier is a Variable then we must either bind the
                            //variable or eliminate solutions which have an incorrect value for it
                            if (this._graphSpecifier.TokenType == Token.VARIABLE)
                            {
                                String gvar = this._graphSpecifier.Value.Substring(1);
                                INode currGraph = (currGraphUri == null) ? null : new UriNode(null, currGraphUri);
                                foreach (int id in result.SetIDs.ToList())
                                {
                                    ISet s = result[id];
                                    if (s[gvar] == null)
                                    {
                                        //If Graph Variable is not yet bound for solution bind it
                                        s.Add(gvar, currGraph);
                                    }
                                    else if (!s[gvar].Equals(currGraph))
                                    {
                                        //If Graph Variable is bound for solution and doesn't match
                                        //current Graph then we have to remove the solution
                                        result.Remove(id);
                                    }
                                }
                            }
                            //Union solutions into the Results
                            finalResult.Union(result);
                        }

                        //Reset the Active Graph after each pass
                        context.Data.ResetActiveGraph();
                        datasetOk = false;
                    }

                    //Return the final result
                    if (finalResult.IsEmpty) finalResult = new NullMultiset();
                    context.OutputMultiset = finalResult;
                }
                finally
                {
                    if (datasetOk) context.Data.ResetActiveGraph();
                }
            }

            return context.OutputMultiset;
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made</param>
        /// <returns></returns>
        public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist)
        {
            //For EXISTS and NOT EXISTS if the other is the Identity then it has no effect
            if (other is IdentityMultiset) return this;
            if (mustExist)
            {
                //If an EXISTS then Null/Empty Other results in Null
                if (other is NullMultiset) return other;
                if (other.IsEmpty) return new NullMultiset();
            }
            else
            {
                //If a NOT EXISTS then Null/Empty results in this
                if (other is NullMultiset) return this;
                if (other.IsEmpty) return this;
            }

            //Find the Variables that are to be used for Joining
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0)
            {
                //All Disjoint Solutions are compatible
                if (mustExist)
                {
                    //If an EXISTS and disjoint then result is this
                    return this;
                }
                else
                {
                    //If a NOT EXISTS and disjoint then result is null
                    return new NullMultiset();
                }
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old algorithm which is correct but naive with worse case O(n^2)
            //foreach (ISet x in this.Sets)
            //{
            //    //New ExistsJoin() logic based on the improved Join() logic
            //    bool exists = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
            //    //bool exists = other.Sets.Any(s => s.IsCompatibleWith(x, joinVars));

            //    if (exists)
            //    {
            //        //If there are compatible sets and this is an EXIST then preserve the solution
            //        if (mustExist) joinedSet.Add(x);
            //    }
            //    else
            //    {
            //        //If there are no compatible sets and this is a NOT EXISTS then preserve the solution
            //        if (!mustExist) joinedSet.Add(x);
            //    }
            //}

            //This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List<HashTable<INode, int>> values = new List<HashTable<INode, int>>();
            List<List<int>> nulls = new List<List<int>>();
            foreach (String var in joinVars)
            {
                values.Add(new HashTable<INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List<int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            //Then do a pass over the RHS and work out the intersections
            HashSet<int> exists = new HashSet<int>();
            foreach (ISet y in other.Sets)
            {
                IEnumerable<int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty<int>();
                            break;
                        }
                    }
                    else
                    {
                        //Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                    }
                    i++;
                }
                if (possMatches == null) continue;

                //Look at possible matches, if is a valid match then mark the set as having an existing match
                //Don't reconsider sets which have already been marked as having an existing match
                foreach (int poss in possMatches)
                {
                    if (exists.Contains(poss)) continue;
                    if (this._sets[poss].IsCompatibleWith(y, joinVars))
                    {
                        exists.Add(poss);
                    }
                }
            }

            //Apply the actual exists
            if (exists.Count == this.Count)
            {
                //If number of sets that have a match is equal to number of sets then we're either returning everything or nothing
                if (mustExist)
                {
                    return this;
                }
                else
                {
                    return new NullMultiset();
                }
            }
            else
            {
                //Otherwise iterate
                foreach (ISet x in this.Sets)
                {
                    if (mustExist)
                    {
                        if (exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                    else
                    {
                        if (!exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                }
            }

            return joinedSet;
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset result;

            //Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset?

            if (this._pattern is Bgp && ((Bgp)this._pattern).IsEmpty)
            {
                //Optimise the case where we have GRAPH ?g {} by not setting the Graph and just returning
                //a Null Multiset
                result = new NullMultiset();
            }
            else
            {
                bool datasetOk = false;
                try
                {
                    List <String> activeGraphs = new List <string>();

                    //Get the URIs of Graphs that should be evaluated over
                    if (this._graphSpecifier.TokenType != Token.VARIABLE)
                    {
                        switch (this._graphSpecifier.TokenType)
                        {
                        case Token.URI:
                        case Token.QNAME:
                            Uri activeGraphUri = new Uri(Tools.ResolveUriOrQName(this._graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri));
                            if (context.Data.HasGraph(activeGraphUri))
                            {
                                //If the Graph is explicitly specified and there are FROM NAMED present then the Graph
                                //URI must be in the graphs specified by a FROM NAMED or the result is null
                                if (context.Query != null &&
                                    ((!context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) ||
                                     context.Query.DefaultGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u)) ||
                                     context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u)))
                                    )
                                {
                                    //Either there was no Query OR there were no Default/Named Graphs OR
                                    //the specified URI was either a Default/Named Graph URI
                                    //In any case we can go ahead and set the active Graph
                                    activeGraphs.Add(activeGraphUri.ToString());
                                }
                                else
                                {
                                    //The specified URI was not present in the Default/Named Graphs so return null
                                    context.OutputMultiset = new NullMultiset();
                                    return(context.OutputMultiset);
                                }
                            }
                            else
                            {
                                //If specifies a specific Graph and not in the Dataset result is a null multiset
                                context.OutputMultiset = new NullMultiset();
                                return(context.OutputMultiset);
                            }
                            break;

                        default:
                            throw new RdfQueryException("Cannot use a '" + this._graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause");
                        }
                    }
                    else
                    {
                        String gvar = this._graphSpecifier.Value.Substring(1);

                        //Watch out for the case in which the Graph Variable is not bound for all Sets in which case
                        //we still need to operate over all Graphs
                        if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null))
                        {
                            //If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs
                            List <Uri> graphUris = new List <Uri>();
                            foreach (ISet s in context.InputMultiset.Sets)
                            {
                                INode temp = s[gvar];
                                if (temp != null)
                                {
                                    if (temp.NodeType == NodeType.Uri)
                                    {
                                        activeGraphs.Add(temp.ToString());
                                        graphUris.Add(((IUriNode)temp).Uri);
                                    }
                                }
                            }
                        }
                        else
                        {
                            //Nothing yet bound to the Graph Variable so the Query is over all the named Graphs
                            if (context.Query != null && context.Query.NamedGraphs.Any())
                            {
                                //Query specifies one/more named Graphs
                                activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.ToString()));
                            }
                            else
                            {
                                //Query is over entire dataset/default Graph since no named Graphs are explicitly specified
                                activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString()));
                            }
                        }
                    }

                    //Remove all duplicates from Active Graphs to avoid duplicate results
                    activeGraphs = activeGraphs.Distinct().ToList();

                    //Evaluate the inner pattern
                    BaseMultiset initialInput = context.InputMultiset;
                    BaseMultiset finalResult  = new Multiset();

                    //Evalute for each Graph URI and union the results
                    foreach (String uri in activeGraphs)
                    {
                        //Always use the same Input for each Graph URI and set that Graph to be the Active Graph
                        //Be sure to translate String.Empty back to the null URI to select the default graph
                        //correctly
                        context.InputMultiset = initialInput;
                        Uri currGraphUri = (uri.Equals(String.Empty)) ? null : new Uri(uri);

                        //This bit of logic takes care of the fact that calling SetActiveGraph((Uri)null) resets the
                        //Active Graph to be the default graph which if the default graph is null is usually the Union of
                        //all Graphs in the Store
                        if (currGraphUri == null && context.Data.DefaultGraph == null && context.Data.UsesUnionDefaultGraph)
                        {
                            if (context.Data.HasGraph(null))
                            {
                                context.Data.SetActiveGraph(context.Data[null]);
                            }
                            else
                            {
                                continue;
                            }
                        }
                        else
                        {
                            context.Data.SetActiveGraph(currGraphUri);
                        }
                        datasetOk = true;

                        //Evaluate for the current Active Graph
                        result = context.Evaluate(this._pattern);

                        //Merge the Results into our overall Results
                        if (result is NullMultiset || result is IdentityMultiset)
                        {
                            //Don't do anything
                        }
                        else
                        {
                            //If the Graph Specifier is a Variable then we must either bind the
                            //variable or eliminate solutions which have an incorrect value for it
                            if (this._graphSpecifier.TokenType == Token.VARIABLE)
                            {
                                String gvar      = this._graphSpecifier.Value.Substring(1);
                                INode  currGraph = (currGraphUri == null) ? null : new UriNode(null, currGraphUri);
                                foreach (int id in result.SetIDs.ToList())
                                {
                                    ISet s = result[id];
                                    if (s[gvar] == null)
                                    {
                                        //If Graph Variable is not yet bound for solution bind it
                                        s.Add(gvar, currGraph);
                                    }
                                    else if (!s[gvar].Equals(currGraph))
                                    {
                                        //If Graph Variable is bound for solution and doesn't match
                                        //current Graph then we have to remove the solution
                                        result.Remove(id);
                                    }
                                }
                            }
                            //Union solutions into the Results
                            finalResult.Union(result);
                        }

                        //Reset the Active Graph after each pass
                        context.Data.ResetActiveGraph();
                        datasetOk = false;
                    }

                    //Return the final result
                    if (finalResult.IsEmpty)
                    {
                        finalResult = new NullMultiset();
                    }
                    context.OutputMultiset = finalResult;
                }
                finally
                {
                    if (datasetOk)
                    {
                        context.Data.ResetActiveGraph();
                    }
                }
            }

            return(context.OutputMultiset);
        }
Ejemplo n.º 19
0
 public virtual BaseMultiset GetMultiset(IStore store)
 {
     var ms = new Multiset(Columns);
     foreach (var row in Rows)
     {
         var set = new Set();
         for (int i = 0; i < Columns.Count; i++)
         {
             if (row[i] > 0)
             {
                 set.Add(Columns[i], MakeNode(store, row[i]));
             }
         }
         ms.Add(set);
     }
     return ms;
 }
Ejemplo n.º 20
0
        /// <summary>
        /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset MinusJoin(BaseMultiset other)
        {
            //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set
            if (other is IdentityMultiset) return this;
            if (other is NullMultiset) return this;
            //If the other Multiset is disjoint then minus-ing it also doesn't alter this set
            if (this.IsDisjointWith(other)) return this;

            //Find the Variables that are to be used for Joining
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0) return this.Product(other);

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();
            foreach (ISet x in this.Sets)
            {
                //New Minus logic based on the improved Join() logic
                bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));

                //If no compatible sets then this set is preserved
                if (!minus)
                {
                    joinedSet.Add(x);
                }
            }
            return joinedSet;
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <param name="expr">Expression.</param>
        /// <returns></returns>
        public virtual BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr)
        {
            // If the Other is the Identity/Null Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            if (other.IsEmpty)
            {
                return(this);
            }

            Multiset joinedSet                 = new Multiset();
            LeviathanLeftJoinBinder binder     = new LeviathanLeftJoinBinder(joinedSet);
            SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder);

            // Find the First Variable from this Multiset which is in both Multisets
            // If there is no Variable from this Multiset in the other Multiset then this
            // should be a Join operation instead of a LeftJoin
            List <String> joinVars = Variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
#if NET40
                if (Options.UsePLinqEvaluation && expr.CanParallelise)
                {
                    PartitionedMultiset partitionedSet = new PartitionedMultiset(this.Count, other.Count + 1);
                    this.Sets.AsParallel().ForAll(x => EvalLeftJoinProduct(x, other, partitionedSet, expr));
                    return(partitionedSet);
                }
#endif
                // Do a serial Left Join Product

                // Calculate a Product filtering as we go
                foreach (ISet x in Sets)
                {
                    bool standalone = false;
                    bool matched    = false;
                    foreach (ISet y in other.Sets)
                    {
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                            else
                            {
                                matched = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone && !matched)
                    {
                        joinedSet.Add(x.Copy());
                    }
                }
#if NET40
#endif
            }
            else
            {
                // This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable
                // Downside is that it does require more memory than the old algorithm
                List <MultiDictionary <INode, List <int> > > values = new List <MultiDictionary <INode, List <int> > >();
                List <List <int> > nulls = new List <List <int> >();
                foreach (String var in joinVars)
                {
                    joinedSet.AddVariable(var);
                    values.Add(new MultiDictionary <INode, List <int> >(new FastVirtualNodeComparer()));
                    nulls.Add(new List <int>());
                }

                // First do a pass over the RHS Result to find all possible values for joined variables
                foreach (ISet y in other.Sets)
                {
                    int i = 0;
                    foreach (String var in joinVars)
                    {
                        INode value = y[var];
                        if (value != null)
                        {
                            if (values[i].TryGetValue(value, out List <int> ids))
                            {
                                ids.Add(y.ID);
                            }
                            else
                            {
                                values[i].Add(value, new List <int> {
                                    y.ID
                                });
                            }
                        }
                        else
                        {
                            nulls[i].Add(y.ID);
                        }
                        i++;
                    }
                }

                // Then do a pass over the LHS and work out the intersections
#if NET40
                if (Options.UsePLinqEvaluation && expr.CanParallelise)
                {
                    this.Sets.AsParallel().ForAll(x => EvalLeftJoin(x, other, joinVars, values, nulls, joinedSet, subcontext, expr));
                }
                else
                {
                    // Use a Serial Left Join
                    foreach (ISet x in this.Sets)
                    {
                        this.EvalLeftJoin(x, other, joinVars, values, nulls, joinedSet, subcontext, expr);
                    }
                }
#else
                // Use a Serial Left Join
                foreach (var x in Sets)
                {
                    EvalLeftJoin(x, other, joinVars, values, nulls, joinedSet, subcontext, expr);
                }
#endif
            }
            return(joinedSet);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="expr">Expression</param>
        /// <returns></returns>
        public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr)
        {
            //If the Other is the Identity/Null Multiset the result is this Multiset
            if (other is IdentityMultiset) return this;
            if (other is NullMultiset) return this;
            if (other.IsEmpty) return this;

            Multiset joinedSet = new Multiset();
            LeviathanLeftJoinBinder binder = new LeviathanLeftJoinBinder(joinedSet);
            SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder);

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0)
            {
                //Calculate a Product filtering as we go
                foreach (ISet x in this.Sets)
                {
                    bool standalone = false;
                    foreach (ISet y in other.Sets)
                    {
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.EffectiveBooleanValue(subcontext, z.ID))
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone) joinedSet.Add(x);
                }
            }
            else
            {
                foreach (ISet x in this.Sets)
                {
                    IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));
                    bool standalone = false;
                    int i = 0;
                    foreach (ISet y in ys)
                    {
                        i++;
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.EffectiveBooleanValue(subcontext, z.ID))
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone || i == 0) joinedSet.Add(x);
                }
            }
            return joinedSet;
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made</param>
        /// <returns></returns>
        public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist)
        {
            //For EXISTS and NOT EXISTS if the other is the Identity then it has no effect
            if (other is IdentityMultiset) return this;
            if (mustExist)
            {
                //If an EXISTS then Null/Empty Other results in Null
                if (other is NullMultiset) return other;
                if (other.IsEmpty) return new NullMultiset();
            }
            else
            {
                //If a NOT EXISTS then Null/Empty results in this
                if (other is NullMultiset) return this;
                if (other.IsEmpty) return this;
            }

            //Find the Variables that are to be used for Joining
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0)
            {
                //All Disjoint Solutions are compatible
                if (mustExist)
                {
                    //If an EXISTS and disjoint then result is this
                    return this;
                }
                else
                {
                    //If a NOT EXISTS and disjoint then result is null
                    return new NullMultiset();
                }
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();
            foreach (ISet x in this.Sets)
            {
                //New ExistsJoin() logic based on the improved Join() logic
                bool exists = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //bool exists = other.Sets.Any(s => s.IsCompatibleWith(x, joinVars));

                if (exists)
                {
                    //If there are compatible sets and this is an EXIST then preserve the solution
                    if (mustExist) joinedSet.Add(x);
                }
                else
                {
                    //If there are no compatible sets and this is a NOT EXISTS then preserve the solution
                    if (!mustExist) joinedSet.Add(x);
                }
            }
            return joinedSet;
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Joins this Multiset to another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Join(BaseMultiset other)
        {
            //If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset) return this;
            //If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset) return other;
            //If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty) return new NullMultiset();

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0) return this.Product(other);

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();
            foreach (ISet x in this.Sets)
            {
                //For sets to be compatible for every joinable variable they must either have a null for the
                //variable in one of the sets or if they have values the values must be equal

                ////This first check is to try speed things up, it looks whether there are solutions that may match
                ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do
                ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue;

                IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));

                foreach (ISet y in ys)
                {
                    joinedSet.Add(x.Join(y));
                }
            }
            return joinedSet;
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made</param>
        /// <returns></returns>
        public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist)
        {
            //For EXISTS and NOT EXISTS if the other is the Identity then it has no effect
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (mustExist)
            {
                //If an EXISTS then Null/Empty Other results in Null
                if (other is NullMultiset)
                {
                    return(other);
                }
                if (other.IsEmpty)
                {
                    return(new NullMultiset());
                }
            }
            else
            {
                //If a NOT EXISTS then Null/Empty results in this
                if (other is NullMultiset)
                {
                    return(this);
                }
                if (other.IsEmpty)
                {
                    return(this);
                }
            }

            //Find the Variables that are to be used for Joining
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                //All Disjoint Solutions are compatible
                if (mustExist)
                {
                    //If an EXISTS and disjoint then result is this
                    return(this);
                }
                else
                {
                    //If a NOT EXISTS and disjoint then result is null
                    return(new NullMultiset());
                }
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old algorithm which is correct but naive with worse case O(n^2)
            //foreach (ISet x in this.Sets)
            //{
            //    //New ExistsJoin() logic based on the improved Join() logic
            //    bool exists = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
            //    //bool exists = other.Sets.Any(s => s.IsCompatibleWith(x, joinVars));

            //    if (exists)
            //    {
            //        //If there are compatible sets and this is an EXIST then preserve the solution
            //        if (mustExist) joinedSet.Add(x);
            //    }
            //    else
            //    {
            //        //If there are no compatible sets and this is a NOT EXISTS then preserve the solution
            //        if (!mustExist) joinedSet.Add(x);
            //    }
            //}

            //This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List <HashTable <INode, int> > values = new List <HashTable <INode, int> >();
            List <List <int> >             nulls  = new List <List <int> >();

            foreach (String var in joinVars)
            {
                values.Add(new HashTable <INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List <int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            //Then do a pass over the RHS and work out the intersections
            HashSet <int> exists = new HashSet <int>();

            foreach (ISet y in other.Sets)
            {
                IEnumerable <int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty <int>();
                            break;
                        }
                    }
                    else
                    {
                        //Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                    }
                    i++;
                }
                if (possMatches == null)
                {
                    continue;
                }

                //Look at possible matches, if is a valid match then mark the set as having an existing match
                //Don't reconsider sets which have already been marked as having an existing match
                foreach (int poss in possMatches)
                {
                    if (exists.Contains(poss))
                    {
                        continue;
                    }
                    if (this._sets[poss].IsCompatibleWith(y, joinVars))
                    {
                        exists.Add(poss);
                    }
                }
            }

            //Apply the actual exists
            if (exists.Count == this.Count)
            {
                //If number of sets that have a match is equal to number of sets then we're either returning everything or nothing
                if (mustExist)
                {
                    return(this);
                }
                else
                {
                    return(new NullMultiset());
                }
            }
            else
            {
                //Otherwise iterate
                foreach (ISet x in this.Sets)
                {
                    if (mustExist)
                    {
                        if (exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                    else
                    {
                        if (!exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                }
            }

            return(joinedSet);
        }
        /// <summary>
        /// Processes an INSERT/DELETE command
        /// </summary>
        /// <param name="cmd">Insert/Delete Command</param>
        public void ProcessModifyCommand(ModifyCommand cmd)
        {
            if (this._manager is IUpdateableGenericIOManager)
            {
                ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString());
            }
            else
            {
                if (this._manager is IQueryableGenericIOManager)
                {
                    //First build and make the query to get a Result Set
                    String queryText = "SELECT * WHERE " + cmd.WherePattern.ToString();
                    SparqlQueryParser parser = new SparqlQueryParser();
                    SparqlQuery query = parser.ParseFromString(queryText);
                    if (cmd.GraphUri != null && !cmd.UsingUris.Any()) query.AddDefaultGraph(cmd.GraphUri);
                    foreach (Uri u in cmd.UsingUris)
                    {
                        query.AddDefaultGraph(u);
                    }
                    foreach (Uri u in cmd.UsingNamedUris)
                    {
                        query.AddNamedGraph(u);
                    }

                    Object results = ((IQueryableGenericIOManager)this._manager).Query(query.ToString());
                    if (results is SparqlResultSet)
                    {
                        //Now need to transform the Result Set back to a Multiset
                        Multiset mset = new Multiset((SparqlResultSet)results);

                        //Generate the Triples for each Solution
                        List<Triple> deletedTriples = new List<Triple>();
                        Dictionary<String, List<Triple>> deletedGraphTriples = new Dictionary<string, List<Triple>>();
                        foreach (Set s in mset.Sets)
                        {
                            List<Triple> tempDeletedTriples = new List<Triple>();
                            try
                            {
                                ConstructContext context = new ConstructContext(null, s, true);
                                foreach (IConstructTriplePattern p in cmd.DeletePattern.TriplePatterns.OfType<IConstructTriplePattern>())
                                {
                                    try
                                    {
                                        tempDeletedTriples.Add(p.Construct(context));
                                    }
                                    catch (RdfQueryException)
                                    {
                                        //If we get an error here then it means we could not construct a specific
                                        //triple so we continue anyway
                                    }
                                }
                                deletedTriples.AddRange(tempDeletedTriples);
                            }
                            catch (RdfQueryException)
                            {
                                //If we get an error here this means we couldn't construct for this solution so the
                                //solution is ignored for this graph
                            }

                            //Triples from GRAPH clauses
                            foreach (GraphPattern gp in cmd.DeletePattern.ChildGraphPatterns)
                            {
                                tempDeletedTriples.Clear();
                                try
                                {
                                    String graphUri;
                                    switch (gp.GraphSpecifier.TokenType)
                                    {
                                        case Token.URI:
                                            graphUri = gp.GraphSpecifier.Value;
                                            break;
                                        case Token.VARIABLE:
                                            if (s.ContainsVariable(gp.GraphSpecifier.Value))
                                            {
                                                INode temp = s[gp.GraphSpecifier.Value.Substring(1)];
                                                if (temp == null)
                                                {
                                                    //If the Variable is not bound then skip
                                                    continue;
                                                }
                                                else if (temp.NodeType == NodeType.Uri)
                                                {
                                                    graphUri = temp.ToSafeString();
                                                }
                                                else
                                                {
                                                    //If the Variable is not bound to a URI then skip
                                                    continue;
                                                }
                                            }
                                            else
                                            {
                                                //If the Variable is not bound for this solution then skip
                                                continue;
                                            }
                                            break;
                                        default:
                                            //Any other Graph Specifier we have to ignore this solution
                                            continue;
                                    }
                                    if (!deletedGraphTriples.ContainsKey(graphUri)) deletedGraphTriples.Add(graphUri, new List<Triple>());
                                    ConstructContext context = new ConstructContext(null, s, true);
                                    foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>())
                                    {
                                        try
                                        {
                                            tempDeletedTriples.Add(p.Construct(context));
                                        }
                                        catch (RdfQueryException)
                                        {
                                            //If we throw an error this means we couldn't construct a specific
                                            //triple so we continue anyway
                                        }
                                    }
                                    deletedGraphTriples[graphUri].AddRange(tempDeletedTriples);
                                }
                                catch (RdfQueryException)
                                {
                                    //If we get an error here this means we couldn't construct for this solution so the
                                    //solution is ignored for this graph
                                }
                            }
                        }

                        //Generate the Triples for each Solution
                        List<Triple> insertedTriples = new List<Triple>();
                        Dictionary<String, List<Triple>> insertedGraphTriples = new Dictionary<string, List<Triple>>();
                        foreach (Set s in mset.Sets)
                        {
                            List<Triple> tempInsertedTriples = new List<Triple>();
                            try
                            {
                                ConstructContext context = new ConstructContext(null, s, true);
                                foreach (IConstructTriplePattern p in cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>())
                                {
                                    try
                                    {
                                        tempInsertedTriples.Add(p.Construct(context));
                                    }
                                    catch (RdfQueryException)
                                    {
                                        //If we get an error here then it means we couldn't construct a specific
                                        //triple so we continue anyway
                                    }
                                }
                                insertedTriples.AddRange(tempInsertedTriples);
                            }
                            catch (RdfQueryException)
                            {
                                //If we get an error here this means we couldn't construct for this solution so the
                                //solution is ignored for this graph
                            }

                            //Triples from GRAPH clauses
                            foreach (GraphPattern gp in cmd.InsertPattern.ChildGraphPatterns)
                            {
                                tempInsertedTriples.Clear();
                                try
                                {
                                    String graphUri;
                                    switch (gp.GraphSpecifier.TokenType)
                                    {
                                        case Token.URI:
                                            graphUri = gp.GraphSpecifier.Value;
                                            break;
                                        case Token.VARIABLE:
                                            if (s.ContainsVariable(gp.GraphSpecifier.Value))
                                            {
                                                INode temp = s[gp.GraphSpecifier.Value.Substring(1)];
                                                if (temp == null)
                                                {
                                                    //If the Variable is not bound then skip
                                                    continue;
                                                }
                                                else if (temp.NodeType == NodeType.Uri)
                                                {
                                                    graphUri = temp.ToSafeString();
                                                }
                                                else
                                                {
                                                    //If the Variable is not bound to a URI then skip
                                                    continue;
                                                }
                                            }
                                            else
                                            {
                                                //If the Variable is not bound for this solution then skip
                                                continue;
                                            }
                                            break;
                                        default:
                                            //Any other Graph Specifier we have to ignore this solution
                                            continue;
                                    }
                                    if (!insertedGraphTriples.ContainsKey(graphUri)) insertedGraphTriples.Add(graphUri, new List<Triple>());
                                    ConstructContext context = new ConstructContext(null, s, true);
                                    foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>())
                                    {
                                        try
                                        {
                                            tempInsertedTriples.Add(p.Construct(context));
                                        }
                                        catch (RdfQueryException)
                                        {
                                            //If we get an error here it means we couldn't construct a specific
                                            //triple so we continue anyway
                                        }
                                    }
                                    insertedGraphTriples[graphUri].AddRange(tempInsertedTriples);
                                }
                                catch (RdfQueryException)
                                {
                                    //If we get an error here this means we couldn't construct for this solution so the
                                    //solution is ignored for this graph
                                }
                            }
                        }

                        //Now decide how to apply the update
                        if (this._manager.UpdateSupported)
                        {
                            this._manager.UpdateGraph(cmd.GraphUri, insertedTriples, deletedTriples);
                            //We do these two operations sequentially even if in some cases they could be combined to ensure that the underlying
                            //Manager doesn't do any optimisations which would have the result of our updates not being properly applied
                            //e.g. ignoring Triples which are both asserted and retracted in one update
                            foreach (KeyValuePair<String, List<Triple>> graphDeletion in deletedGraphTriples)
                            {
                                this._manager.UpdateGraph(graphDeletion.Key, Enumerable.Empty<Triple>(), graphDeletion.Value);
                            }
                            foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples)
                            {
                                this._manager.UpdateGraph(graphInsertion.Key, graphInsertion.Value, Enumerable.Empty<Triple>());
                            }
                        }
                        else
                        {
                            Graph g = new Graph();
                            this._manager.LoadGraph(g, cmd.GraphUri);
                            g.Retract(deletedTriples);
                            this._manager.SaveGraph(g);

                            foreach (String graphUri in deletedGraphTriples.Keys.Concat(insertedGraphTriples.Keys).Distinct())
                            {
                                g = new Graph();
                                this._manager.LoadGraph(g, graphUri);
                                if (deletedGraphTriples.ContainsKey(graphUri)) g.Retract(deletedGraphTriples[graphUri]);
                                if (insertedGraphTriples.ContainsKey(graphUri)) g.Assert(insertedGraphTriples[graphUri]);
                                this._manager.SaveGraph(g);
                            }
                        }
                    }
                    else
                    {
                        throw new SparqlUpdateException("Cannot evaluate an INSERT/DELETE Command as the underlying Store failed to answer the query for the WHERE portion of the command as expected");
                    }
                }
                else
                {
                    throw new NotSupportedException("INSERT/DELETE commands are not supported by this Update Processor as the manager for the underlying Store does not provide Query capabilities which are necessary to process this command");
                }
            }
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset MinusJoin(BaseMultiset other)
        {
            //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            //If the other Multiset is disjoint then minus-ing it also doesn't alter this set
            if (this.IsDisjointWith(other))
            {
                return(this);
            }

            //Find the Variables that are to be used for Joining
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(this.Product(other));
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old algorithm which is correct but naive and has O(n^2) complexity
            //foreach (ISet x in this.Sets)
            //{
            //    //New Minus logic based on the improved Join() logic
            //    bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));

            //    //If no compatible sets then this set is preserved
            //    if (!minus)
            //    {
            //        joinedSet.Add(x);
            //    }
            //}

            //This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List <HashTable <INode, int> > values = new List <HashTable <INode, int> >();
            List <List <int> >             nulls  = new List <List <int> >();

            foreach (String var in joinVars)
            {
                values.Add(new HashTable <INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List <int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            //Then do a pass over the RHS and work out the intersections
            HashSet <int> toMinus = new HashSet <int>();

            foreach (ISet y in other.Sets)
            {
                IEnumerable <int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty <int>();
                            break;
                        }
                    }
                    else
                    {
                        //Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                    }
                    i++;
                }
                if (possMatches == null)
                {
                    continue;
                }

                //Look at possible matches, if is a valid match then mark the matched set for minus'ing
                //Don't reconsider sets which have already been marked for minusing
                foreach (int poss in possMatches)
                {
                    if (toMinus.Contains(poss))
                    {
                        continue;
                    }
                    if (this._sets[poss].IsCompatibleWith(y, joinVars))
                    {
                        toMinus.Add(poss);
                    }
                }
            }

            //Apply the actual minus
            if (toMinus.Count == this.Count)
            {
                //If number of sets to minus is equal to number of sets then we're minusing everything
                return(new NullMultiset());
            }
            else
            {
                //Otherwise iterate
                foreach (ISet x in this.Sets)
                {
                    if (!toMinus.Contains(x.ID))
                    {
                        joinedSet.Add(x.Copy());
                    }
                }
            }

            return(joinedSet);
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made.</param>
        /// <returns></returns>
        public virtual BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist)
        {
            // For EXISTS and NOT EXISTS if the other is the Identity then it has no effect
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (mustExist)
            {
                // If an EXISTS then Null/Empty Other results in Null
                if (other is NullMultiset)
                {
                    return(other);
                }
                if (other.IsEmpty)
                {
                    return(new NullMultiset());
                }
            }
            else
            {
                // If a NOT EXISTS then Null/Empty results in this
                if (other is NullMultiset)
                {
                    return(this);
                }
                if (other.IsEmpty)
                {
                    return(this);
                }
            }

            // Find the Variables that are to be used for Joining
            List <String> joinVars = Variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                // All Disjoint Solutions are compatible
                if (mustExist)
                {
                    // If an EXISTS and disjoint then result is this
                    return(this);
                }
                else
                {
                    // If a NOT EXISTS and disjoint then result is null
                    return(new NullMultiset());
                }
            }

            // Start building the Joined Set
            Multiset joinedSet = new Multiset();

            // This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            // Downside is that it does require more memory than the old algorithm
            List <MultiDictionary <INode, List <int> > > values = new List <MultiDictionary <INode, List <int> > >();
            List <List <int> > nulls = new List <List <int> >();

            foreach (String var in joinVars)
            {
                joinedSet.AddVariable(var);
                values.Add(new MultiDictionary <INode, List <int> >(new FastVirtualNodeComparer()));
                nulls.Add(new List <int>());
            }

            // First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        if (values[i].TryGetValue(value, out List <int> ids))
                        {
                            ids.Add(x.ID);
                        }
                        else
                        {
                            values[i].Add(value, new List <int> {
                                x.ID
                            });
                        }
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            // Then do a pass over the RHS and work out the intersections
            HashSet <int> exists = new HashSet <int>();

            foreach (ISet y in other.Sets)
            {
                IEnumerable <int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i][value].Concat(nulls[i]) : possMatches.Intersect(values[i][value].Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty <int>();
                            break;
                        }
                    }
                    else
                    {
                        // Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? SetIDs : possMatches.Intersect(SetIDs));
                    }
                    i++;
                }
                if (possMatches == null)
                {
                    continue;
                }

                // Look at possible matches, if is a valid match then mark the set as having an existing match
                // Don't reconsider sets which have already been marked as having an existing match
                foreach (int poss in possMatches)
                {
                    if (exists.Contains(poss))
                    {
                        continue;
                    }
                    if (this[poss].IsCompatibleWith(y, joinVars))
                    {
                        exists.Add(poss);
                    }
                }
            }

            // Apply the actual exists
            if (exists.Count == Count)
            {
                // If number of sets that have a match is equal to number of sets then we're either returning everything or nothing
                if (mustExist)
                {
                    return(this);
                }
                else
                {
                    return(new NullMultiset());
                }
            }
            else
            {
                // Otherwise iterate
                foreach (ISet x in Sets)
                {
                    if (mustExist)
                    {
                        if (exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                    else
                    {
                        if (!exists.Contains(x.ID))
                        {
                            joinedSet.Add(x.Copy());
                        }
                    }
                }
            }

            return(joinedSet);
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Joins this Multiset to another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Join(BaseMultiset other)
        {
            //If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            //If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset)
            {
                return(other);
            }
            //If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(this.Product(other));
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old Join algorithm which while correct is O(n^2) so scales terribly
            //foreach (ISet x in this.Sets)
            //{
            //    //For sets to be compatible for every joinable variable they must either have a null for the
            //    //variable in one of the sets or if they have values the values must be equal

            //    ////This first check is to try speed things up, it looks whether there are solutions that may match
            //    ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do
            //    ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue;

            //    IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
            //    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));

            //    foreach (ISet y in ys)
            //    {
            //        joinedSet.Add(x.Join(y));
            //    }
            //}

            //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List <HashTable <INode, int> > values = new List <HashTable <INode, int> >();
            List <List <int> >             nulls  = new List <List <int> >();

            foreach (String var in joinVars)
            {
                values.Add(new HashTable <INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List <int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

#if NET40 && !SILVERLIGHT
            if (Options.UsePLinqEvaluation)
            {
                //Use a paralllel join
                other.Sets.AsParallel().ForAll(y => EvalJoin(y, joinVars, values, nulls, joinedSet));
            }
            else
            {
#endif
            //Use a serial join
            //Then do a pass over the RHS and work out the intersections
            foreach (ISet y in other.Sets)
            {
                this.EvalJoin(y, joinVars, values, nulls, joinedSet);
            }
#if NET40 && !SILVERLIGHT
        }
#endif

            return(joinedSet);
        }
Ejemplo n.º 30
0
        /// <summary>
        /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <returns></returns>
        public virtual BaseMultiset MinusJoin(BaseMultiset other)
        {
            // If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            // If the other Multiset is disjoint then minus-ing it also doesn't alter this set
            if (IsDisjointWith(other))
            {
                return(this);
            }

            // Find the Variables that are to be used for Joining
            List <String> joinVars = Variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(Product(other));
            }

            // Start building the Joined Set
            Multiset joinedSet = new Multiset();

            // This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            // Downside is that it does require more memory than the old algorithm
            List <MultiDictionary <INode, List <int> > > values = new List <MultiDictionary <INode, List <int> > >();
            List <List <int> > nulls = new List <List <int> >();

            foreach (String var in joinVars)
            {
                values.Add(new MultiDictionary <INode, List <int> >(new FastVirtualNodeComparer()));
                nulls.Add(new List <int>());
            }

            // First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        if (values[i].TryGetValue(value, out List <int> ids))
                        {
                            ids.Add(x.ID);
                        }
                        else
                        {
                            values[i].Add(value, new List <int> {
                                x.ID
                            });
                        }
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            // Then do a pass over the RHS and work out the intersections
            HashSet <int> toMinus = new HashSet <int>();

            foreach (ISet y in other.Sets)
            {
                IEnumerable <int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i][value].Concat(nulls[i]) : possMatches.Intersect(values[i][value].Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty <int>();
                            break;
                        }
                    }
                    else
                    {
                        // Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? SetIDs : possMatches.Intersect(SetIDs));
                    }
                    i++;
                }
                if (possMatches == null)
                {
                    continue;
                }

                // Look at possible matches, if is a valid match then mark the matched set for minus'ing
                // Don't reconsider sets which have already been marked for minusing
                foreach (int poss in possMatches)
                {
                    if (toMinus.Contains(poss))
                    {
                        continue;
                    }
                    if (this[poss].IsMinusCompatibleWith(y, joinVars))
                    {
                        toMinus.Add(poss);
                    }
                }
            }

            // Apply the actual minus
            if (toMinus.Count == Count)
            {
                // If number of sets to minus is equal to number of sets then we're minusing everything
                return(new NullMultiset());
            }
            else
            {
                // Otherwise iterate
                foreach (ISet x in Sets)
                {
                    if (!toMinus.Contains(x.ID))
                    {
                        joinedSet.Add(x.Copy());
                    }
                }
            }

            return(joinedSet);
        }
Ejemplo n.º 31
0
        /// <summary>
        /// Evaluates the filtered product
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset initialInput = context.InputMultiset;
            BaseMultiset lhsResults   = context.Evaluate(this._lhs);

            if (lhsResults is NullMultiset || lhsResults.IsEmpty)
            {
                //If LHS Results are Null/Empty then end result will always be null so short circuit
                context.OutputMultiset = new NullMultiset();
            }
            else
            {
                context.InputMultiset = initialInput;
                BaseMultiset rhsResults = context.Evaluate(this._rhs);
                if (rhsResults is NullMultiset || rhsResults.IsEmpty)
                {
                    //If RHS Results are Null/Empty then end results will always be null so short circuit
                    context.OutputMultiset = new NullMultiset();
                }
                else if (rhsResults is IdentityMultiset)
                {
                    //Apply Filter over LHS Results only - defer evaluation to filter implementation
                    context.InputMultiset = lhsResults;
                    UnaryExpressionFilter filter = new UnaryExpressionFilter(this._expr);
                    filter.Evaluate(context);
                    context.OutputMultiset = lhsResults;
                }
                else
                {
                    //Calculate the product applying the filter as we go
#if NET40 && !SILVERLIGHT
                    if (Options.UsePLinqEvaluation && this._expr.CanParallelise)
                    {
                        PartitionedMultiset partitionedSet;
                        SparqlResultBinder  binder = context.Binder;
                        if (lhsResults.Count >= rhsResults.Count)
                        {
                            partitionedSet = new PartitionedMultiset(lhsResults.Count, rhsResults.Count);
                            context.Binder = new LeviathanLeftJoinBinder(partitionedSet);
                            lhsResults.Sets.AsParallel().ForAll(x => this.EvalFilteredProduct(context, x, rhsResults, partitionedSet));
                        }
                        else
                        {
                            partitionedSet = new PartitionedMultiset(rhsResults.Count, lhsResults.Count);
                            context.Binder = new LeviathanLeftJoinBinder(partitionedSet);
                            rhsResults.Sets.AsParallel().ForAll(y => this.EvalFilteredProduct(context, y, lhsResults, partitionedSet));
                        }

                        context.Binder         = binder;
                        context.OutputMultiset = partitionedSet;
                    }
                    else
                    {
#endif
                    BaseMultiset productSet   = new Multiset();
                    SparqlResultBinder binder = context.Binder;
                    context.Binder = new LeviathanLeftJoinBinder(productSet);
                    foreach (ISet x in lhsResults.Sets)
                    {
                        foreach (ISet y in rhsResults.Sets)
                        {
                            ISet z = x.Join(y);
                            productSet.Add(z);
                            try
                            {
                                if (!this._expr.Evaluate(context, z.ID).AsSafeBoolean())
                                {
                                    //Means the expression evaluates to false so we discard the solution
                                    productSet.Remove(z.ID);
                                }
                            }
                            catch
                            {
                                //Means this solution does not meet the FILTER and can be discarded
                                productSet.Remove(z.ID);
                            }
                        }
                        //Remember to check for timeouts occassionaly
                        context.CheckTimeout();
                    }
                    context.Binder         = binder;
                    context.OutputMultiset = productSet;
#if NET40 && !SILVERLIGHT
                }
#endif
                }
            }
            return(context.OutputMultiset);
        }
Ejemplo n.º 32
0
        /// <summary>
        /// Joins this Multiset to another Multiset.
        /// </summary>
        /// <param name="other">Other Multiset.</param>
        /// <returns></returns>
        public virtual BaseMultiset Join(BaseMultiset other)
        {
            // If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            // If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset)
            {
                return(other);
            }
            // If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            // Find the First Variable from this Multiset which is in both Multisets
            // If there is no Variable from this Multiset in the other Multiset then this
            // should be a Product operation instead of a Join
            List <String> joinVars = Variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                return(Product(other));
            }

            // Start building the Joined Set
            Multiset joinedSet = new Multiset();

            // This is the new Join algorithm which is O(2n) so much faster and scalable
            // Downside is that it does require more memory than the old algorithm
            List <MultiDictionary <INode, List <int> > > values = new List <MultiDictionary <INode, List <int> > >();
            List <List <int> > nulls = new List <List <int> >();

            foreach (String var in joinVars)
            {
                joinedSet.AddVariable(var);
                values.Add(new MultiDictionary <INode, List <int> >(new FastVirtualNodeComparer()));
                nulls.Add(new List <int>());
            }

            // First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in Sets)
            {
                var i = 0;
                foreach (var var in joinVars)
                {
                    var value = x[var];
                    if (value != null)
                    {
                        if (values[i].TryGetValue(value, out List <int> ids))
                        {
                            ids.Add(x.ID);
                        }
                        else
                        {
                            values[i].Add(value, new List <int> {
                                x.ID
                            });
                        }
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

#if NET40
            if (Options.UsePLinqEvaluation)
            {
                // Use a paralllel join
                other.Sets.AsParallel().ForAll(y => EvalJoin(y, joinVars, values, nulls, joinedSet));
            }
            else
            {
                // Use a serial join
                // Then do a pass over the RHS and work out the intersections
                foreach (ISet y in other.Sets)
                {
                    this.EvalJoin(y, joinVars, values, nulls, joinedSet);
                }
            }
#else
            // Use a serial join
            // Then do a pass over the RHS and work out the intersections
            foreach (ISet y in other.Sets)
            {
                EvalJoin(y, joinVars, values, nulls, joinedSet);
            }
#endif
            return(joinedSet);
        }
Ejemplo n.º 33
0
        /// <summary>
        /// Evaluates a Group By by generating a <see cref="GroupMultiset">GroupMultiset</see> from the Input Multiset
        /// </summary>
        /// <param name="context">SPARQL Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            BaseMultiset results = context.Evaluate(this._pattern);

            context.InputMultiset = results;

            //Identity/Null yields an empty multiset
            if (context.InputMultiset is IdentityMultiset || context.InputMultiset is NullMultiset)
            {
                results = new Multiset();
            }
            GroupMultiset       groupSet = new GroupMultiset(results);
            List <BindingGroup> groups;

            //Calculate Groups
            if (context.Query.GroupBy != null)
            {
                groups = context.Query.GroupBy.Apply(context);
            }
            else if (this._grouping != null)
            {
                groups = this._grouping.Apply(context);
            }
            else
            {
                groups = new List <BindingGroup>()
                {
                    new BindingGroup(results.SetIDs)
                };
            }

            //Add Groups to the GroupMultiset
            HashSet <String> vars = new HashSet <String>();

            foreach (BindingGroup group in groups)
            {
                foreach (KeyValuePair <String, INode> assignment in group.Assignments)
                {
                    if (vars.Contains(assignment.Key))
                    {
                        continue;
                    }

                    groupSet.AddVariable(assignment.Key);
                    vars.Add(assignment.Key);
                }
                groupSet.AddGroup(group);
            }
            //If grouping produced no groups and there are aggregates present
            //then an implicit group is created
            if (groups.Count == 0 && this._aggregates.Count > 0)
            {
                groupSet.AddGroup(new BindingGroup());
            }

            //Apply the aggregates
            context.InputMultiset = groupSet;
            context.Binder.SetGroupContext(true);
            foreach (SparqlVariable var in this._aggregates)
            {
                if (!vars.Contains(var.Name))
                {
                    groupSet.AddVariable(var.Name);
                    vars.Add(var.Name);
                }

                foreach (ISet s in groupSet.Sets)
                {
                    try
                    {
                        INode value = var.Aggregate.Apply(context, groupSet.GroupSetIDs(s.ID));
                        s.Add(var.Name, value);
                    }
                    catch (RdfQueryException)
                    {
                        s.Add(var.Name, null);
                    }
                }
            }
            context.Binder.SetGroupContext(false);

            context.OutputMultiset = groupSet;
            return(context.OutputMultiset);
        }
Ejemplo n.º 34
0
        /// <summary>
        /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            // Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset?

            bool datasetOk = false;

            try
            {
                List <String> activeGraphs = new List <string>();

                // Get the URIs of Graphs that should be evaluated over
                if (_graphSpecifier.TokenType != Token.VARIABLE)
                {
                    switch (_graphSpecifier.TokenType)
                    {
                    case Token.URI:
                    case Token.QNAME:
                        Uri activeGraphUri = UriFactory.Create(Tools.ResolveUriOrQName(_graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri));
                        if (context.Data.HasGraph(activeGraphUri))
                        {
                            // If the Graph is explicitly specified and there are FROM/FROM NAMED present then the Graph
                            // URI must be in the graphs specified by a FROM/FROM NAMED or the result is null
                            if (context.Query == null ||
                                ((!context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) ||
                                 context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u)))
                                )
                            {
                                // Either there was no Query
                                // OR there were no Default/Named Graphs (hence any Graph URI is permitted)
                                // OR the specified URI was a Named Graph URI
                                // In any case we can go ahead and set the active Graph
                                activeGraphs.Add(activeGraphUri.AbsoluteUri);
                            }
                            else
                            {
                                // The specified URI was not present in the Named Graphs so return null
                                context.OutputMultiset = new NullMultiset();
                                return(context.OutputMultiset);
                            }
                        }
                        else
                        {
                            // If specifies a specific Graph and not in the Dataset result is a null multiset
                            context.OutputMultiset = new NullMultiset();
                            return(context.OutputMultiset);
                        }
                        break;

                    default:
                        throw new RdfQueryException("Cannot use a '" + _graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause");
                    }
                }
                else
                {
                    String gvar = _graphSpecifier.Value.Substring(1);

                    // Watch out for the case in which the Graph Variable is not bound for all Sets in which case
                    // we still need to operate over all Graphs
                    if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null))
                    {
                        // If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs
                        List <Uri> graphUris = new List <Uri>();
                        foreach (ISet s in context.InputMultiset.Sets)
                        {
                            INode temp = s[gvar];
                            if (temp == null)
                            {
                                continue;
                            }
                            if (temp.NodeType != NodeType.Uri)
                            {
                                continue;
                            }
                            activeGraphs.Add(temp.ToString());
                            graphUris.Add(((IUriNode)temp).Uri);
                        }
                    }
                    else
                    {
                        // Nothing yet bound to the Graph Variable so the Query is over all the named Graphs
                        if (context.Query != null && context.Query.NamedGraphs.Any())
                        {
                            // Query specifies one/more named Graphs
                            activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.AbsoluteUri));
                        }
                        else if (context.Query != null && context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any())
                        {
                            // Gives null since the query dataset does not include any named graphs
                            context.OutputMultiset = new NullMultiset();
                            return(context.OutputMultiset);
                        }
                        else
                        {
                            // Query is over entire dataset/default Graph since no named Graphs are explicitly specified
                            activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString()));
                        }
                    }
                }

                // Remove all duplicates from Active Graphs to avoid duplicate results
                activeGraphs = activeGraphs.Distinct().ToList();

                // Evaluate the inner pattern
                BaseMultiset initialInput = context.InputMultiset;
                BaseMultiset finalResult  = new Multiset();

                // Evalute for each Graph URI and union the results
                foreach (String uri in activeGraphs)
                {
                    // Always use the same Input for each Graph URI and set that Graph to be the Active Graph
                    // Be sure to translate String.Empty back to the null URI to select the default graph
                    // correctly
                    context.InputMultiset = initialInput;
                    Uri currGraphUri = (uri.Equals(String.Empty)) ? null : UriFactory.Create(uri);

                    // Set Active Graph
                    if (currGraphUri == null)
                    {
                        // GRAPH operates over named graphs only so default graph gets skipped
                        continue;
                    }
                    // The result of the HasGraph() call is ignored we just make it so datasets with any kind of
                    // load on demand behaviour work properly
                    context.Data.HasGraph(currGraphUri);
                    // All we actually care about is setting the active graph
                    context.Data.SetActiveGraph(currGraphUri);
                    datasetOk = true;

                    // Evaluate for the current Active Graph
                    BaseMultiset result = context.Evaluate(_pattern);

                    // Merge the Results into our overall Results
                    if (result is NullMultiset)
                    {
                        // Don't do anything, adds nothing to the results
                    }
                    else if (result is IdentityMultiset)
                    {
                        // Adds a single row to the results
                        if (_graphSpecifier.TokenType == Token.VARIABLE)
                        {
                            // Include graph variable if not yet bound
                            INode currGraph = new UriNode(null, currGraphUri);
                            Set   s         = new Set();
                            s.Add(_graphSpecifier.Value.Substring(1), currGraph);
                            finalResult.Add(s);
                        }
                        else
                        {
                            finalResult.Add(new Set());
                        }
                    }
                    else
                    {
                        // If the Graph Specifier is a Variable then we must either bind the
                        // variable or eliminate solutions which have an incorrect value for it
                        if (_graphSpecifier.TokenType == Token.VARIABLE)
                        {
                            String gvar      = _graphSpecifier.Value.Substring(1);
                            INode  currGraph = new UriNode(null, currGraphUri);
                            foreach (int id in result.SetIDs.ToList())
                            {
                                ISet s = result[id];
                                if (s[gvar] == null)
                                {
                                    // If Graph Variable is not yet bound for solution bind it
                                    s.Add(gvar, currGraph);
                                }
                                else if (!s[gvar].Equals(currGraph))
                                {
                                    // If Graph Variable is bound for solution and doesn't match
                                    // current Graph then we have to remove the solution
                                    result.Remove(id);
                                }
                            }
                        }
                        // Union solutions into the Results
                        finalResult.Union(result);
                    }

                    // Reset the Active Graph after each pass
                    context.Data.ResetActiveGraph();
                    datasetOk = false;
                }

                // Return the final result
                if (finalResult.IsEmpty)
                {
                    finalResult = new NullMultiset();
                }
                context.OutputMultiset = finalResult;
            }
            finally
            {
                if (datasetOk)
                {
                    context.Data.ResetActiveGraph();
                }
            }

            return(context.OutputMultiset);
        }
Ejemplo n.º 35
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return context.OutputMultiset;
            }

            BaseMultiset initialInput, localOutput, results;

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
                case 0:
                    //Input is as given and Output is new empty multiset
                    initialInput = context.InputMultiset;
                    localOutput = new Multiset();
                    break;

                case 1:
                    //Input becomes current Output and Output is new empty multiset
                    initialInput = context.OutputMultiset;
                    localOutput = new Multiset();
                    break;

                default:
                    //Input is join of previous input and ouput and Output is new empty multiset
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        initialInput = context.InputMultiset.Product(context.OutputMultiset);
                    }
                    else
                    {
                        //Normal Join
                        initialInput = context.InputMultiset.Join(context.OutputMultiset);
                    }
                    localOutput = new Multiset();
                    break;
            }
            context.InputMultiset = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp = this._triplePatterns[pattern];
            int resultsFound = 0;

            if (temp is TriplePattern)
            {
                //Find the first Triple which matches the Pattern
                TriplePattern tp = (TriplePattern)temp;
                foreach (Triple t in tp.GetTriples(context))
                {
                    //Remember to check for Timeout during lazy evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        context.OutputMultiset.Add(tp.CreateResult(t));

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt) return results;

                            //Otherwise we need to keep going here
                            //So must reset our input and outputs before continuing
                            context.InputMultiset = initialInput;
                            context.OutputMultiset = new Multiset();
                            resultsFound--;
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.QueryTimeout - context.QueryTime);
                            }
                            else
                            {
                                //Normal Join
                                context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                            }
                            return context.OutputMultiset;
                        }
                    }
                }
            }
            else if (temp is FilterPattern)
            {
                FilterPattern fp = (FilterPattern)temp;
                ISparqlFilter filter = fp.Filter;
                ISparqlExpression expr = filter.Expression;

                //Find the first result of those we've got so far that matches
                if (context.InputMultiset is IdentityMultiset || context.InputMultiset.IsEmpty)
                {
                    try
                    {
                        //If the Input is the Identity Multiset then the Output is either
                        //the Identity/Null Multiset depending on whether the Expression evaluates to true
                        if (expr.EffectiveBooleanValue(context, 0))
                        {
                            context.OutputMultiset = new IdentityMultiset();
                        }
                        else
                        {
                            context.OutputMultiset = new NullMultiset();
                        }
                    }
                    catch
                    {
                        //If Expression fails to evaluate then result is NullMultiset
                        context.OutputMultiset = new NullMultiset();
                    }
                } 
                else
                {
                    foreach (int id in context.InputMultiset.SetIDs)
                    {
                        //Remember to check for Timeout during lazy evaluation
                        context.CheckTimeout();

                        try
                        {
                            if (expr.EffectiveBooleanValue(context, id))
                            {
                                resultsFound++;
                                context.OutputMultiset.Add(context.InputMultiset[id]);

                                //Recurse unless we're the last pattern
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);

                                    //If recursion leads to a halt then we halt and return immediately
                                    if (halt) return results;

                                    //Otherwise we need to keep going here
                                    //So must reset our input and outputs before continuing
                                    context.InputMultiset = initialInput;
                                    context.OutputMultiset = new Multiset();
                                    resultsFound--;
                                }
                                else
                                {
                                    //If we're at the last pattern and we've found a match then we can halt
                                    halt = true;

                                    //Generate the final output and return it
                                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                                    {
                                        //Disjoint so do a Product
                                        context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                                    }
                                    else
                                    {
                                        //Normal Join
                                        context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                                    }
                                    return context.OutputMultiset;
                                }
                            }
                        }
                        catch
                        {
                            //Ignore expression evaluation errors
                        }
                    }
                }
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0) return new NullMultiset();

            //We should never reach here so throw an error to that effect
            //The reason we'll never reach here is that this method should always return earlier
            throw new RdfQueryException("Unexpected control flow in evaluating a Streamed BGP for an ASK query");
        }
Ejemplo n.º 36
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return(context.OutputMultiset);
            }

            BaseMultiset initialInput, localOutput, results = null;

            //Determine whether the Pattern modifies the existing Input rather than joining to it
            bool modifies = (this._triplePatterns[pattern] is FilterPattern);
            bool extended = (pattern > 0 && this._triplePatterns[pattern - 1] is BindPattern);
            bool modified = (pattern > 0 && this._triplePatterns[pattern - 1] is FilterPattern);

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
            case 0:
                //Input is as given and Output is new empty multiset
                if (!modifies)
                {
                    initialInput = context.InputMultiset;
                }
                else
                {
                    //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input
                    //This takes care of FILTERs being out of scope
                    initialInput = new Multiset();
                }
                localOutput = new Multiset();
                break;

            case 1:
                //Input becomes current Output and Output is new empty multiset
                initialInput = context.OutputMultiset;
                localOutput  = new Multiset();
                break;

            default:
                if (!extended && !modified)
                {
                    //Input is join of previous input and output and Output is new empty multiset
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        initialInput = context.InputMultiset.Join(context.OutputMultiset);
                    }
                }
                else
                {
                    initialInput = context.OutputMultiset;
                }
                localOutput = new Multiset();
                break;
            }
            context.InputMultiset  = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp         = this._triplePatterns[pattern];
            int            resultsFound = 0;
            int            prevResults  = -1;

            if (temp is TriplePattern)
            {
                //Find the first Triple which matches the Pattern
                TriplePattern        tp = (TriplePattern)temp;
                IEnumerable <Triple> ts = tp.GetTriples(context);

                //In the case that we're lazily evaluating an optimisable ORDER BY then
                //we need to apply OrderBy()'s to our enumeration
                //This only applies to the 1st pattern
                if (pattern == 0)
                {
                    if (context.Query != null)
                    {
                        if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy)
                        {
                            IComparer <Triple> comparer = context.Query.OrderBy.GetComparer(tp);
                            if (comparer != null)
                            {
                                ts = ts.OrderBy(t => t, comparer);
                            }
                            else
                            {
                                //Can't get a comparer so can't optimise
                                this._requiredResults = -1;
                            }
                        }
                    }
                }

                foreach (Triple t in ts)
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        if (tp.IndexType == TripleIndexType.NoVariables)
                        {
                            localOutput            = new IdentityMultiset();
                            context.OutputMultiset = localOutput;
                        }
                        else
                        {
                            context.OutputMultiset.Add(tp.CreateResult(t));
                        }

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt && results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                return(results);
                            }
                            else if (halt)
                            {
                                if (results.Count == 0)
                                {
                                    //If recursing leads to no results then eliminate all outputs
                                    //Also reset to prevResults to -1
                                    resultsFound = 0;
                                    localOutput  = new Multiset();
                                    prevResults  = -1;
                                }
                                else if (prevResults > -1)
                                {
                                    if (results.Count == prevResults)
                                    {
                                        //If the amount of results found hasn't increased then this match does not
                                        //generate any further solutions further down the recursion so we can eliminate
                                        //this from the results
                                        localOutput.Remove(localOutput.SetIDs.Max());
                                    }
                                }
                                prevResults = results.Count;

                                //If we're supposed to halt but not reached the number of required results then continue
                                context.InputMultiset  = initialInput;
                                context.OutputMultiset = localOutput;
                            }
                            else
                            {
                                //Otherwise we need to keep going here
                                //So must reset our input and outputs before continuing
                                context.InputMultiset  = initialInput;
                                context.OutputMultiset = new Multiset();
                                resultsFound--;
                            }
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                            }
                            else
                            {
                                //Normal Join
                                results = context.InputMultiset.Join(context.OutputMultiset);
                            }

                            //If not reached required number of results continue
                            if (results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                context.OutputMultiset = results;
                                return(context.OutputMultiset);
                            }
                        }
                    }
                }
            }
            else if (temp is FilterPattern)
            {
                FilterPattern     filter     = (FilterPattern)temp;
                ISparqlExpression filterExpr = filter.Filter.Expression;

                if (filter.Variables.IsDisjoint(context.InputMultiset.Variables))
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Filter is Disjoint so determine whether it has any affect or not
                    if (filter.Variables.Any())
                    {
                        //Has Variables but disjoint from input => not in scope so gets ignored

                        //Do we recurse or not?
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            //Recurse and return
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);
                            return(results);
                        }
                        else
                        {
                            //We don't affect the input in any way so just return it
                            return(context.InputMultiset);
                        }
                    }
                    else
                    {
                        //No Variables so have to evaluate it to see if it gives true otherwise
                        try
                        {
                            if (filterExpr.EffectiveBooleanValue(context, 0))
                            {
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    //Recurse and return
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);
                                    return(results);
                                }
                                else
                                {
                                    //Last Pattern and we evaluate to true so can return the input as-is
                                    halt = true;
                                    return(context.InputMultiset);
                                }
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Evaluates to false so eliminates all solutions (use an empty Multiset)
                            return(new Multiset());
                        }
                    }
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Test each solution found so far against the Filter and eliminate those that evalute to false/error
                    foreach (int id in context.InputMultiset.SetIDs.ToList())
                    {
                        try
                        {
                            if (filterExpr.EffectiveBooleanValue(context, id))
                            {
                                //If evaluates to true then add to output
                                context.OutputMultiset.Add(context.InputMultiset[id]);
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Error means we ignore the solution
                        }
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        //We can never decide whether to recurse again at this point as we are not capable of deciding
                        //which solutions should be dumped (that is the job of an earlier pattern in the BGP)
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);

                        return(results);
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to filter
                        return(context.OutputMultiset);
                    }
                }
            }
            else if (temp is BindPattern)
            {
                BindPattern       bind     = (BindPattern)temp;
                ISparqlExpression bindExpr = bind.AssignExpression;
                String            bindVar  = bind.VariableName;

                if (context.InputMultiset.ContainsVariable(bindVar))
                {
                    throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query");
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Compute the Binding for every value
                    context.OutputMultiset.AddVariable(bindVar);
                    foreach (ISet s in context.InputMultiset.Sets)
                    {
                        ISet x = s.Copy();
                        try
                        {
                            INode val = bindExpr.Value(context, s.ID);
                            x.Add(bindVar, val);
                        }
                        catch (RdfQueryException)
                        {
                            //Equivalent to no assignment but the solution is preserved
                        }
                        context.OutputMultiset.Add(x);
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);
                        return(results);
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to extend
                        return(context.OutputMultiset);
                    }
                }
            }
            else
            {
                throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern");
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return(new NullMultiset());
            }
            else
            {
                //Generate the final output and return it
                if (!modifies)
                {
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        results = context.InputMultiset.Join(context.OutputMultiset);
                    }
                    context.OutputMultiset = results;
                }
                return(context.OutputMultiset);
            }
        }
Ejemplo n.º 37
0
        /// <summary>
        /// Joins this Multiset to another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Join(BaseMultiset other)
        {
            //If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset) return this;
            //If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset) return other;
            //If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty) return new NullMultiset();

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0) return this.Product(other);

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old Join algorithm which while correct is O(n^2) so scales terribly
            //foreach (ISet x in this.Sets)
            //{
            //    //For sets to be compatible for every joinable variable they must either have a null for the
            //    //variable in one of the sets or if they have values the values must be equal

            //    ////This first check is to try speed things up, it looks whether there are solutions that may match
            //    ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do
            //    ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue;

            //    IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
            //    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));

            //    foreach (ISet y in ys)
            //    {
            //        joinedSet.Add(x.Join(y));
            //    }
            //}

            //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List<HashTable<INode, int>> values = new List<HashTable<INode, int>>();
            List<List<int>> nulls = new List<List<int>>();
            foreach (String var in joinVars)
            {
                values.Add(new HashTable<INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List<int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            #if NET40 && !SILVERLIGHT
            if (Options.UsePLinqEvaluation)
            {
                //Use a paralllel join
                other.Sets.AsParallel().ForAll(y => EvalJoin(y, joinVars, values, nulls, joinedSet));
            }
            else
            {
            #endif
                //Use a serial join
                //Then do a pass over the RHS and work out the intersections
                foreach (ISet y in other.Sets)
                {
                    this.EvalJoin(y, joinVars, values, nulls, joinedSet);
                }
            #if NET40 && !SILVERLIGHT
            }
            #endif

            return joinedSet;
        }
Ejemplo n.º 38
0
        public void SparqlMultisetLeftJoin()
        {
            //Create a load of Nodes to use in the tests
            Graph g = new Graph();
            g.NamespaceMap.AddNamespace(String.Empty, new Uri("http://example.org"));
            IUriNode s1 = g.CreateUriNode(":s1");
            IUriNode s2 = g.CreateUriNode(":s2");
            IUriNode p1 = g.CreateUriNode(":p1");
            IUriNode p2 = g.CreateUriNode(":p2");
            IUriNode rdfsLabel = g.CreateUriNode("rdfs:label");
            ILiteralNode o1 = g.CreateLiteralNode("Some Text");
            ILiteralNode o2 = g.CreateLiteralNode("1", new Uri(XmlSpecsHelper.XmlSchemaDataTypeInteger));

            //Create an ID and Null Multiset
            IdentityMultiset id = new IdentityMultiset();
            NullMultiset nullset = new NullMultiset();

            //Create and Populate a Multiset
            Multiset m = new Multiset();
            Set s = new Set();
            s.Add("s", s1);
            s.Add("p", p1);
            s.Add("o", o1);
            m.Add(s);
            s = new Set();
            s.Add("s", s2);
            s.Add("p", p2);
            s.Add("o", o2);
            m.Add(s);

            //Create and Populate another Multiset
            Multiset n = new Multiset();
            s = new Set();
            s.Add("s", s1);
            s.Add("label", o1);
            n.Add(s);

            //Create and Populate another Multiset
            Multiset d = new Multiset();
            s = new Set();
            s.Add("s1", s1);
            s.Add("p1", p1);
            s.Add("o1", o1);
            d.Add(s);
            s = new Set();
            s.Add("s1", s2);
            s.Add("p1", p2);
            s.Add("o1", o2);
            d.Add(s);

            //Show the Sets
            Console.WriteLine("LHS");
            foreach (Set set in m.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
            Console.WriteLine("RHS");
            foreach (Set set in n.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
            Console.WriteLine("D");
            foreach (Set set in d.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Identity
            Console.WriteLine("Join ID-LHS");
            BaseMultiset join = id.Join(m);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Identity
            Console.WriteLine("Join LHS-ID");
            join = m.Join(id);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Null
            Console.WriteLine("Join NULL-LHS");
            join = nullset.Join(m);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Null
            Console.WriteLine("Join LHS-NULL");
            join = m.Join(nullset);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a LeftJoin
            Console.WriteLine("LeftJoin NULL-LHS");
            BaseMultiset leftjoin = nullset.LeftJoin(m, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a LeftJoin
            Console.WriteLine("LeftJoin LHS-NULL");
            leftjoin = m.LeftJoin(nullset, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join
            Console.WriteLine("Join LHS-RHS");
            join = m.Join(n);
            foreach (Set set in join.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
           
            //Try a LeftOuterJoin
            Console.WriteLine("LeftJoin LHS-RHS");
            leftjoin = m.LeftJoin(n, new BooleanExpressionTerm(true));
            foreach (Set set in leftjoin.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Produce
            Console.WriteLine("Product LHS-RHS");
            BaseMultiset product = m.Product(n);
            foreach (Set set in product.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Join to Self
            Console.WriteLine("Product LHS-D");
            product = m.Product(d);
            foreach (Set set in product.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();

            //Try a Union
            Console.WriteLine("Union LHS-RHS");
            BaseMultiset union = m.Union(n);
            foreach (Set set in union.Sets)
            {
                Console.WriteLine(set.ToString());
            }
            Console.WriteLine();
        }
Ejemplo n.º 39
0
        /// <summary>
        /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset MinusJoin(BaseMultiset other)
        {
            //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set
            if (other is IdentityMultiset) return this;
            if (other is NullMultiset) return this;
            //If the other Multiset is disjoint then minus-ing it also doesn't alter this set
            if (this.IsDisjointWith(other)) return this;

            //Find the Variables that are to be used for Joining
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0) return this.Product(other);

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            //This is the old algorithm which is correct but naive and has O(n^2) complexity
            //foreach (ISet x in this.Sets)
            //{
            //    //New Minus logic based on the improved Join() logic
            //    bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));

            //    //If no compatible sets then this set is preserved
            //    if (!minus)
            //    {
            //        joinedSet.Add(x);
            //    }
            //}

            //This is the new algorithm which is also correct but is O(3n) so much faster and scalable
            //Downside is that it does require more memory than the old algorithm
            List<HashTable<INode, int>> values = new List<HashTable<INode, int>>();
            List<List<int>> nulls = new List<List<int>>();
            foreach (String var in joinVars)
            {
                values.Add(new HashTable<INode, int>(HashTableBias.Enumeration));
                nulls.Add(new List<int>());
            }

            //First do a pass over the LHS Result to find all possible values for joined variables
            foreach (ISet x in this.Sets)
            {
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = x[var];
                    if (value != null)
                    {
                        values[i].Add(value, x.ID);
                    }
                    else
                    {
                        nulls[i].Add(x.ID);
                    }
                    i++;
                }
            }

            //Then do a pass over the RHS and work out the intersections
            HashSet<int> toMinus = new HashSet<int>();
            foreach (ISet y in other.Sets)
            {
                IEnumerable<int> possMatches = null;
                int i = 0;
                foreach (String var in joinVars)
                {
                    INode value = y[var];
                    if (value != null)
                    {
                        if (values[i].ContainsKey(value))
                        {
                            possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                        }
                        else
                        {
                            possMatches = Enumerable.Empty<int>();
                            break;
                        }
                    }
                    else
                    {
                        //Don't forget that a null will be potentially compatible with everything
                        possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                    }
                    i++;
                }
                if (possMatches == null) continue;

                //Look at possible matches, if is a valid match then mark the matched set for minus'ing
                //Don't reconsider sets which have already been marked for minusing
                foreach (int poss in possMatches)
                {
                    if (toMinus.Contains(poss)) continue;
                    if (this._sets[poss].IsCompatibleWith(y, joinVars))
                    {
                        toMinus.Add(poss);
                    }
                }
            }

            //Apply the actual minus
            if (toMinus.Count == this.Count)
            {
                //If number of sets to minus is equal to number of sets then we're minusing everything
                return new NullMultiset();
            }
            else
            {
                //Otherwise iterate
                foreach (ISet x in this.Sets)
                {
                    if (!toMinus.Contains(x.ID))
                    {
                        joinedSet.Add(x.Copy());
                    }
                }
            }

            return joinedSet;
        }
Ejemplo n.º 40
0
        /// <summary>
        /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="expr">Expression</param>
        /// <returns></returns>
        public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr)
        {
            //If the Other is the Identity/Null Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            if (other.IsEmpty)
            {
                return(this);
            }

            Multiset joinedSet                 = new Multiset();
            LeviathanLeftJoinBinder binder     = new LeviathanLeftJoinBinder(joinedSet);
            SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder);

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                //Calculate a Product filtering as we go
                foreach (ISet x in this.Sets)
                {
                    bool standalone = false;
                    foreach (ISet y in other.Sets)
                    {
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone)
                    {
                        joinedSet.Add(x.Copy());
                    }
                }
            }
            else
            {
                //This is the old algorithm which is correct but has complexity O(n^2) so it scales terribly
                //foreach (ISet x in this.Sets)
                //{
                //    IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));
                //    bool standalone = false;
                //    int i = 0;
                //    foreach (ISet y in ys)
                //    {
                //        i++;
                //        ISet z = x.Join(y);
                //        try
                //        {
                //            joinedSet.Add(z);
                //            if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                //            {
                //                joinedSet.Remove(z.ID);
                //                standalone = true;
                //            }
                //        }
                //        catch
                //        {
                //            joinedSet.Remove(z.ID);
                //            standalone = true;
                //        }
                //    }
                //    if (standalone || i == 0) joinedSet.Add(x);
                //}

                //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable
                //Downside is that it does require more memory than the old algorithm
                List <HashTable <INode, int> > values = new List <HashTable <INode, int> >();
                List <List <int> >             nulls  = new List <List <int> >();
                foreach (String var in joinVars)
                {
                    values.Add(new HashTable <INode, int>(HashTableBias.Enumeration));
                    nulls.Add(new List <int>());
                }

                //First do a pass over the LHS Result to find all possible values for joined variables
                HashSet <int> matched    = new HashSet <int>();
                HashSet <int> standalone = new HashSet <int>();
                foreach (ISet x in this.Sets)
                {
                    int i = 0;
                    foreach (String var in joinVars)
                    {
                        INode value = x[var];
                        if (value != null)
                        {
                            values[i].Add(value, x.ID);
                        }
                        else
                        {
                            nulls[i].Add(x.ID);
                        }
                        i++;
                    }
                }

                //Then do a pass over the RHS and work out the intersections
                foreach (ISet y in other.Sets)
                {
                    IEnumerable <int> possMatches = null;
                    int i = 0;
                    foreach (String var in joinVars)
                    {
                        INode value = y[var];
                        if (value != null)
                        {
                            if (values[i].ContainsKey(value))
                            {
                                possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i])));
                            }
                            else
                            {
                                possMatches = Enumerable.Empty <int>();
                                break;
                            }
                        }
                        else
                        {
                            //Don't forget that a null will be potentially compatible with everything
                            possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs));
                        }
                        i++;
                    }
                    if (possMatches == null)
                    {
                        continue;
                    }

                    //Now do the actual joins for the current set
                    //Note - We access the dictionary directly here because going through the this[int id] method
                    //incurs a Contains() call each time and we know the IDs must exist because they came from
                    //our dictionary originally!
                    foreach (int poss in possMatches)
                    {
                        if (this._sets[poss].IsCompatibleWith(y, joinVars))
                        {
                            ISet z = this._sets[poss].Join(y);
                            joinedSet.Add(z);
                            try
                            {
                                if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean())
                                {
                                    joinedSet.Remove(z.ID);
                                    standalone.Add(poss);
                                }
                                else
                                {
                                    matched.Add(poss);
                                }
                            }
                            catch
                            {
                                joinedSet.Remove(z.ID);
                                standalone.Add(poss);
                            }
                        }
                    }
                }

                //Finally add in unmatched sets from LHS
                foreach (int id in this.SetIDs)
                {
                    if (!matched.Contains(id) || standalone.Contains(id))
                    {
                        joinedSet.Add(this._sets[id].Copy());
                    }
                }
            }
            return(joinedSet);
        }
Ejemplo n.º 41
0
 /// <summary>
 /// Converts a Bindings Clause to a Multiset
 /// </summary>
 /// <returns></returns>
 public BaseMultiset ToMultiset()
 {
     if (this._vars.Any())
     {
         Multiset m = new Multiset();
         foreach (String var in this._vars)
         {
             m.AddVariable(var);
         }
         foreach (BindingTuple tuple in this._tuples)
         {
             m.Add(new Set(tuple));
         }
         return m;
     }
     else
     {
         return new IdentityMultiset();
     }
 }
Ejemplo n.º 42
0
        /// <summary>
        /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations.
        /// </summary>
        /// <param name="multiset">Multiset.</param>
        /// <param name="other">Other Multiset.</param>
        /// <param name="timeout">Timeout, if &lt;=0 no timeout is used and product will be computed sychronously.</param>
        /// <returns></returns>
        public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout)
        {
            if (other is IdentityMultiset)
            {
                return(multiset);
            }
            if (other is NullMultiset)
            {
                return(other);
            }
            if (other.IsEmpty)
            {
                return(new NullMultiset());
            }

            // If no timeout use default implementation
            if (timeout <= 0)
            {
                return(multiset.Product(other));
            }

            // Otherwise Invoke using an Async call
#if NET40
            BaseMultiset productSet;
            if (Options.UsePLinqEvaluation)
            {
                if (multiset.Count >= other.Count)
                {
                    productSet = new PartitionedMultiset(multiset.Count, other.Count);
                }
                else
                {
                    productSet = new PartitionedMultiset(other.Count, multiset.Count);
                }
            }
            else
            {
                productSet = new Multiset();
            }
#else
            var productSet = new Multiset();
#endif

            var stop = new StopToken();
            var t    = (int)Math.Min(timeout, int.MaxValue);
#if NET40 || NETSTANDARD1_4 || NETSTANDARD2_0
            var productTask = Task.Factory.StartNew(() => GenerateProduct(multiset, other, productSet, stop));
            if (!productTask.Wait(t))
            {
                stop.ShouldStop = true;
                productTask.Wait();
            }

            return(productSet);
#else
            GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct);
            IAsyncResult            r = d.BeginInvoke(multiset, other, productSet, stop, null, null);
            // Wait
            r.AsyncWaitHandle.WaitOne(t);
            if (!r.IsCompleted)
            {
                stop.ShouldStop = true;
                r.AsyncWaitHandle.WaitOne();
            }
            return(productSet);
#endif
        }
Ejemplo n.º 43
0
        /// <summary>
        /// Joins this Multiset to another Multiset
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <returns></returns>
        public override BaseMultiset Join(BaseMultiset other)
        {
            //If the Other is the Identity Multiset the result is this Multiset
            if (other is IdentityMultiset) return this;
            //If the Other is the Null Multiset the result is the Null Multiset
            if (other is NullMultiset) return other;
            //If the Other is Empty then the result is the Null Multiset
            if (other.IsEmpty) return new NullMultiset();

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();
            if (joinVars.Count == 0) return this.Product(other);

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();
            foreach (Set x in this.Sets)
            {
                //For sets to be compatible for every joinable variable they must either have a null for the
                //variable in one of the sets or if they have values the values must be equal

                IEnumerable<Set> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));

                foreach (Set y in ys)
                {
                    joinedSet.Add(new Set(x, y));
                }
            }
            return joinedSet;
        }
Ejemplo n.º 44
0
        /// <summary>
        /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="expr">Expression</param>
        /// <returns></returns>
        public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr)
        {
            //If the Other is the Identity/Null Multiset the result is this Multiset
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (other is NullMultiset)
            {
                return(this);
            }
            if (other.IsEmpty)
            {
                return(this);
            }

            Multiset joinedSet                 = new Multiset();
            LeviathanLeftJoinBinder binder     = new LeviathanLeftJoinBinder(joinedSet);
            SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder);

            //Find the First Variable from this Multiset which is in both Multisets
            //If there is no Variable from this Multiset in the other Multiset then this
            //should be a Join operation instead of a LeftJoin
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                //Calculate a Product filtering as we go
                foreach (ISet x in this.Sets)
                {
                    bool standalone = false;
                    foreach (ISet y in other.Sets)
                    {
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.EffectiveBooleanValue(subcontext, z.ID))
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone)
                    {
                        joinedSet.Add(x);
                    }
                }
            }
            else
            {
                foreach (ISet x in this.Sets)
                {
                    IEnumerable <ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                    //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars));
                    bool standalone = false;
                    int  i          = 0;
                    foreach (ISet y in ys)
                    {
                        i++;
                        ISet z = x.Join(y);
                        try
                        {
                            joinedSet.Add(z);
                            if (!expr.EffectiveBooleanValue(subcontext, z.ID))
                            {
                                joinedSet.Remove(z.ID);
                                standalone = true;
                            }
                        }
                        catch
                        {
                            joinedSet.Remove(z.ID);
                            standalone = true;
                        }
                    }
                    if (standalone || i == 0)
                    {
                        joinedSet.Add(x);
                    }
                }
            }
            return(joinedSet);
        }
Ejemplo n.º 45
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return(context.OutputMultiset);
            }

            BaseMultiset initialInput, localOutput, results;

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
            case 0:
                //Input is as given and Output is new empty multiset
                initialInput = context.InputMultiset;
                localOutput  = new Multiset();
                break;

            case 1:
                //Input becomes current Output and Output is new empty multiset
                initialInput = context.OutputMultiset;
                localOutput  = new Multiset();
                break;

            default:
                //Input is join of previous input and ouput and Output is new empty multiset
                if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                {
                    //Disjoint so do a Product
                    initialInput = context.InputMultiset.Product(context.OutputMultiset);
                }
                else
                {
                    //Normal Join
                    initialInput = context.InputMultiset.Join(context.OutputMultiset);
                }
                localOutput = new Multiset();
                break;
            }
            context.InputMultiset  = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp         = this._triplePatterns[pattern];
            int            resultsFound = 0;

            if (temp.PatternType == TriplePatternType.Match)
            {
                //Find the first Triple which matches the Pattern
                IMatchTriplePattern tp = (IMatchTriplePattern)temp;
                foreach (Triple t in tp.GetTriples(context))
                {
                    //Remember to check for Timeout during lazy evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        context.OutputMultiset.Add(tp.CreateResult(t));

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt)
                            {
                                return(results);
                            }

                            //Otherwise we need to keep going here
                            //So must reset our input and outputs before continuing
                            context.InputMultiset  = initialInput;
                            context.OutputMultiset = new Multiset();
                            resultsFound--;
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.QueryTimeout - context.QueryTime);
                            }
                            else
                            {
                                //Normal Join
                                context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                            }
                            return(context.OutputMultiset);
                        }
                    }
                }
            }
            else if (temp.PatternType == TriplePatternType.Filter)
            {
                IFilterPattern    fp     = (IFilterPattern)temp;
                ISparqlFilter     filter = fp.Filter;
                ISparqlExpression expr   = filter.Expression;

                //Find the first result of those we've got so far that matches
                if (context.InputMultiset is IdentityMultiset || context.InputMultiset.IsEmpty)
                {
                    try
                    {
                        //If the Input is the Identity Multiset then the Output is either
                        //the Identity/Null Multiset depending on whether the Expression evaluates to true
                        if (expr.Evaluate(context, 0).AsSafeBoolean())
                        {
                            context.OutputMultiset = new IdentityMultiset();
                        }
                        else
                        {
                            context.OutputMultiset = new NullMultiset();
                        }
                    }
                    catch
                    {
                        //If Expression fails to evaluate then result is NullMultiset
                        context.OutputMultiset = new NullMultiset();
                    }
                }
                else
                {
                    foreach (int id in context.InputMultiset.SetIDs)
                    {
                        //Remember to check for Timeout during lazy evaluation
                        context.CheckTimeout();

                        try
                        {
                            if (expr.Evaluate(context, id).AsSafeBoolean())
                            {
                                resultsFound++;
                                context.OutputMultiset.Add(context.InputMultiset[id].Copy());

                                //Recurse unless we're the last pattern
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);

                                    //If recursion leads to a halt then we halt and return immediately
                                    if (halt)
                                    {
                                        return(results);
                                    }

                                    //Otherwise we need to keep going here
                                    //So must reset our input and outputs before continuing
                                    context.InputMultiset  = initialInput;
                                    context.OutputMultiset = new Multiset();
                                    resultsFound--;
                                }
                                else
                                {
                                    //If we're at the last pattern and we've found a match then we can halt
                                    halt = true;

                                    //Generate the final output and return it
                                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                                    {
                                        //Disjoint so do a Product
                                        context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                                    }
                                    else
                                    {
                                        //Normal Join
                                        context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset);
                                    }
                                    return(context.OutputMultiset);
                                }
                            }
                        }
                        catch
                        {
                            //Ignore expression evaluation errors
                        }
                    }
                }
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return(new NullMultiset());
            }

            //We should never reach here so throw an error to that effect
            //The reason we'll never reach here is that this method should always return earlier
            throw new RdfQueryException("Unexpected control flow in evaluating a Streamed BGP for an ASK query");
        }
        /// <summary>
        /// Evaluates a setp of the Path
        /// </summary>
        /// <param name="context">Context</param>
        /// <param name="path">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        /// <returns></returns>
        protected List<INode> EvaluateStep(SparqlEvaluationContext context, List<INode> path, bool reverse)
        {
            if (this.Path is Property)
            {
                HashSet<INode> nodes = new HashSet<INode>();
                INode predicate = ((Property)this.Path).Predicate;
                IEnumerable<Triple> ts = (reverse ? context.Data.GetTriplesWithPredicateObject(predicate, path[path.Count - 1]) : context.Data.GetTriplesWithSubjectPredicate(path[path.Count - 1], predicate));
                foreach (Triple t in ts)
                {
                    if (reverse)
                    {
                        if (!path.Contains(t.Subject))
                        {
                            nodes.Add(t.Subject);
                        }
                    }
                    else
                    {
                        if (!path.Contains(t.Object))
                        {
                            nodes.Add(t.Object);
                        }
                    }
                }
                return nodes.ToList();
            }
            else
            {
                List<INode> nodes = new List<INode>();

                BaseMultiset initialInput = context.InputMultiset;
                Multiset currInput = new Multiset();
                VariablePattern x = new VariablePattern("?x");
                VariablePattern y = new VariablePattern("?y");
                Set temp = new Set();
                if (reverse)
                {
                    temp.Add("y", path[path.Count - 1]);
                }
                else
                {
                    temp.Add("x", path[path.Count - 1]);
                }
                currInput.Add(temp);
                context.InputMultiset = currInput;

                Bgp bgp = new Bgp(new PropertyPathPattern(x, this.Path, y));
                BaseMultiset results = context.Evaluate(bgp);//bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (Set s in results.Sets)
                    {
                        if (reverse)
                        {
                            if (s["x"] != null)
                            {
                                if (!path.Contains(s["x"]))
                                {
                                    nodes.Add(s["x"]);
                                }
                            }
                        }
                        else
                        {
                            if (s["y"] != null)
                            {
                                if (!path.Contains(s["y"]))
                                {
                                    nodes.Add(s["y"]);
                                }
                            }
                        }
                    }
                }

                return nodes;
            }
        }
Ejemplo n.º 47
0
        /// <summary>
        /// Processes an INSERT command
        /// </summary>
        /// <param name="cmd">Insert Command</param>
        /// <remarks>
        /// <para>
        /// <strong>Note:</strong> The underlying manager must implement the <see cref="IQueryableGenericIOManager">IQueryableGenericIOManager</see> interface in order for INSERT commands to be processed
        /// </para>
        /// </remarks>
        public void ProcessInsertCommand(InsertCommand cmd)
        {
            if (this._manager is IUpdateableGenericIOManager)
            {
                ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString());
            }
            else
            {
                if (this._manager is IQueryableGenericIOManager)
                {
                    //Check IO Behaviour
                    //For a insert we either need the ability to Update Add Triples or to Overwrite Graphs
                    //Firstly check behaviour persuant to default graph if applicable
                    if (cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>().Any())
                    {
                        //Must support notion of default graph
                        if ((this._manager.IOBehaviour & IOBehaviour.HasDefaultGraph) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of an explicit unnamed Default Graph required to process this command");
                        //Must allow either OverwriteDefault or CanUpdateAddTriples
                        if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteDefault) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command");
                    }
                    //Then check behaviour persuant to named graphs if applicable
                    if (cmd.InsertPattern.HasChildGraphPatterns)
                    {
                        //Must support named graphs
                        if ((this._manager.IOBehaviour & IOBehaviour.HasNamedGraphs) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of named graphs required to process this command");
                        //Must allow either CanUpdateAddTriples or OverwriteNamed
                        if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteNamed) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command");
                    }

                    //First build and make the query to get a Result Set
                    String queryText = "SELECT * WHERE " + cmd.WherePattern.ToString();
                    SparqlQueryParser parser = new SparqlQueryParser();
                    SparqlQuery query = parser.ParseFromString(queryText);
                    if (cmd.GraphUri != null && !cmd.UsingUris.Any()) query.AddDefaultGraph(cmd.GraphUri);
                    foreach (Uri u in cmd.UsingUris)
                    {
                        query.AddDefaultGraph(u);
                    }
                    foreach (Uri u in cmd.UsingNamedUris)
                    {
                        query.AddNamedGraph(u);
                    }

                    Object results = ((IQueryableGenericIOManager)this._manager).Query(query.ToString());
                    if (results is SparqlResultSet)
                    {
                        //Now need to transform the Result Set back to a Multiset
                        Multiset mset = new Multiset((SparqlResultSet)results);

                        //Generate the Triples for each Solution
                        List<Triple> insertedTriples = new List<Triple>();
                        Dictionary<String, List<Triple>> insertedGraphTriples = new Dictionary<string, List<Triple>>();
                        foreach (ISet s in mset.Sets)
                        {
                            List<Triple> tempInsertedTriples = new List<Triple>();
                            try
                            {
                                ConstructContext context = new ConstructContext(null, s, true);
                                foreach (IConstructTriplePattern p in cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>())
                                {
                                    try
                                    {
                                        tempInsertedTriples.Add(p.Construct(context));
                                    }
                                    catch (RdfQueryException)
                                    {
                                        //If we get an error here then it means we couldn't construct a specific
                                        //triple so we continue anyway
                                    }
                                }
                                insertedTriples.AddRange(tempInsertedTriples);
                            }
                            catch (RdfQueryException)
                            {
                                //If we get an error here this means we couldn't construct for this solution so the
                                //solution is ignore for this graph
                            }

                            //Triples from GRAPH clauses
                            foreach (GraphPattern gp in cmd.InsertPattern.ChildGraphPatterns)
                            {
                                tempInsertedTriples.Clear();
                                try
                                {
                                    String graphUri;
                                    switch (gp.GraphSpecifier.TokenType)
                                    {
                                        case Token.URI:
                                            graphUri = gp.GraphSpecifier.Value;
                                            break;
                                        case Token.VARIABLE:
                                            if (s.ContainsVariable(gp.GraphSpecifier.Value))
                                            {
                                                INode temp = s[gp.GraphSpecifier.Value.Substring(1)];
                                                if (temp == null)
                                                {
                                                    //If the Variable is not bound then skip
                                                    continue;
                                                }
                                                else if (temp.NodeType == NodeType.Uri)
                                                {
                                                    graphUri = temp.ToSafeString();
                                                }
                                                else
                                                {
                                                    //If the Variable is not bound to a URI then skip
                                                    continue;
                                                }
                                            }
                                            else
                                            {
                                                //If the Variable is not bound for this solution then skip
                                                continue;
                                            }
                                            break;
                                        default:
                                            //Any other Graph Specifier we have to ignore this solution
                                            continue;
                                    }
                                    if (!insertedGraphTriples.ContainsKey(graphUri)) insertedGraphTriples.Add(graphUri, new List<Triple>());
                                    ConstructContext context = new ConstructContext(null, s, true);
                                    foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>())
                                    {
                                        try
                                        {
                                            tempInsertedTriples.Add(p.Construct(context));
                                        }
                                        catch (RdfQueryException)
                                        {
                                            //If we get an error here then it means we couldn't construct a specific
                                            //triple so we continue anyway
                                        }
                                    }
                                    insertedGraphTriples[graphUri].AddRange(tempInsertedTriples);
                                }
                                catch (RdfQueryException)
                                {
                                    //If we get an error here this means we couldn't construct for this solution so the
                                    //solution is ignore for this graph
                                }
                            }
                        }

                        //Now decide how to apply the update
                        if (this._manager.UpdateSupported)
                        {
                            this._manager.UpdateGraph(cmd.GraphUri, insertedTriples, Enumerable.Empty<Triple>());
                            foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples)
                            {
                                this._manager.UpdateGraph(graphInsertion.Key, graphInsertion.Value, Enumerable.Empty<Triple>());
                            }
                        }
                        else
                        {
                            Graph g = new Graph();
                            this._manager.LoadGraph(g, cmd.GraphUri);
                            g.Assert(insertedTriples);
                            this._manager.SaveGraph(g);

                            foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples)
                            {
                                g = new Graph();
                                this._manager.LoadGraph(g, graphInsertion.Key);
                                g.Assert(graphInsertion.Value);
                                this._manager.SaveGraph(g);
                            }
                        }
                    }
                    else
                    {
                        throw new SparqlUpdateException("Cannot evaluate an INSERT Command as the underlying Store failed to answer the query for the WHERE portion of the command as expected");
                    }
                }
                else
                {
                    throw new NotSupportedException("INSERT commands are not supported by this Update Processor as the manager for the underlying Store does not provide Query capabilities which are necessary to process this command");
                }
            }
        }
Ejemplo n.º 48
0
        /// <summary>
        /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS
        /// </summary>
        /// <param name="other">Other Multiset</param>
        /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made</param>
        /// <returns></returns>
        public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist)
        {
            //For EXISTS and NOT EXISTS if the other is the Identity then it has no effect
            if (other is IdentityMultiset)
            {
                return(this);
            }
            if (mustExist)
            {
                //If an EXISTS then Null/Empty Other results in Null
                if (other is NullMultiset)
                {
                    return(other);
                }
                if (other.IsEmpty)
                {
                    return(new NullMultiset());
                }
            }
            else
            {
                //If a NOT EXISTS then Null/Empty results in this
                if (other is NullMultiset)
                {
                    return(this);
                }
                if (other.IsEmpty)
                {
                    return(this);
                }
            }

            //Find the Variables that are to be used for Joining
            List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList();

            if (joinVars.Count == 0)
            {
                //All Disjoint Solutions are compatible
                if (mustExist)
                {
                    //If an EXISTS and disjoint then result is this
                    return(this);
                }
                else
                {
                    //If a NOT EXISTS and disjoint then result is null
                    return(new NullMultiset());
                }
            }

            //Start building the Joined Set
            Multiset joinedSet = new Multiset();

            foreach (ISet x in this.Sets)
            {
                //New ExistsJoin() logic based on the improved Join() logic
                bool exists = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v])));
                //bool exists = other.Sets.Any(s => s.IsCompatibleWith(x, joinVars));

                if (exists)
                {
                    //If there are compatible sets and this is an EXIST then preserve the solution
                    if (mustExist)
                    {
                        joinedSet.Add(x);
                    }
                }
                else
                {
                    //If there are no compatible sets and this is a NOT EXISTS then preserve the solution
                    if (!mustExist)
                    {
                        joinedSet.Add(x);
                    }
                }
            }
            return(joinedSet);
        }
Ejemplo n.º 49
0
        /// <summary>
        /// Evaluates a setp of the Path
        /// </summary>
        /// <param name="context">Context</param>
        /// <param name="path">Paths</param>
        /// <param name="reverse">Whether to evaluate Paths in reverse</param>
        /// <returns></returns>
        protected List <INode> EvaluateStep(SparqlEvaluationContext context, List <INode> path, bool reverse)
        {
            if (this.Path is Property)
            {
                HashSet <INode>      nodes     = new HashSet <INode>();
                INode                predicate = ((Property)this.Path).Predicate;
                IEnumerable <Triple> ts        = (reverse ? context.Data.GetTriplesWithPredicateObject(predicate, path[path.Count - 1]) : context.Data.GetTriplesWithSubjectPredicate(path[path.Count - 1], predicate));
                foreach (Triple t in ts)
                {
                    if (reverse)
                    {
                        if (!path.Contains(t.Subject))
                        {
                            nodes.Add(t.Subject);
                        }
                    }
                    else
                    {
                        if (!path.Contains(t.Object))
                        {
                            nodes.Add(t.Object);
                        }
                    }
                }
                return(nodes.ToList());
            }
            else
            {
                HashSet <INode> nodes = new HashSet <INode>();

                BaseMultiset    initialInput = context.InputMultiset;
                Multiset        currInput    = new Multiset();
                VariablePattern x            = new VariablePattern("?x");
                VariablePattern y            = new VariablePattern("?y");
                Set             temp         = new Set();
                if (reverse)
                {
                    temp.Add("y", path[path.Count - 1]);
                }
                else
                {
                    temp.Add("x", path[path.Count - 1]);
                }
                currInput.Add(temp);
                context.InputMultiset = currInput;

                Bgp          bgp     = new Bgp(new PropertyPathPattern(x, this.Path, y));
                BaseMultiset results = context.Evaluate(bgp); //bgp.Evaluate(context);
                context.InputMultiset = initialInput;

                if (!results.IsEmpty)
                {
                    foreach (ISet s in results.Sets)
                    {
                        if (reverse)
                        {
                            if (s["x"] != null)
                            {
                                if (!path.Contains(s["x"]))
                                {
                                    nodes.Add(s["x"]);
                                }
                            }
                        }
                        else
                        {
                            if (s["y"] != null)
                            {
                                if (!path.Contains(s["y"]))
                                {
                                    nodes.Add(s["y"]);
                                }
                            }
                        }
                    }
                }

                return(nodes.ToList());
            }
        }
Ejemplo n.º 50
0
        private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt)
        {
            halt = false;

            //Handle Empty BGPs
            if (pattern == 0 && this._triplePatterns.Count == 0)
            {
                context.OutputMultiset = new IdentityMultiset();
                return context.OutputMultiset;
            }

            BaseMultiset initialInput, localOutput, results = null;

            //Determine whether the Pattern modifies the existing Input rather than joining to it
            bool modifies = (this._triplePatterns[pattern] is FilterPattern);
            bool extended = (pattern > 0 && this._triplePatterns[pattern-1] is BindPattern);
            bool modified = (pattern > 0 && this._triplePatterns[pattern-1] is FilterPattern);

            //Set up the Input and Output Multiset appropriately
            switch (pattern)
            {
                case 0:
                    //Input is as given and Output is new empty multiset
                    if (!modifies)
                    {
                        initialInput = context.InputMultiset;
                    }
                    else
                    {
                        //If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input
                        //This takes care of FILTERs being out of scope
                        initialInput = new Multiset();
                    }
                    localOutput = new Multiset();
                    break;

                case 1:
                    //Input becomes current Output and Output is new empty multiset
                    initialInput = context.OutputMultiset;
                    localOutput = new Multiset();
                    break;

                default:
                    if (!extended && !modified)
                    {
                        //Input is join of previous input and output and Output is new empty multiset
                        if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                        {
                            //Disjoint so do a Product
                            initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                        }
                        else
                        {
                            //Normal Join
                            initialInput = context.InputMultiset.Join(context.OutputMultiset);
                        }
                    }
                    else
                    {
                        initialInput = context.OutputMultiset;
                    }
                    localOutput = new Multiset();
                    break;
            }
            context.InputMultiset = initialInput;
            context.OutputMultiset = localOutput;

            //Get the Triple Pattern we're evaluating
            ITriplePattern temp = this._triplePatterns[pattern];
            int resultsFound = 0;
            int prevResults = -1;

            if (temp is TriplePattern)
            {
                //Find the first Triple which matches the Pattern
                TriplePattern tp = (TriplePattern)temp;
                IEnumerable<Triple> ts = tp.GetTriples(context);

                //In the case that we're lazily evaluating an optimisable ORDER BY then
                //we need to apply OrderBy()'s to our enumeration
                //This only applies to the 1st pattern
                if (pattern == 0)
                {
                    if (context.Query != null)
                    {
                        if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy)
                        {
                            IComparer<Triple> comparer = context.Query.OrderBy.GetComparer(tp);
                            if (comparer != null)
                            {
                                ts = ts.OrderBy(t => t, comparer);
                            }
                            else
                            {
                                //Can't get a comparer so can't optimise
                                this._requiredResults = -1;
                            }
                        }
                    }
                }

                foreach (Triple t in ts)
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    if (tp.Accepts(context, t))
                    {
                        resultsFound++;
                        if (tp.IndexType == TripleIndexType.NoVariables)
                        {
                            localOutput = new IdentityMultiset();
                            context.OutputMultiset = localOutput;
                        }
                        else
                        {
                            context.OutputMultiset.Add(tp.CreateResult(t));
                        }

                        //Recurse unless we're the last pattern
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);

                            //If recursion leads to a halt then we halt and return immediately
                            if (halt && results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                return results;
                            }
                            else if (halt)
                            {
                                if (results.Count == 0)
                                {
                                    //If recursing leads to no results then eliminate all outputs
                                    //Also reset to prevResults to -1
                                    resultsFound = 0;
                                    localOutput = new Multiset();
                                    prevResults = -1;
                                }
                                else if (prevResults > -1)
                                {
                                    if (results.Count == prevResults)
                                    {
                                        //If the amount of results found hasn't increased then this match does not
                                        //generate any further solutions further down the recursion so we can eliminate
                                        //this from the results
                                        localOutput.Remove(localOutput.SetIDs.Max());
                                    }
                                }
                                prevResults = results.Count;

                                //If we're supposed to halt but not reached the number of required results then continue
                                context.InputMultiset = initialInput;
                                context.OutputMultiset = localOutput;
                            }
                            else
                            {
                                //Otherwise we need to keep going here
                                //So must reset our input and outputs before continuing
                                context.InputMultiset = initialInput;
                                context.OutputMultiset = new Multiset();
                                resultsFound--;
                            }
                        }
                        else
                        {
                            //If we're at the last pattern and we've found a match then we can halt
                            halt = true;

                            //Generate the final output and return it
                            if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                            {
                                //Disjoint so do a Product
                                results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                            }
                            else
                            {
                                //Normal Join
                                results = context.InputMultiset.Join(context.OutputMultiset);
                            }

                            //If not reached required number of results continue
                            if (results.Count >= this._requiredResults && this._requiredResults != -1)
                            {
                                context.OutputMultiset = results;
                                return context.OutputMultiset;
                            }
                        }
                    }
                }
            }
            else if (temp is FilterPattern)
            {
                FilterPattern filter = (FilterPattern)temp;
                ISparqlExpression filterExpr = filter.Filter.Expression;

                if (filter.Variables.IsDisjoint(context.InputMultiset.Variables))
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Filter is Disjoint so determine whether it has any affect or not
                    if (filter.Variables.Any())
                    {
                        //Has Variables but disjoint from input => not in scope so gets ignored

                        //Do we recurse or not?
                        if (pattern < this._triplePatterns.Count - 1)
                        {
                            //Recurse and return
                            results = this.StreamingEvaluate(context, pattern + 1, out halt);
                            return results;
                        }
                        else
                        {
                            //We don't affect the input in any way so just return it
                            return context.InputMultiset;
                        }
                    }
                    else
                    {
                        //No Variables so have to evaluate it to see if it gives true otherwise
                        try
                        {
                            if (filterExpr.Evaluate(context, 0).AsSafeBoolean())
                            {
                                if (pattern < this._triplePatterns.Count - 1)
                                {
                                    //Recurse and return
                                    results = this.StreamingEvaluate(context, pattern + 1, out halt);
                                    return results;
                                }
                                else
                                {
                                    //Last Pattern and we evaluate to true so can return the input as-is
                                    halt = true;
                                    return context.InputMultiset;
                                }
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Evaluates to false so eliminates all solutions (use an empty Multiset)
                            return new Multiset();
                        }
                    }
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Test each solution found so far against the Filter and eliminate those that evalute to false/error
                    foreach (int id in context.InputMultiset.SetIDs.ToList())
                    {
                        try
                        {
                            if (filterExpr.Evaluate(context, id).AsSafeBoolean())
                            {
                                //If evaluates to true then add to output
                                context.OutputMultiset.Add(context.InputMultiset[id].Copy());
                            }
                        }
                        catch (RdfQueryException)
                        {
                            //Error means we ignore the solution
                        }
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        //We can never decide whether to recurse again at this point as we are not capable of deciding
                        //which solutions should be dumped (that is the job of an earlier pattern in the BGP)
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);

                        return results;
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to filter
                        return context.OutputMultiset;
                    }
                }
            }
            else if (temp is BindPattern)
            {
                BindPattern bind = (BindPattern)temp;
                ISparqlExpression bindExpr = bind.AssignExpression;
                String bindVar = bind.VariableName;

                if (context.InputMultiset.ContainsVariable(bindVar))
                {
                    throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query");
                }
                else
                {
                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Compute the Binding for every value
                    context.OutputMultiset.AddVariable(bindVar);
                    foreach (ISet s in context.InputMultiset.Sets)
                    {
                        ISet x = s.Copy();
                        try
                        {
                            INode val = bindExpr.Evaluate(context, s.ID);
                            x.Add(bindVar, val);
                        }
                        catch (RdfQueryException)
                        {
                            //Equivalent to no assignment but the solution is preserved
                        }
                        context.OutputMultiset.Add(x.Copy());
                    }

                    //Remember to check for Timeouts during Lazy Evaluation
                    context.CheckTimeout();

                    //Decide whether to recurse or not
                    resultsFound = context.OutputMultiset.Count;
                    if (pattern < this._triplePatterns.Count - 1)
                    {
                        //Recurse then return
                        results = this.StreamingEvaluate(context, pattern + 1, out halt);
                        return results;
                    }
                    else
                    {
                        halt = true;

                        //However many results we need we'll halt - previous patterns can call us again if they find more potential solutions
                        //for us to extend
                        return context.OutputMultiset;
                    }
                }
            }
            else
            {
                throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern");
            }

            //If we found no possibles we return the null multiset
            if (resultsFound == 0)
            {
                return new NullMultiset();
            }
            else
            {
                //Generate the final output and return it
                if (!modifies)
                {
                    if (context.InputMultiset.IsDisjointWith(context.OutputMultiset))
                    {
                        //Disjoint so do a Product
                        results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout);
                    }
                    else
                    {
                        //Normal Join
                        results = context.InputMultiset.Join(context.OutputMultiset);
                    }
                    context.OutputMultiset = results;
                }
                return context.OutputMultiset;
            }
        }