Example #1
0
        /// <summary>
        /// Get a full one height tree with joint edges and unmaterlized edges.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="component"></param>
        /// <returns></returns>
        private OneHeightTree GetNodeUnits(ConnectedComponent graph, MatchComponent component)
        {
            var useOriginalEdge = new List <OneHeightTree>();
            var useRevEdge      = new List <OneHeightTree>();

            // Return node deinfed in the outer context preferably
            foreach (var node in graph.Nodes.Values.Where(n => n.IsFromOuterContext && !component.Nodes.Contains(n)))
            {
                var remainingEdges = node.Neighbors.Where(e => !component.EdgeMaterilizedDict.ContainsKey(e)).ToList();
                if (component.UnmaterializedNodeMapping.ContainsKey(node) ||
                    remainingEdges.Any(e => component.Nodes.Contains(e.SinkNode)))
                {
                    return(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges = remainingEdges
                    });
                }
            }

            foreach (var node in graph.Nodes.Values.Where(n => !component.Nodes.Contains(n)))
            {
                var remainingEdges = node.Neighbors.Where(e => !component.EdgeMaterilizedDict.ContainsKey(e)).ToList();
                if (component.UnmaterializedNodeMapping.ContainsKey(node))
                {
                    useOriginalEdge.Add(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges    = remainingEdges,
                    });
                    break;
                }
                if (remainingEdges.Any(e => component.Nodes.Contains(e.SinkNode)))
                {
                    useRevEdge.Add(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges    = remainingEdges
                    });
                }
            }

            if (useOriginalEdge.Any())
            {
                return(useOriginalEdge[0]);
            }
            if (useRevEdge.Any())
            {
                return(useRevEdge[0]);
            }
            return(null);
        }
Example #2
0
        /// <summary>
        /// Get a full one height tree with joint edges and unmaterlized edges.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="component"></param>
        /// <returns></returns>
        private OneHeightTree GetNodeUnits(ConnectedComponent graph, MatchComponent component)
        {
            foreach (MatchNode node in graph.Nodes.Values.Where(n => !component.Nodes.ContainsKey(n.NodeAlias)))
            {
                List <MatchEdge> remainingEdges = node.Neighbors.Where(e => !component.EdgeMaterilizedDict.ContainsKey(e)).ToList();
                if (component.UnmaterializedNodeMapping.ContainsKey(node) ||
                    remainingEdges.Any(e => component.Nodes.ContainsKey(e.SinkNode.NodeAlias)))
                {
                    return(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges = remainingEdges,
                    });
                }
            }

            return(null);
        }
Example #3
0
        // We firstly think every node are isolated, and we will find subgraphs later
        internal string AddTable(WNamedTableReference table)
        {
            string alias = table.Alias.Value;

            this.TableInputDependency[alias] = new HashSet <string>();
            MatchNode matchNode = new MatchNode()
            {
                NodeAlias        = alias,
                Neighbors        = new List <MatchEdge>(),
                ReverseNeighbors = new List <MatchEdge>(),
                DanglingEdges    = new List <MatchEdge>(),
                Predicates       = new List <WBooleanExpression>(),
                Properties       = new HashSet <string>()
            };
            ConnectedComponent subgraph = new ConnectedComponent();

            subgraph.Nodes[alias] = matchNode;
            this.GraphPattern.ConnectedSubgraphs.Add(subgraph);
            matchNode.Position = this.TableInputDependency.Count;
            return(alias);
        }
        /// <summary>
        /// Get a full one height tree with joint edges and unmaterlized edges,
        /// returns a tuple whose first item is the one height tree and the second item
        /// indicates whether the one height tree only joins with the component's materialized
        /// node on its root.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="component"></param>
        /// <returns></returns>
        private IEnumerable<Tuple<OneHeightTree, bool>> GetNodeUnits(ConnectedComponent graph, MatchComponent component)
        {
            var nodes = graph.Nodes;
            foreach (var node in nodes.Values.Where(e => !graph.IsTailNode[e]))
            {
                var remainingEdges = node.Neighbors.Where(e => !component.EdgeMaterilizedDict.ContainsKey(e)).ToList();

                // If there exists a component's edge pointing to the 1-heright tree's root
                // or a 1-height tree's edge pointing to the component's node, then generates a valid
                // 1-height tree with edges. Otherwise, if a node can be joint to component as a single
                // split node with unmaterialized edges, generates a 1-height tree with a tag set to true.
                if (component.UnmaterializedNodeMapping.ContainsKey(node) ||
                    remainingEdges.Any(e => component.Nodes.Contains(e.SinkNode)))
                {
                    yield return new Tuple<OneHeightTree, bool>(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges = remainingEdges
                    }, false);
                }
                else if (remainingEdges.Count > 0 && component.MaterializedNodeSplitCount.Count > 1 &&
                         component.MaterializedNodeSplitCount.ContainsKey(node))
                {
                    yield return new Tuple<OneHeightTree, bool>(new OneHeightTree
                    {
                        TreeRoot = node,
                        Edges = remainingEdges
                    }, true);
                }
            }
        }
 public abstract List <Tuple <MatchNode, MatchEdge, MatchNode, List <MatchEdge>, List <MatchEdge> > > GetOptimizedTraversalOrder2(ConnectedComponent subGraph);
Example #6
0
        // Greate the MatchGraph of this AggregationBlock. If some free nodes and free edges are connected, they are in the same ConnectedComponent
        internal HashSet <string> CreateMatchGraph(WMatchClause matchClause)
        {
            HashSet <string> freeNodesAndEdges = new HashSet <string>();
            Dictionary <string, MatchPath>          pathCollection     = new Dictionary <string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            Dictionary <string, MatchNode>          nodeCollection     = new Dictionary <string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            Dictionary <string, MatchEdge>          edgeCollection     = new Dictionary <string, MatchEdge>(StringComparer.OrdinalIgnoreCase);
            Dictionary <string, ConnectedComponent> subgraphCollection = new Dictionary <string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);

            // we use Disjoint-set data structure to determine whether tables are in the same component or not.
            UnionFind unionFind = new UnionFind();

            foreach (ConnectedComponent subgraph in this.GraphPattern.ConnectedSubgraphs)
            {
                foreach (KeyValuePair <string, MatchNode> pair in subgraph.Nodes)
                {
                    nodeCollection.Add(pair.Key, pair.Value);
                    unionFind.Add(pair.Key);
                }
            }

            if (matchClause != null)
            {
                foreach (WMatchPath path in matchClause.Paths)
                {
                    int       index         = 0;
                    bool      outOfBlock    = false;
                    MatchEdge edgeToSrcNode = null;

                    for (int count = path.PathEdgeList.Count; index < count; ++index)
                    {
                        WSchemaObjectName currentNodeTableRef = path.PathEdgeList[index].Item1;
                        WEdgeColumnReferenceExpression currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                        WSchemaObjectName nextNodeTableRef = index != count - 1
                            ? path.PathEdgeList[index + 1].Item1
                            : path.Tail;
                        string currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                        string edgeAlias           = currentEdgeColumnRef.Alias;
                        string nextNodeExposedName = nextNodeTableRef != null ? nextNodeTableRef.BaseIdentifier.Value : null;

                        // Get the source node of a path
                        if (!nodeCollection.ContainsKey(currentNodeExposedName))
                        {
                            continue;
                        }
                        MatchNode srcNode = nodeCollection[currentNodeExposedName];

                        // Get the edge of a path, and set required attributes
                        // Because the sourceNode is relative, we need to construct new edges or paths
                        // But they need to share the same predicates and proerties
                        MatchEdge edgeFromSrcNode;
                        if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                        {
                            if (!edgeCollection.ContainsKey(edgeAlias))
                            {
                                edgeCollection[edgeAlias] = new MatchEdge()
                                {
                                    LinkAlias            = edgeAlias,
                                    SourceNode           = srcNode,
                                    EdgeType             = currentEdgeColumnRef.EdgeType,
                                    Predicates           = new List <WBooleanExpression>(),
                                    BindNodeTableObjName = new WSchemaObjectName(),
                                    IsReversed           = false,
                                    Properties           = new List <string>(GraphViewReservedProperties.ReservedEdgeProperties)
                                };
                                unionFind.Add(edgeAlias);
                            }

                            edgeFromSrcNode = new MatchEdge
                            {
                                LinkAlias            = edgeAlias,
                                SourceNode           = srcNode,
                                EdgeType             = edgeCollection[edgeAlias].EdgeType,
                                Predicates           = edgeCollection[edgeAlias].Predicates,
                                BindNodeTableObjName = edgeCollection[edgeAlias].BindNodeTableObjName,
                                IsReversed           = false,
                                Properties           = edgeCollection[edgeAlias].Properties
                            };
                        }
                        else
                        {
                            if (!pathCollection.ContainsKey(edgeAlias))
                            {
                                pathCollection[edgeAlias] = new MatchPath
                                {
                                    SourceNode           = srcNode,
                                    LinkAlias            = edgeAlias,
                                    Predicates           = new List <WBooleanExpression>(),
                                    BindNodeTableObjName = new WSchemaObjectName(),
                                    MinLength            = currentEdgeColumnRef.MinLength,
                                    MaxLength            = currentEdgeColumnRef.MaxLength,
                                    ReferencePathInfo    = false,
                                    AttributeValueDict   = currentEdgeColumnRef.AttributeValueDict,
                                    IsReversed           = false,
                                    EdgeType             = currentEdgeColumnRef.EdgeType,
                                    Properties           = new List <string>(GraphViewReservedProperties.ReservedEdgeProperties)
                                };
                            }

                            edgeFromSrcNode = new MatchPath
                            {
                                SourceNode           = srcNode,
                                LinkAlias            = edgeAlias,
                                Predicates           = pathCollection[edgeAlias].Predicates,
                                BindNodeTableObjName = pathCollection[edgeAlias].BindNodeTableObjName,
                                MinLength            = pathCollection[edgeAlias].MinLength,
                                MaxLength            = pathCollection[edgeAlias].MaxLength,
                                ReferencePathInfo    = false,
                                AttributeValueDict   = pathCollection[edgeAlias].AttributeValueDict,
                                IsReversed           = false,
                                EdgeType             = pathCollection[edgeAlias].EdgeType,
                                Properties           = pathCollection[edgeAlias].Properties
                            };
                        }

                        if (path.IsReversed)
                        {
                            unionFind.Union(edgeAlias, currentNodeExposedName);
                        }
                        else
                        {
                            unionFind.Union(currentNodeExposedName, edgeAlias);
                        }

                        if (edgeToSrcNode != null)
                        {
                            edgeToSrcNode.SinkNode = srcNode;

                            if (!(edgeToSrcNode is MatchPath))
                            {
                                // Construct reverse edge
                                MatchEdge reverseEdge = new MatchEdge
                                {
                                    SourceNode           = edgeToSrcNode.SinkNode,
                                    SinkNode             = edgeToSrcNode.SourceNode,
                                    LinkAlias            = edgeToSrcNode.LinkAlias,
                                    Predicates           = edgeToSrcNode.Predicates,
                                    BindNodeTableObjName = edgeToSrcNode.BindNodeTableObjName,
                                    IsReversed           = true,
                                    EdgeType             = edgeToSrcNode.EdgeType,
                                    Properties           = edgeToSrcNode.Properties,
                                };
                                srcNode.ReverseNeighbors.Add(reverseEdge);
                            }
                        }

                        edgeToSrcNode = edgeFromSrcNode;

                        // Add this edge to node's neightbors
                        if (nextNodeExposedName != null)
                        {
                            if (path.IsReversed)
                            {
                                unionFind.Union(nextNodeExposedName, edgeAlias);
                            }
                            else
                            {
                                unionFind.Union(edgeAlias, nextNodeExposedName);
                            }

                            srcNode.Neighbors.Add(edgeFromSrcNode);
                        }
                        // Add this edge to node's dangling edges
                        else
                        {
                            srcNode.DanglingEdges.Add(edgeFromSrcNode);
                        }
                    }

                    if (path.Tail == null)
                    {
                        continue;
                    }

                    // Get destination node of a path
                    string tailExposedName = path.Tail.BaseIdentifier.Value;

                    if (!nodeCollection.ContainsKey(tailExposedName))
                    {
                        continue;
                    }

                    MatchNode destNode = nodeCollection[tailExposedName];

                    if (edgeToSrcNode != null)
                    {
                        edgeToSrcNode.SinkNode = destNode;
                        if (!(edgeToSrcNode is MatchPath))
                        {
                            // Construct reverse edge
                            MatchEdge reverseEdge = new MatchEdge
                            {
                                SourceNode           = edgeToSrcNode.SinkNode,
                                SinkNode             = edgeToSrcNode.SourceNode,
                                LinkAlias            = edgeToSrcNode.LinkAlias,
                                Predicates           = edgeToSrcNode.Predicates,
                                BindNodeTableObjName = edgeToSrcNode.BindNodeTableObjName,
                                IsReversed           = true,
                                EdgeType             = edgeToSrcNode.EdgeType,
                                Properties           = edgeToSrcNode.Properties,
                            };
                            destNode.ReverseNeighbors.Add(reverseEdge);
                        }
                    }
                }
            }

            // Use union find algorithmn to define which subgraph does a node belong to and put it into where it belongs to.
            foreach (var node in nodeCollection)
            {
                freeNodesAndEdges.Add(node.Key);
                string root = unionFind.Find(node.Key);

                ConnectedComponent subGraph;
                if (!subgraphCollection.ContainsKey(root))
                {
                    subGraph = new ConnectedComponent();
                    subgraphCollection[root] = subGraph;
                }
                else
                {
                    subGraph = subgraphCollection[root];
                }

                subGraph.Nodes[node.Key] = node.Value;

                subGraph.IsTailNode[node.Value] = false;

                foreach (MatchEdge edge in node.Value.Neighbors)
                {
                    subGraph.Edges[edge.LinkAlias] = edge;
                    freeNodesAndEdges.Add(edge.LinkAlias);
                }

                foreach (MatchEdge edge in node.Value.DanglingEdges)
                {
                    subGraph.Edges[edge.LinkAlias] = edge;
                    edge.IsDanglingEdge            = true;
                    freeNodesAndEdges.Add(edge.LinkAlias);
                }

                if (node.Value.Neighbors.Count + node.Value.ReverseNeighbors.Count + node.Value.DanglingEdges.Count > 0)
                {
                    node.Value.Properties.Add(GremlinKeyword.Star);
                }
            }

            this.GraphPattern = new MatchGraph(subgraphCollection.Values.ToList());

            return(freeNodesAndEdges);
        }
        /// <summary>
        /// Constructs the graph pattern specified by the MATCH clause. 
        /// The graph pattern may consist of multiple fully-connected sub-graphs.
        /// </summary>
        /// <param name="query">The SELECT query block</param>
        /// <returns>A graph object contains all the connected componeents</returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            if (query == null || query.MatchClause == null)
                return null;

            var columnsOfNodeTables = _graphMetaData.ColumnsOfNodeTables;
            var nodeViewMapping = _graphMetaData.NodeViewMapping;
            var unionFind = new UnionFind();
            var edgeColumnToAliasesDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            var pathDictionary = new Dictionary<string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            var reversedEdgeDict = new Dictionary<string, MatchEdge>();
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            unionFind.Parent = parent;

            // Constructs the graph pattern specified by the path expressions in the MATCH clause
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathEdgeList.Count; index < count; ++index)
                {
                    var currentNodeTableRef = path.PathEdgeList[index].Item1;
                    var currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                    var currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                    var nextNodeTableRef = index != count - 1
                        ? path.PathEdgeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNodeTableRef.BaseIdentifier.Value;
                    var patternNode = nodes.GetOrCreate(currentNodeExposedName);
                    if (patternNode.NodeAlias == null)
                    {
                        patternNode.NodeAlias = currentNodeExposedName;
                        patternNode.Neighbors = new List<MatchEdge>();
                        patternNode.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            patternNode.NodeTableObjectName = nodeTable.TableObjectName;
                            if (patternNode.NodeTableObjectName.SchemaIdentifier == null)
                                patternNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                        }
                    }

                    Identifier edgeIdentifier = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last();
                    string schema = patternNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                    string nodeTableName = patternNode.NodeTableObjectName.BaseIdentifier.Value;
                    string bindTableName =
                        _context.EdgeNodeBinding[
                            new Tuple<string, string>(nodeTableName.ToLower(), edgeIdentifier.Value.ToLower())].ToLower();
                    var bindNodeTableObjName = new WSchemaObjectName(
                        new Identifier {Value = schema},
                        new Identifier {Value = bindTableName}
                        );
                    var edgeColumn =
                        columnsOfNodeTables[
                            WNamedTableReference.SchemaNameToTuple(bindNodeTableObjName)][
                                currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value];
                    string edgeAlias = currentEdgeColumnRef.Alias;
                    //string revEdgeAlias = edgeAlias;
                    bool isReversed = path.IsReversed || edgeColumn.EdgeInfo.IsReversedEdge;
                    string currentRevEdgeName = null;

                    // get original edge name
                    var currentEdgeName = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value;
                    var originalSourceName = isReversed ?
                        (_context[nextNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value
                        : (_context[currentNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value;

                    if (isReversed)
                    {
                        var i = currentEdgeName.IndexOf(originalSourceName, StringComparison.OrdinalIgnoreCase) +
                            originalSourceName.Length;
                        currentRevEdgeName = currentEdgeName.Substring(i + 1,
                            currentEdgeName.Length - "Reversed".Length - i - 1);
                    }
                    else
                    {
                        var srcTuple = WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName);
                        // [nodeView]-[edge]->[node/nodeView]
                        if (edgeColumn.Role == WNodeTableColumnRole.Edge && nodeViewMapping.ContainsKey(srcTuple))
                        {
                            var physicalNodeName =
                                _context.EdgeNodeBinding[new Tuple<string, string>(srcTuple.Item2, currentEdgeName.ToLower())];
                            currentRevEdgeName = physicalNodeName + "_" + currentEdgeName + "Reversed";
                        }
                        else
                        {
                            currentRevEdgeName = originalSourceName + "_" + currentEdgeName + "Reversed";
                        }
                    }

                    if (edgeAlias == null)
                    {
                        edgeAlias = !isReversed
                            ? string.Format("{0}_{1}_{2}", currentNodeExposedName, currentEdgeName, nextNodeExposedName)
                            : string.Format("{0}_{1}_{2}", nextNodeExposedName, currentRevEdgeName, currentNodeExposedName);

                        //when the current edge is a reversed edge, the key should still be the original edge name
                        //e.g.: TestDeleteEdgeWithTableAlias
                        var edgeNameKey = isReversed ? currentRevEdgeName : currentEdgeName;
                        if (edgeColumnToAliasesDict.ContainsKey(edgeNameKey))
                        {
                            edgeColumnToAliasesDict[edgeNameKey].Add(edgeAlias);
                        }
                        else
                        {
                            edgeColumnToAliasesDict.Add(edgeNameKey, new List<string> { edgeAlias });
                        }
                    }

                    MatchEdge edge, revEdge;
                    if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                    {
                        var isEdgeView = edgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var hasRevEdge = edgeColumn.EdgeInfo.HasReversedEdge;
                        edge = new MatchEdge
                        {
                            IsEdgeView = isEdgeView,
                            IsReversedEdge = false,
                            HasReversedEdge = hasRevEdge,
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName = bindNodeTableObjName,
                        };
                        _context.AddEdgeReference(edge);

                        if (hasRevEdge)
                        {
                            revEdge = new MatchEdge
                            {
                                IsEdgeView = isEdgeView,
                                IsReversedEdge = true,
                                SinkNode = patternNode,
                                EdgeColumn = new WEdgeColumnReferenceExpression()
                                {
                                    ColumnType = currentEdgeColumnRef.ColumnType,
                                    Alias = currentEdgeColumnRef.Alias,
                                    MaxLength = currentEdgeColumnRef.MaxLength,
                                    MinLength = currentEdgeColumnRef.MinLength,
                                    AttributeValueDict = currentEdgeColumnRef.AttributeValueDict,
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier()
                                    {
                                        QuoteType = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().QuoteType,
                                        Value = currentRevEdgeName,
                                    }),
                                },
                                EdgeAlias = edgeAlias,
                                //EdgeAlias = revEdgeAlias,
                            };
                            reversedEdgeDict[edge.EdgeAlias] = revEdge;
                        }
                    }
                    else
                    {
                        MatchPath matchPath = new MatchPath
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                            MinLength = currentEdgeColumnRef.MinLength,
                            MaxLength = currentEdgeColumnRef.MaxLength,
                            ReferencePathInfo = false,
                            AttributeValueDict = currentEdgeColumnRef.AttributeValueDict
                        };
                        _context.AddEdgeReference(matchPath);
                        pathDictionary[edgeAlias] = matchPath;
                        edge = matchPath;
                    }

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = patternNode;
                        if (preEdge.HasReversedEdge)
                        {
                            //var preSourceNode = preEdge.SourceNode;
                            var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                            var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                            var preEdgeColumn =
                                columnsOfNodeTables[
                                    WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                        preEdgeColName];
                            var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                            var isNodeView =
                                _graphMetaData.NodeViewMapping.ContainsKey(
                                    WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName));

                            reversedEdgeDict[preEdge.EdgeAlias].SourceNode = patternNode;
                            // [node/nodeView]-[edgeView]->[node/nodeView]
                            if (isEdgeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                            }
                            // [node/nodeView]-[edge]->[nodeView]
                            else if (!isEdgeView && isNodeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = "dbo" },
                                    new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                    );
                            }
                            else
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = schema },
                                    new Identifier { Value = bindTableName }
                                    );
                            }
                        }
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);

                    patternNode.Neighbors.Add(edge);

                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.NodeTableObjectName = nodeTable.TableObjectName;
                        if (tailNode.NodeTableObjectName.SchemaIdentifier == null)
                            tailNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                    }
                }
                if (preEdge != null)
                {
                    preEdge.SinkNode = tailNode;
                    if (preEdge.HasReversedEdge)
                    {
                        var schema = tailNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                        var nodeTableName = tailNode.NodeTableObjectName.BaseIdentifier.Value;
                        //var preSourceNode = preEdge.SourceNode;
                        var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                        var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                        var preEdgeColumn =
                            columnsOfNodeTables[
                                WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                    preEdgeColName];
                        var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var isNodeView =
                            _graphMetaData.NodeViewMapping.ContainsKey(
                                WNamedTableReference.SchemaNameToTuple(tailNode.NodeTableObjectName));
                        reversedEdgeDict[preEdge.EdgeAlias].SourceNode = tailNode;
                        // [node/nodeView]-[edgeView]->[node/nodeView]
                        if (isEdgeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                        }
                        // [node/nodeView]-[edge]->[nodeView]
                        else if (!isEdgeView && isNodeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = "dbo" },
                                new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                );
                        }
                        else
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = schema },
                                new Identifier { Value = nodeTableName.ToLower() }
                                );
                        }
                    }
                }
            }

            // Puts nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            var graph = new MatchGraph
            {
                ReversedEdgeDict = reversedEdgeDict,
                ConnectedSubGraphs = connectedSubGraphs,
                SourceNodeStatisticsDict = new Dictionary<Tuple<string, bool>, Statistics>(),
            };
            unionFind.Parent = null;

            // When an edge in the MATCH clause is not associated with an alias,
            // assigns to it a default alias: sourceAlias_EdgeColumnName_sinkAlias.
            // Also rewrites edge attributes anywhere in the query that can be bound to this default alias.
            var replaceTableRefVisitor = new ReplaceEdgeReferenceVisitor();
            replaceTableRefVisitor.Invoke(query, edgeColumnToAliasesDict);

            // Rematerializes node tables in the MATCH clause which are defined in the upper-level context
            // and join them with the upper-level table references.
            RematerilizeExtrenalNodeTableReference(query, nodes);

            // Transforms the path reference in the SELECT elements into a
            // scalar function to display path information.
            TransformPathInfoDisplaySelectElement(query, pathDictionary);

            return graph;
        }
 public abstract List <Tuple <MatchNode, MatchEdge> > GetOptimizedTraversalOrder(ConnectedComponent subGraph, out Dictionary <string, List <Tuple <MatchEdge, MaterializedEdgeType> > > nodeToMaterializedEdgesDict);
 /// <summary>
 /// Get a full one height tree with joint edges and unmaterlized edges,
 /// returns a tuple whose first item is the one height tree and the second item
 /// indicates whether the one height tree only joins with the component's materialized
 /// node on its root.
 /// </summary>
 /// <param name="graph"></param>
 /// <param name="component"></param>
 /// <returns></returns>
 private IEnumerable<OneHeightTree> GetNodeUnits(ConnectedComponent graph, MatchComponent component)
 {
     //var nodes = graph.Nodes;
     //foreach (var node in graph.Nodes.Values)
     foreach (var node in graph.Nodes.Values.Where(n => !component.Nodes.Contains(n)))
     {
         var remainingEdges = node.Neighbors.Where(e => !component.EdgeMaterilizedDict.ContainsKey(e)).ToList();
         if (component.UnmaterializedNodeMapping.ContainsKey(node) ||
             remainingEdges.Any(e => component.Nodes.Contains(e.SinkNode)))
         {
             yield return new OneHeightTree
             {
                 TreeRoot = node,
                 Edges = remainingEdges
             };
         }
     }
 }
        /// <summary>
        /// Get the optimal join component for the given connected graph
        /// 1. Generate the initial states
        /// 2. DP, Iterate on each states: 
        ///     Get smallest join units -> Enumerate on all possible combination of the join units
        ///     -> Join to the current component to get the next states 
        ///     -> Those components with the largest average size per edge will be eliminate if exceeding the upper bound
        /// 3. If all the components has reached its end states, return the component with the smallest join cost
        /// </summary>
        /// <param name="subGraph"></param>
        /// <param name="revEdgeDict"></param>
        /// <param name="srcNodeStatisticsDict"></param>
        /// <returns></returns>
        private MatchComponent ConstructComponent(ConnectedComponent subGraph, Dictionary<string, MatchEdge> revEdgeDict,
            Dictionary<Tuple<string, bool>, Statistics> srcNodeStatisticsDict)
        {
            //var componentStates = new List<MatchComponent>();
            MatchComponent optimalFinalComponent = null;

            //Init
            double maxValue = Double.MinValue;
            var componentStates = subGraph.Nodes.Select(node => new MatchComponent(node.Value)).ToList();

            // DP
            while (componentStates.Any())
            {
                int maxIndex = -1;
                var nextCompnentStates = new List<MatchComponent>();

                // Iterate on current components
                foreach (var curComponent in componentStates)
                {
                    var nodeUnits = GetNodeUnits(subGraph, curComponent);
                    if (!nodeUnits.Any()
                        && curComponent.ActiveNodeCount == subGraph.ActiveNodeCount
                        && curComponent.EdgeMaterilizedDict.Count(e => e.Value == true) == subGraph.EdgeCount
                        )
                    {
                        if (optimalFinalComponent == null || curComponent.Cost < optimalFinalComponent.Cost)
                        {
                            optimalFinalComponent = curComponent;

                        }
                        continue;
                    }

                    var candidateUnits = _pruningStrategy.GetCandidateUnits(nodeUnits, curComponent, revEdgeDict);

                    // Iterates on the candidate node units & add it to the current component to generate next states
                    foreach (var candidateUnit in candidateUnits)
                    {
                        // Pre-filter. If the lower bound of the current totoal join cost
                        // > current optimal join cost, prunes this component.
                        if (optimalFinalComponent != null)
                        {
                            double candidateSize = candidateUnit.TreeRoot.EstimatedRows*
                                                   candidateUnit.PreMatOutgoingEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur*next)*
                                                   candidateUnit.PostMatOutgoingEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur*next)*
                                                   candidateUnit.UnmaterializedEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur*next);
                            double costLowerBound = curComponent.Cardinality*
                                                    candidateUnit.PreMatIncomingEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur * next)
                                                    + candidateSize;

                            if (candidateUnit.JoinHint == JoinHint.Loop)
                                costLowerBound = Math.Min(costLowerBound,
                                    Math.Log(candidateUnit.TreeRoot.EstimatedRows, 512));
                            if (curComponent.Cost + costLowerBound >
                                optimalFinalComponent.Cost )
                            {
                                continue;
                            }
                        }

                        var newComponent = curComponent.GetNextState(candidateUnit, _statisticsCalculator, _graphMetaData, srcNodeStatisticsDict);

                        if (nextCompnentStates.Count >= MaxStates)
                        {
                            if (maxIndex < 0)
                            {
                                var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                maxIndex = tuple.Item1;
                                maxValue = tuple.Item2;
                            }
                            else
                            {
                                int compEdgeCount = newComponent.EdgeMaterilizedDict.Count;
                                compEdgeCount = compEdgeCount == 0 ? 1 : compEdgeCount;
                                if (newComponent.Cost/compEdgeCount < maxValue)
                                {
                                    nextCompnentStates[maxIndex] = newComponent;
                                    var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                    maxIndex = tuple.Item1;
                                    maxValue = tuple.Item2;
                                }
                                continue;
                            }
                        }
                        nextCompnentStates.Add(newComponent);
                    }
                }
                componentStates = nextCompnentStates;
            }

            return optimalFinalComponent;
        }
        /// <summary>
        /// Get the optimal join component for the given connected graph
        /// 1. Generate the initial states
        /// 2. DP, Iterate on each states: 
        ///     Get smallest join units -> Enumerate on all possible combination of the join units
        ///     -> Join to the current component to get the next states 
        ///     -> Those components with the largest average size per edge will be eliminate if exceeding the upper bound
        /// 3. If all the components has reached its end states, return the component with the smallest join cost
        /// </summary>
        /// <param name="subGraph"></param>
        /// <returns></returns>
        private MatchComponent ConstructComponent(ConnectedComponent subGraph)
        {
            var componentStates = new List<MatchComponent>();
            MatchComponent optimalFinalComponent = null;

            //Init
            double maxValue = Double.MinValue;
            foreach (var node in subGraph.Nodes)
            {
                if (!subGraph.IsTailNode[node.Value])
                {
                    // Enumerate on each edge for a node to generate the intial states
                    var nodeEdgeCount = node.Value.Neighbors.Count;
                    int eNum = (int) Math.Pow(2, nodeEdgeCount) - 1;
                    while (eNum > 0)
                    {
                        var nodeInitialEdges = new List<MatchEdge>();
                        for (int i = 0; i < nodeEdgeCount; i++)
                        {
                            int index = (1 << i);
                            if ((eNum & index) != 0)
                            {
                                nodeInitialEdges.Add(node.Value.Neighbors[i]);
                            }
                        }
                        componentStates.Add(new MatchComponent(node.Value, nodeInitialEdges, _graphMetaData));
                        eNum--;
                    }
                }
            }


            // DP
            while (componentStates.Any())
            {
                int maxIndex = -1;
                var nextCompnentStates = new List<MatchComponent>();

                // Iterate on current components
                foreach (var curComponent in componentStates)
                {
                    var nodeUnits = GetNodeUnits(subGraph, curComponent);
                    if (!nodeUnits.Any()
                        && curComponent.ActiveNodeCount == subGraph.ActiveNodeCount
                        && curComponent.EdgeMaterilizedDict.Count == subGraph.EdgeCount
                        )
                    {
                        if (optimalFinalComponent == null || curComponent.Cost < optimalFinalComponent.Cost)
                        {
                            optimalFinalComponent = curComponent;
                            
                        }
                        continue;
                    }

                    var candidateUnits = _pruningStrategy.GetCandidateUnits(nodeUnits, curComponent);

                    // Iterates on the candidate node units & add it to the current component to generate next states
                    foreach (var candidateUnit in candidateUnits)
                    {
                        // Pre-filter. If the lower bound of the current totoal join cost
                        // > current optimal join cost, prunes this component.
                        if (optimalFinalComponent != null)
                        {
                            double candidateSize = candidateUnit.TreeRoot.EstimatedRows*
                                                   candidateUnit.UnmaterializedEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur*next)*
                                                   candidateUnit.MaterializedEdges.Select(e => e.AverageDegree)
                                                       .Aggregate(1.0, (cur, next) => cur*next);
                            double costLowerBound = curComponent.Cardinality + candidateSize;
                            if (candidateUnit.MaterializedEdges.Count == 0)
                                costLowerBound = Math.Min(costLowerBound,
                                    Math.Log(candidateUnit.TreeRoot.EstimatedRows, 512));
                            if (curComponent.Cost + costLowerBound >
                                optimalFinalComponent.Cost )
                            {
                                continue;
                            }
                        }

                        var newComponent = curComponent.GetNextState(candidateUnit, _statisticsCalculator,_graphMetaData);
                        if (nextCompnentStates.Count >= MaxStates)
                        {
                            if (maxIndex < 0)
                            {
                                var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                maxIndex = tuple.Item1;
                                maxValue = tuple.Item2;
                            }
                            else
                            {
                                int compEdgeCount = newComponent.EdgeMaterilizedDict.Count;
                                compEdgeCount = compEdgeCount == 0 ? 1 : compEdgeCount;
                                if (newComponent.Cost/compEdgeCount < maxValue)
                                {
                                    nextCompnentStates[maxIndex] = newComponent;
                                    var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                    maxIndex = tuple.Item1;
                                    maxValue = tuple.Item2;
                                }
                                continue;
                            }
                        }
                        nextCompnentStates.Add(newComponent);
                    }
                }
                componentStates = nextCompnentStates;
            }

            return optimalFinalComponent;

        }
Example #12
0
        public override List <Tuple <MatchNode, MatchEdge> > GetOptimizedTraversalOrder(ConnectedComponent subGraph, out Dictionary <string, List <Tuple <MatchEdge, MaterializedEdgeType> > > nodeToMaterializedEdgesDict)
        {
            nodeToMaterializedEdgesDict = null;
            if (subGraph.Nodes.Count == 1)
            {
                return
                    new List <Tuple <MatchNode, MatchEdge> >
                    {
                        new Tuple <MatchNode, MatchEdge>(subGraph.Nodes.First().Value, null),
                    }
            }
            ;

            // If it exists, pick a node defined in the outer context as the start point
            var componentStates = subGraph.Nodes.Where(node => node.Value.IsFromOuterContext).
                                  Select(node => new MatchComponent(node.Value)).Take(1).ToList();

            // Else, pick a node without incoming edges as the start point
            if (!componentStates.Any())
            {
                componentStates = subGraph.Nodes.Where(node => node.Value.ReverseNeighbors.Count == 0).
                                  Select(node => new MatchComponent(node.Value)).Take(1).ToList();
            }
            // Otherwise, pick a node randomly as the start point
            else if (!componentStates.Any())
            {
                componentStates.Add(new MatchComponent(subGraph.Nodes.First().Value));
            }

            // DP
            while (componentStates.Any())
            {
                var nextCompnentStates = new List <MatchComponent>();

                // Iterate on current components
                foreach (var curComponent in componentStates)
                {
                    var nodeUnits = GetNodeUnits(subGraph, curComponent);
                    if (nodeUnits == null &&
                        curComponent.ActiveNodeCount == subGraph.ActiveNodeCount &&
                        curComponent.EdgeMaterilizedDict.Count(e => e.Value == true) == subGraph.EdgeCount)
                    {
                        curComponent.TraversalChain.Reverse();
                        nodeToMaterializedEdgesDict = curComponent.NodeToMaterializedEdgesDict;
                        return(curComponent.TraversalChain);
                    }

                    var candidateUnit = GetCandidateUnits(nodeUnits, curComponent);
                    // Add it to the current component to generate next states
                    var newComponent = GetNextState(curComponent, candidateUnit);

                    if (nextCompnentStates.Count >= MaxStates)
                    {
                        throw new GraphViewException("This graph pattern is not supported yet.");
                    }

                    nextCompnentStates.Add(newComponent);
                }
                componentStates = nextCompnentStates;
            }

            return(null);
        }
        /// <summary>
        /// Construct Graph from the match clause. The Graph can consist of multiple connected SubGraph.
        /// Not supported in this version
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            var unionFind = new UnionFind();
            if (query.MatchClause == null)
                return null;
            var edgeTableReferenceDict = new Dictionary<string, List<string>>(StringComparer.CurrentCultureIgnoreCase);
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.CurrentCultureIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.CurrentCultureIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
            unionFind.Parent = parent;
            HashSet<Tuple<string, string>> nodeTypes = new HashSet<Tuple<string, string>>();

            //Construct Graph from Match Pattern
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathNodeList.Count; index < count; ++index)
                {
                    var currentNode = path.PathNodeList[index].Item1;
                    var currentEdge = path.PathNodeList[index].Item2;
                    var currentNodeExposedName = currentNode.BaseIdentifier.Value;
                    var nextNode = index != count - 1
                        ? path.PathNodeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNode.BaseIdentifier.Value;
                    var node = nodes.GetOrCreate(currentNodeExposedName);
                    if (node.NodeAlias == null)
                    {
                        node.NodeAlias = currentNodeExposedName;
                        node.Neighbors = new List<MatchEdge>();
                        node.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            node.TableObjectName = nodeTable.TableObjectName;
                            if (node.TableObjectName.SchemaIdentifier == null)
                                node.TableObjectName.Identifiers.Insert(0, new Identifier { Value = "dbo" });
                            var nodeTypeTuple = WNamedTableReference.SchemaNameToTuple(node.TableObjectName);
                            if (!nodeTypes.Contains(nodeTypeTuple))
                                nodeTypes.Add(nodeTypeTuple);

                        }
                    }

                    if (currentEdge.AliasRole == AliasType.Default)
                    {
                        var currentEdgeName = currentEdge.MultiPartIdentifier.Identifiers.Last().Value;
                        if (edgeTableReferenceDict.ContainsKey(currentEdgeName))
                        {
                            edgeTableReferenceDict[currentEdgeName].Add(currentEdge.Alias);
                        }
                        else
                        {
                            edgeTableReferenceDict.Add(currentEdgeName, new List<string> { currentEdge.Alias });
                        }
                    }
                    var edge = new MatchEdge
                    {
                        SourceNode = node,
                        EdgeColumn = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier
                            {
                                Identifiers = new List<Identifier>
                                {
                                    new Identifier {Value = node.NodeAlias},
                                    currentEdge.MultiPartIdentifier.Identifiers.Last()
                                }
                            }
                        },
                        EdgeAlias = currentEdge.Alias
                    };

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = node;
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);


                    node.Neighbors.Add(edge);


                    _context.AddEdgeReference(currentEdge.Alias, edge.SourceNode.TableObjectName, currentEdge);
                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.TableObjectName = nodeTable.TableObjectName;
                        if (tailNode.TableObjectName.SchemaIdentifier == null)
                            tailNode.TableObjectName.Identifiers.Insert(0, new Identifier { Value = "dbo" });
                        var nodeTypeTuple = WNamedTableReference.SchemaNameToTuple(tailNode.TableObjectName);
                        if (!nodeTypes.Contains(nodeTypeTuple))
                            nodeTypes.Add(nodeTypeTuple);
                    }
                }
                if (preEdge != null) 
                    preEdge.SinkNode = tailNode;
            }

            // Put nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            // Replace Edge name alias with proper alias in the query
            var replaceTableRefVisitor = new ReplaceTableRefVisitor();
            replaceTableRefVisitor.Invoke(query, edgeTableReferenceDict);
            

            // If a table alias in the MATCH clause is defined in an upper-level context, 
            // to be able to translate this MATCH clause, this table alias must be re-materialized 
            // in the FROM clause of the current context and joined with the corresponding table
            // in the upper-level context. 
            var tableRefs = query.FromClause.TableReferences;
            var tableSet = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
            var newTableRefs = new List<WTableReference>();
            for (int index = 0; index < tableRefs.Count; ++index)
            {
                var table = tableRefs[index] as WNamedTableReference;
                if (table == null)
                {
                    newTableRefs.Add(tableRefs[index]);
                    continue;
                }
                var tableTuple = WNamedTableReference.SchemaNameToTuple(table.TableObjectName);
                if (!nodeTypes.Contains(tableTuple))
                {
                    newTableRefs.Add(table);
                }
                else
                {
                    tableSet.Add(table.ExposedName.Value);
                }
            }
            query.FromClause = new WFromClause
            {
                TableReferences = newTableRefs,
            };
            WBooleanExpression whereCondiction = null;
            foreach (var node in nodes)
            {
                if (!tableSet.Contains(node.Key))
                {
                    node.Value.External = true;
                    var newWhereCondition = new WBooleanComparisonExpression
                    {
                        ComparisonType = BooleanComparisonType.Equals,
                        FirstExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(
                                new Identifier { Value = node.Key },
                                new Identifier { Value = "GlobalNodeId" })
                        },
                        SecondExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(
                                new Identifier { Value = node.Value.RefAlias },
                                new Identifier { Value = "GlobalNodeId" })
                        },
                    };
                    whereCondiction = WBooleanBinaryExpression.Conjunction(whereCondiction, newWhereCondition);
                }
            }
            if (whereCondiction != null)
            {
                if (query.WhereClause == null)
                {
                    query.WhereClause = new WWhereClause { SearchCondition = whereCondiction };
                }
                else
                {
                    if (query.WhereClause.SearchCondition == null)
                    {
                        query.WhereClause.SearchCondition = whereCondiction;
                    }
                    else
                    {
                        query.WhereClause.SearchCondition = new WBooleanBinaryExpression
                        {
                            BooleanExpressionType = BooleanBinaryExpressionType.And,
                            FirstExpr = new WBooleanParenthesisExpression
                            {
                                Expression = query.WhereClause.SearchCondition
                            },
                            SecondExpr = new WBooleanParenthesisExpression
                            {
                                Expression = whereCondiction
                            }
                        };
                    }
                }
            }

            var graph = new MatchGraph
            {
                ConnectedSubGraphs = connectedSubGraphs,
                NodeTypesSet = nodeTypes,
            };
            unionFind.Parent = null;
            return graph;
        }
        /// <summary>
        /// Get the optimal join component for the given connected graph
        /// 1. Generate the initial states
        /// 2. DP, Iterate on each states: 
        ///     Get smallest join units -> Enumerate on all possible combination of the join units
        ///     -> Join to the current component to get the next states 
        ///     -> Those components with the largest average size per edge will be eliminate if exceeding the upper bound
        /// 3. If all the components has reached its end states, return the component with the smallest join cost
        /// </summary>
        /// <param name="subGraph"></param>
        /// <returns></returns>
        public MatchComponent ConstructComponent(ConnectedComponent subGraph)
        {
            var componentStates = new List<MatchComponent>();
            var nodes = subGraph.Nodes;
            var edges = subGraph.Edges;
            int nodeCount = subGraph.IsTailNode.Count(e => !e.Value);
            MatchComponent finishedComponent = null;

            //Init
            int maxIndex = -1;
            double maxValue = Double.MinValue;
            foreach (var node in nodes)
            {
                if (!subGraph.IsTailNode[node.Value])
                {
                // Enumerate on each edge for a node to generate the intial states
                var edgeCount = node.Value.Neighbors.Count;
                int eNum = (int) Math.Pow(2, edgeCount) - 1;
                while (eNum > 0)
                {
                    var nodeInitialEdges = new List<MatchEdge>();
                    for (int i = 0; i < edgeCount; i++)
                    {
                        int index = (1 << i);
                        if ((eNum & index) != 0)
                        {
                            nodeInitialEdges.Add(node.Value.Neighbors[i]);
                        }
                    }
                        componentStates.Add(new MatchComponent(node.Value, nodeInitialEdges, _context));
                    eNum--;
                }
                }
            }


            // DP
            while (componentStates.Any())
            {
                maxIndex = -1;
                var nextCompnentStates = new List<MatchComponent>();

                // Iterate on current components
                foreach (var curComponent in componentStates)
                {
                    var nodeUnits = GetNodeUnits(subGraph, curComponent).ToList();
                    if (!nodeUnits.Any())
                    {
                        if (finishedComponent == null || curComponent.Cost < finishedComponent.Cost)
                        {
                            finishedComponent = curComponent;
                        }
                        continue;
                    }


                    var candidateUnits = _pruningStrategy.GetCandidateUnits(nodeUnits, curComponent);

                    // Iterate on the candidate node units & add it to the current component to generate next states
                    foreach (var candidateUnit in candidateUnits)
                    {
                        // Pre-filter
                        if (finishedComponent != null &&
                            (curComponent.Size +
                             candidateUnit.TreeRoot.EstimatedRows*
                             candidateUnit.UnmaterializedEdges.Select(e => e.AverageDegree)
                                 .Aggregate(1.0, (cur, next) => cur*next)*
                             candidateUnit.MaterializedEdges.Select(e => e.AverageDegree)
                                 .Aggregate(1.0, (cur, next) => cur*next) >
                             finishedComponent.Cost))
                        {
                            continue;
                        }

                        // TODO : redundant work if newSize>maxvalue
                        var newComponent = curComponent.GetNextState(candidateUnit, _tableIdDensity, _statisticsCalculator);
                        if (nextCompnentStates.Count >= MaxStates)
                        {
                            if (maxIndex < 0)
                            {
                                var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                maxIndex = tuple.Item1;
                                maxValue = tuple.Item2;
                            }
                            else
                            {
                                int edgeCount = newComponent.EdgeMaterilizedDict.Count;
                                edgeCount = edgeCount == 0 ? 1 : edgeCount;
                                if (newComponent.Cost / edgeCount < maxValue)
                                {
                                    var temp = nextCompnentStates[maxIndex];
                                    nextCompnentStates[maxIndex] = newComponent;
                                    var tuple = GetMostExpensiveMatchComponent(nextCompnentStates);
                                    maxIndex = tuple.Item1;
                                    maxValue = tuple.Item2;
                                }
                                continue;
                            }
                        }
                        nextCompnentStates.Add(newComponent);
                    }
                }
                componentStates = nextCompnentStates;
            }

            return finishedComponent;

        }
        /// <summary>
        /// Get a full one height tree with joint edges and unmaterlized edges,
        /// returns a tuple whose first item is the one height tree and the second item
        /// indicates whether the one height tree only joins with the component's materialized
        /// node on its root.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="component"></param>
        /// <returns></returns>
        public IEnumerable<Tuple<OneHeightTree,bool>> GetNodeUnits(ConnectedComponent graph, MatchComponent component)
        {
            var nodes = graph.Nodes;
            foreach (var node in nodes.Values.Where(e => !graph.IsTailNode[e]))
            {
                //var newJoinUnitList = new List<MatchJoinUnit>()
                bool joint = false;
                var jointEdges = new List<MatchEdge>();
                var nodeEdgeDict = node.Neighbors.ToDictionary(e => e,
                    e => component.EdgeMaterilizedDict.ContainsKey(e));

                // Edge to component node
                foreach (var edge in node.Neighbors.Where(e => !nodeEdgeDict[e]))
                {
                    if (component.Nodes.Contains(edge.SinkNode))
                    {
                        joint = true;
                        nodeEdgeDict[edge] = true;
                        jointEdges.Add(edge);
                    }
                }


                // Component edge to node
                if (!joint && component.UnmaterializedNodeMapping.ContainsKey(node))
                {
                    joint = true;
                }


                // Add unpopulated edges
                var nodeUnpopulatedEdges = nodeEdgeDict.Where(e => !e.Value).Select(e => e.Key).ToList();

                if (joint)
                    yield return new Tuple<OneHeightTree, bool>(new OneHeightTree
                    {
                        TreeRoot = node,
                        MaterializedEdges = jointEdges,
                        UnmaterializedEdges = nodeUnpopulatedEdges,
                    }, false);

                // Single node edge
                else if (nodeUnpopulatedEdges.Count > 0 && component.MaterializedNodeSplitCount.Count > 1 && component.MaterializedNodeSplitCount.ContainsKey(node))
                {
                    yield return new Tuple<OneHeightTree, bool>(new OneHeightTree
                    {
                        TreeRoot = node,
                        MaterializedEdges = jointEdges,
                        UnmaterializedEdges = nodeUnpopulatedEdges,
                    }, true);
                }
            }
        }
        /// <summary>
        /// Constructs the graph pattern specified by the MATCH clause. 
        /// The graph pattern may consist of multiple fully-connected sub-graphs.
        /// </summary>
        /// <param name="query">The SELECT query block</param>
        /// <returns>A graph object contains all the connected componeents</returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            if (query == null || query.MatchClause == null)
                return null;

            var unionFind = new UnionFind();
            var edgeColumnToAliasesDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            var pathDictionary = new Dictionary<string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            unionFind.Parent = parent;

            // Constructs the graph pattern specified by the path expressions in the MATCH clause
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathEdgeList.Count; index < count; ++index)
                {
                    var currentNodeTableRef = path.PathEdgeList[index].Item1;
                    var currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                    var currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                    var nextNodeTableRef = index != count - 1
                        ? path.PathEdgeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNodeTableRef.BaseIdentifier.Value;
                    var patternNode = nodes.GetOrCreate(currentNodeExposedName);
                    if (patternNode.NodeAlias == null)
                    {
                        patternNode.NodeAlias = currentNodeExposedName;
                        patternNode.Neighbors = new List<MatchEdge>();
                        patternNode.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            patternNode.NodeTableObjectName = nodeTable.TableObjectName;
                            if (patternNode.NodeTableObjectName.SchemaIdentifier == null)
                                patternNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                        }
                    }

                    string edgeAlias = currentEdgeColumnRef.Alias;
                    if (edgeAlias == null)
                    {
                        var currentEdgeName = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value;
                        edgeAlias = string.Format("{0}_{1}_{2}", currentNodeExposedName, currentEdgeName,
                            nextNodeExposedName);
                        if (edgeColumnToAliasesDict.ContainsKey(currentEdgeName))
                        {
                            edgeColumnToAliasesDict[currentEdgeName].Add(edgeAlias);
                        }
                        else
                        {
                            edgeColumnToAliasesDict.Add(currentEdgeName, new List<string> { edgeAlias });
                        }
                    }

                    Identifier edgeIdentifier = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last();
                    string schema = patternNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                    string nodeTableName = patternNode.NodeTableObjectName.BaseIdentifier.Value;
                    string bindTableName =
                        _context.EdgeNodeBinding[
                            new Tuple<string, string>(nodeTableName.ToLower(), edgeIdentifier.Value.ToLower())].ToLower();
                    MatchEdge edge;
                    if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                    {
                        edge = new MatchEdge
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                        };
                        _context.AddEdgeReference(edge);
                    }
                    else
                    {
                        MatchPath matchPath = new MatchPath
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                            MinLength = currentEdgeColumnRef.MinLength,
                            MaxLength = currentEdgeColumnRef.MaxLength,
                            ReferencePathInfo = false,
                            AttributeValueDict = currentEdgeColumnRef.AttributeValueDict
                        };
                        _context.AddEdgeReference(matchPath);
                        pathDictionary[edgeAlias] = matchPath;
                        edge = matchPath;
                    }

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = patternNode;
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);


                    patternNode.Neighbors.Add(edge);


                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.NodeTableObjectName = nodeTable.TableObjectName;
                        if (tailNode.NodeTableObjectName.SchemaIdentifier == null)
                            tailNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                    }
                }
                if (preEdge != null)
                    preEdge.SinkNode = tailNode;
            }

            // Puts nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            var graph = new MatchGraph
            {
                ConnectedSubGraphs = connectedSubGraphs,
            };
            unionFind.Parent = null;

            // When an edge in the MATCH clause is not associated with an alias, 
            // assigns to it a default alias: sourceAlias_EdgeColumnName_sinkAlias. 
            // Also rewrites edge attributes anywhere in the query that can be bound to this default alias. 
            var replaceTableRefVisitor = new ReplaceEdgeReferenceVisitor();
            replaceTableRefVisitor.Invoke(query, edgeColumnToAliasesDict);

            // Rematerializes node tables in the MATCH clause which are defined in the upper-level context
            // and join them with the upper-level table references.
            RematerilizeExtrenalNodeTableReference(query, nodes);

            // Transforms the path reference in the SELECT elements into a 
            // scalar function to display path information.
            TransformPathInfoDisplaySelectElement(query, pathDictionary);

            
            return graph;
        }
Example #17
0
        public override List <Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> > > GetOptimizedTraversalOrder(ConnectedComponent subGraph)
        {
            if (subGraph.Nodes.Count == 1)
            {
                return
                    (this.GenerateTraversalOrderFromTraversalChain(
                         new List <Tuple <MatchNode, MatchEdge, MatchNode, List <MatchEdge>, List <MatchEdge> > >
                {
                    new Tuple <MatchNode, MatchEdge, MatchNode, List <MatchEdge>, List <MatchEdge> >(
                        subGraph.Nodes.First().Value, null, null, null, null)
                }));
            }

            // If it exists, pick a node without incoming edges as the start point
            List <MatchComponent> componentStates = subGraph.Nodes.Where(node => node.Value.ReverseNeighbors.Count == 0).
                                                    Select(node => new MatchComponent(node.Value)).Take(1).ToList();

            // Otherwise, pick a node randomly as the start point
            if (!componentStates.Any())
            {
                componentStates.Add(new MatchComponent(subGraph.Nodes.First().Value));
            }

            // DP
            while (componentStates.Any())
            {
                List <MatchComponent> nextCompnentStates = new List <MatchComponent>();

                // Iterate on current components
                foreach (MatchComponent curComponent in componentStates)
                {
                    OneHeightTree nodeUnits = this.GetNodeUnits(subGraph, curComponent);
                    if (nodeUnits == null &&
                        curComponent.ActiveNodeCount == subGraph.ActiveNodeCount &&
                        curComponent.EdgeMaterilizedDict.Count(e => e.Value == true) == subGraph.Edges.Count(e => e.Value.IsDanglingEdge == false))
                    {
                        return(this.GenerateTraversalOrderFromTraversalChain(curComponent.TraversalChain));
                    }

                    CandidateJoinUnit candidateUnit = this.GetCandidateUnits2(nodeUnits, curComponent);
                    // Add it to the current component to generate next states
                    MatchComponent newComponent = this.GetNextState(curComponent, candidateUnit);

                    if (nextCompnentStates.Count >= MaxStates)
                    {
                        throw new GraphViewException("This graph pattern is not supported yet.");
                    }

                    nextCompnentStates.Add(newComponent);
                }
                componentStates = nextCompnentStates;
            }

            return(null);
        }