Exemple #1
0
        /// <summary>
        /// Selects a join type (merge or hash) for the given join edge, and returns a join node
        /// which merges the left and right nodes of the given join edge.
        /// </summary>
        /// <param name="joinEdge">The join edge.</param>
        /// <returns>
        /// The join node merging the left and right nodes from the given join edge.
        /// </returns>
        public jg::Node ChooseJoinType(jg::Edge joinEdge)
        {
            //
            // get the operators for the left and right nodes. if a node does not have an operator,
            // then it must have an SAP and we select a scan operator for it here.

            Operator leftOp, rightOp;

            if (joinEdge.Left.HasOperator)
            {
                leftOp = joinEdge.Left.Operator;
            }
            else
            {
                leftOp = ChooseScan(joinEdge.Left);
            }

            if (joinEdge.Right.HasOperator)
            {
                rightOp = joinEdge.Right.Operator;
            }
            else
            {
                rightOp = ChooseScan(joinEdge.Right);
            }

            //
            // create a new, empty join node

            var joinNode = new jg::Node(null, null);

            if (CanDoMergeJoin(leftOp, rightOp))
            {
                //
                // heuristic: if we can do a merge join, do so

                var leftSortOrder  = leftOp.GetOutputSortOrder();
                var rightSortOrder = rightOp.GetOutputSortOrder();
                var joinVars       = new HashSet <long>(leftSortOrder);
                joinVars.IntersectWith(rightSortOrder);

                //
                // the merge joinoperator is then constructed in the Datastructures.Queries.QueryPlan
                // class.

                joinNode.Operator = QueryPlan.GetMergeJoin(leftOp, rightOp, joinVars.ToArray());
            }
            else
            {
                //
                // if we cannot do a merge join, do a hash join instead. the hash join operator is
                // then constructed in the Datastructures.Queries.QueryPlan class.

                joinNode.Operator = QueryPlan.GetHashJoin(leftOp, rightOp);
            }

            return(joinNode);
        }
Exemple #2
0
        /// <summary>
        /// Merges a pair of given join nodes, causing all edges connecting to either of the two
        /// join nodes to connect to the newly formed node which merges the two.
        /// </summary>
        /// <param name="joinGraph">The join graph.</param>
        /// <param name="oldEdge">The old edge which is to be replaced.</param>
        /// <param name="newNode">The new node which takes merges the two nodes belonging to the given edge.</param>
        private static void MergeJoinNodes(jg::Graph joinGraph, jg::Edge oldEdge, jg::Node newNode)
        {
            //
            // remove the old edge and its nodes from the join graph

            joinGraph.Edges.Remove(oldEdge);
            joinGraph.Nodes.Remove(oldEdge.Left);
            joinGraph.Nodes.Remove(oldEdge.Right);

            //
            // any edges connecting to the removed nodes will be redirected to the new node that
            // merges the two

            foreach (var edge in joinGraph.Edges)
            {
                if (edge.Left.Equals(oldEdge.Left) || edge.Left.Equals(oldEdge.Right))
                {
                    edge.Left = newNode;
                }

                if (edge.Right.Equals(oldEdge.Left) || edge.Right.Equals(oldEdge.Right))
                {
                    edge.Right = newNode;
                }
            }

            //
            // we might end up with duplicate edges pointing to the new node, so make sure to
            // filter those out

            var uniqueEdges = joinGraph.Edges.Distinct().ToList();

            joinGraph.Edges.Clear();
            joinGraph.Edges.AddRange(uniqueEdges);

            //
            // insert the new node into the join graph

            joinGraph.Nodes.Add(newNode);
        }
Exemple #3
0
        /// <summary>
        /// Computes a descriptive query plan for a given Basic Graph Pattern within a given
        /// database context.
        /// </summary>
        /// <param name="context">The database context.</param>
        /// <param name="pattern">The Basic Graph Pattern.</param>
        /// <returns>
        /// A descriptive query plan for the given BGP.
        /// </returns>
        public static QueryPlan ComputePlan(Database context, params Triple <TripleItem, TripleItem, TripleItem>[] pattern)
        {
            //
            // initialize the decision engine
            var decisionEngine = GetDecisionEngine(context);

            //
            // compute the atom collapse
            var collapse = AtomCollapse.Compute(pattern);

            //
            // step 1: compute join graph

            //
            // working copy of collapse graph nodes
            var currentCollapse = new List <ac::Node>();

            foreach (var node in collapse.Nodes)
            {
                currentCollapse.Add(node.Copy());
            }

            List <ac::Node> seeds;
            var             todo = new List <Triple <TripleItem, TripleItem, TripleItem> >();
            var             eval = new List <ac::Node>();

            do
            {
                //
                // compute the seeds
                seeds = ComputeSeeds(currentCollapse);

                //
                // pick one
                var seed = decisionEngine.ChooseSeed(seeds, collapse, currentCollapse).Copy();

                //
                // compute new todo's
                if (todo.Contains(seed.FirstSAP))
                {
                    todo.Remove(seed.FirstSAP);
                }
                foreach (var sap in ComputeNewTodos(seed, currentCollapse))
                {
                    todo.AddIfNotPresent(sap);
                }

                //
                // update the current collapse
                foreach (var node in currentCollapse)
                {
                    if (node.SAPs.Contains(seed.FirstSAP))
                    {
                        node.SAPs.Remove(seed.FirstSAP);
                    }
                }
                currentCollapse.RemoveAll(n => n.SAPs.Count == 0);

                //
                // add the seed to the evaluation list
                eval.Add(seed);
            } while (todo.Count > 0);

            //
            // compute edges
            var collapseEdges = new List <ac::Edge>();

            foreach (var edge in collapse.Edges)
            {
                foreach (var x in eval)
                {
                    foreach (var y in eval)
                    {
                        if (edge.Left.Equals(x) && edge.Right.Equals(y))
                        {
                            collapseEdges.Add(edge);
                        }
                    }
                }
            }

            //
            // create join graph nodes
            var joinNodes = new List <jg::Node>();

            foreach (var cNode in eval)
            {
                var jNode = new jg::Node(cNode.Item, cNode.FirstSAP);
                joinNodes.Add(jNode);
            }

            //
            // create join graph edges
            var joinEdges = new List <jg::Edge>();

            foreach (var cEdge in collapseEdges)
            {
                foreach (var x in joinNodes)
                {
                    foreach (var y in joinNodes)
                    {
                        if (cEdge.Left.Item.Equals(x.Item) && cEdge.Left.FirstSAP.Equals(x.SAP))
                        {
                            if (cEdge.Right.Item.Equals(y.Item) && cEdge.Right.FirstSAP.Equals(y.SAP))
                            {
                                var jEdge = new jg::Edge(x, y);
                                foreach (var lbl in cEdge.Labels)
                                {
                                    jEdge.Labels.Add(lbl);
                                }
                                joinEdges.Add(jEdge);
                            }
                        }
                    }
                }
            }

            //
            // make the join graph
            var joinGraph = new jg::Graph(joinNodes, joinEdges);

            //
            // step 2: compute query plan

            if (joinGraph.Edges.Count == 0)
            {
                var n = joinGraph.Nodes.ElementAt(0);
                n.Operator = decisionEngine.ChooseScan(n);
            }
            else
            {
                while (joinGraph.Nodes.Count > 1)
                {
                    //
                    // choose a join to perform
                    var joinEdge = decisionEngine.ChooseJoinEdge(joinGraph);

                    //
                    // compute the join node for this edge
                    var newNode = decisionEngine.ChooseJoinType(joinEdge);

                    //
                    // merge the nodes of the join edge
                    MergeJoinNodes(joinGraph, joinEdge, newNode);
                }
            }

            //
            // create plan object
            var plan = new QueryPlan(joinGraph.Nodes.ElementAt(0).Operator);

            //
            // assign memory to operators
            AssignMemory(context, plan.Root);

            //
            // return the query plan
            return(plan);
        }