private List <string> PopulateAdjacencyListProperties(MatchEdge edge) { if (edge.EdgeType == WEdgeType.BothEdge) { return new List <string> { GremlinKeyword.EdgeAdj, GremlinKeyword.ReverseEdgeAdj } } ; // // IsTraversalThroughPhysicalReverseEdge // if ((edge.EdgeType == WEdgeType.OutEdge && edge.IsReversed) || edge.EdgeType == WEdgeType.InEdge && !edge.IsReversed) { return new List <string> { GremlinKeyword.ReverseEdgeAdj } } ; else { return new List <string> { GremlinKeyword.EdgeAdj } }; }
private static WColumnReferenceExpression GetNodeColumnReferenceExprFromLink(CompileLink link) { if (link is MatchEdge) { MatchEdge edge = link as MatchEdge; if (edge.EdgeType == WEdgeType.OutEdge) { return(SqlUtil.GetColumnReferenceExpr(edge.LinkAlias, edge.IsReversed ? GremlinKeyword.EdgeSinkV : GremlinKeyword.EdgeSourceV)); } else if (edge.EdgeType == WEdgeType.InEdge) { return(SqlUtil.GetColumnReferenceExpr(edge.LinkAlias, edge.IsReversed ? GremlinKeyword.EdgeSourceV : GremlinKeyword.EdgeSinkV)); } else { return(SqlUtil.GetColumnReferenceExpr(edge.LinkAlias, GremlinKeyword.EdgeOtherV)); } } else if (link is PredicateLink) { PredicateLink predicateLink = link as PredicateLink; if (predicateLink.BooleanExpression is WEdgeVertexBridgeExpression) { return((predicateLink.BooleanExpression as WEdgeVertexBridgeExpression).FirstExpr as WColumnReferenceExpression); } } throw new QueryCompilationException("Cannot support " + link + " as a traversal link or an edge"); }
/// <summary> /// Generate the Table-Valued Function by the edge given the node alias /// </summary> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <returns></returns> private static WTableReference EdgeToTableReference(MatchEdge edge, string nodeAlias) { var edgeColumn = edge.EdgeColumn; var edgeIdentifiers = edge.EdgeColumn.MultiPartIdentifier.Identifiers; if (nodeAlias != edgeIdentifiers.First().Value) { var identifiers = new List <Identifier>(edgeIdentifiers); identifiers.RemoveAt(0); identifiers.Insert(0, new Identifier { Value = nodeAlias }); edgeColumn = new WColumnReferenceExpression { MultiPartIdentifier = new WMultiPartIdentifier { Identifiers = identifiers } }; } var columnName = edgeIdentifiers.Last().Value; var deColIdentifiers = new Identifier[] { edgeColumn.MultiPartIdentifier.Identifiers.First(), new Identifier { Value = columnName + "DeleteCol" } }; var decoderFunction = new Identifier { Value = edge.SourceNode.TableObjectName.SchemaIdentifier.Value + '_' + edge.SourceNode.TableObjectName.BaseIdentifier.Value + '_' + columnName + '_' + "Decoder", }; var tableRef = new WSchemaObjectFunctionTableReference { SchemaObject = new WSchemaObjectName( new Identifier { Value = "dbo" }, decoderFunction), Parameters = new List <WScalarExpression> { edgeColumn, new WColumnReferenceExpression { MultiPartIdentifier = new WMultiPartIdentifier(deColIdentifiers) } }, Alias = new Identifier { Value = edge.EdgeAlias, } }; return(tableRef); }
/// <summary> /// Span the table given the edge using cross apply /// </summary> /// <param name="tableRef"></param> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <returns></returns> public static WTableReference SpanTableRef(WTableReference tableRef, MatchEdge edge, string nodeAlias) { tableRef = new WUnqualifiedJoin { FirstTableRef = tableRef, SecondTableRef = EdgeToTableReference(edge, nodeAlias), UnqualifiedJoinType = UnqualifiedJoinType.CrossApply, }; return(tableRef); }
/// <summary> /// Span the table given the edge using cross apply /// </summary> /// <param name="tableRef"></param> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <returns></returns> public WTableReference SpanTableRef(WTableReference tableRef, MatchEdge edge, string nodeAlias, GraphMetaData metaData) { tableRef = new WUnqualifiedJoin { FirstTableRef = tableRef, SecondTableRef = edge.ToSchemaObjectFunction(nodeAlias, metaData), UnqualifiedJoinType = UnqualifiedJoinType.CrossApply, }; return(tableRef); }
public bool TryGetEdge(string key, out MatchEdge edge) { foreach (var subGraph in ConnectedSubGraphs) { if (subGraph.Edges.TryGetValue(key, out edge)) { return(true); } } edge = null; return(false); }
public void AddEdgeReference(MatchEdge edge) { var edgeAlias = edge.EdgeAlias; if (_nodeTableDictionary.ContainsKey(edgeAlias) || _edgeDictionary.ContainsKey(edgeAlias)) { throw new GraphViewException("Duplicate Alias"); } _edgeDictionary.Add(edgeAlias, new Tuple <WSchemaObjectName, WColumnReferenceExpression>(edge.SourceNode.NodeTableObjectName, edge.EdgeColumn)); }
public ColumnStatistics GetLeafToLeafStatistics(MatchEdge nodeEdge, MatchEdge componentEdge) { var edgeTuple = new Tuple <string, string>(nodeEdge.EdgeAlias, componentEdge.EdgeAlias); if (LeafToLeafSelectivity.ContainsKey(edgeTuple)) { return(LeafToLeafSelectivity[edgeTuple]); } var mergedStatistics = ColumnStatistics.UpdateHistogram(Context.GetEdgeStatistics(nodeEdge), Context.GetEdgeStatistics(componentEdge)); LeafToLeafSelectivity[edgeTuple] = mergedStatistics; return(mergedStatistics); }
public Statistics GetLeafToLeafStatistics(MatchEdge nodeEdge, MatchEdge componentEdge, out double selectivity) { var edgeTuple = new Tuple <string, string>(nodeEdge.EdgeAlias, componentEdge.EdgeAlias); Tuple <Statistics, double> edgeStatisticsTuple; if (_leafToLeafStatistics.TryGetValue(edgeTuple, out edgeStatisticsTuple)) { selectivity = edgeStatisticsTuple.Item2; return(edgeStatisticsTuple.Item1); } var mergedStatistics = Statistics.UpdateHistogram(nodeEdge.Statistics, componentEdge.Statistics, out selectivity); _leafToLeafStatistics[edgeTuple] = new Tuple <Statistics, double>(mergedStatistics, selectivity); return(mergedStatistics); }
/// <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; }
/// <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; }
/// <summary> /// Estimates the average degree of the edges and retrieve density value. /// Send sa query to retrieve the varbinary of the sink in the edge sampling table with edge predicates, /// then generates the statistics histogram for each edge /// </summary> private void RetrieveStatistics(MatchGraph graph) { if (graph == null) throw new ArgumentNullException("graph"); // Declare the parameters if any var declareParameter = ""; if (_variables != null) { declareParameter = _variables.Aggregate(declareParameter, (current, parameter) => current + ("DECLARE " + parameter.VariableName.Value + " " + TsqlFragmentToString.DataType(parameter.DataType) + "\r\n")); } // Calculates the average degree var sb = new StringBuilder(); bool first = true; sb.Append("SELECT [Edge].*, [EdgeDegrees].[SampleRowCount], [EdgeDegrees].[AverageDegree] FROM"); sb.Append("(\n"); foreach (var edge in graph.ConnectedSubGraphs.SelectMany(subGraph => subGraph.Edges.Values)) { if (!first) sb.Append("\nUNION ALL\n"); else { first = false; } var tableObjectName = edge.SourceNode.NodeTableObjectName; string schema = tableObjectName.SchemaIdentifier.Value.ToLower(); string tableName = tableObjectName.BaseIdentifier.Value.ToLower(); string edgeName = edge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value.ToLower(); string bindTableName = _context.EdgeNodeBinding[new Tuple<string, string>(tableName, edgeName)]; // Distinguished between path and edge //var sinkColumnName = edge.IsPath ? "COUNT(Sink)" : "[dbo].[GraphViewUDFGlobalNodeIdEncoder](Sink)"; sb.Append( string.Format(@" SELECT '{0}' as TableSchema, '{1}' as TableName, '{2}' as ColumnName, '{3}' as Alias, [dbo].[GraphViewUDFGlobalNodeIdEncoder](Src) as Src, [dbo].[GraphViewUDFGlobalNodeIdEncoder](Sink) as Sink, 0 as IsReversed, NULL as OriginalEdgeAlias FROM [{0}_{1}_{2}_Sampling] as [{3}]", schema, bindTableName, edgeName, edge.EdgeAlias)); var predicatesExpr = edge.RetrievePredicatesExpression(); if (predicatesExpr!=null) sb.AppendFormat("\n WHERE {0}", predicatesExpr); MatchEdge revEdge; if (graph.ReversedEdgeDict.TryGetValue(edge.EdgeAlias, out revEdge)) { sb.Append("\nUNION ALL\n"); var isEdgeView = revEdge.IsEdgeView; var revTableObjectName = revEdge.SourceNode.NodeTableObjectName; var revSchema = revTableObjectName.SchemaIdentifier.Value.ToLower(); var revEdgeName = revEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value.ToLower(); var revBindTableName = revEdge.BindNodeTableObjName.Identifiers.Last().Value.ToLower(); var revSamplingTableName = revSchema + "_" + revBindTableName + "_" + revEdgeName; var revSrcTuple = WNamedTableReference.SchemaNameToTuple(revEdge.BindNodeTableObjName); //var revSinkTuple = WNamedTableReference.SchemaNameToTuple(revEdge.SinkNode.NodeTableObjectName); var originalEdgeName = edge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value.ToLower(); // [node/nodeView]-[edgeView]->[node/nodeView] if (isEdgeView) { revEdgeName = revSrcTuple.Item2 + "_" + originalEdgeName + "Reversed"; revSamplingTableName = revSrcTuple.Item1 + "_" + revSrcTuple.Item2 + "_" + revEdgeName; } sb.Append( string.Format(@" SELECT '{0}' as TableSchema, '{1}' as TableName, '{2}' as ColumnName, '{3}' as Alias, [dbo].[GraphViewUDFGlobalNodeIdEncoder](Src) as Src, [dbo].[GraphViewUDFGlobalNodeIdEncoder](Sink) as Sink, 1 as IsReversed, '{4}' as OriginalEdgeAlias FROM [{5}_Sampling] as [{3}]", revSchema, revBindTableName, revEdgeName, revEdge.EdgeAlias, edge.EdgeAlias, revSamplingTableName)); var revPredicatesExpr = revEdge.RetrievePredicatesExpression(); if (revPredicatesExpr != null) sb.AppendFormat("\n WHERE {0}", revPredicatesExpr); } } sb.Append("\n) as Edge \n"); sb.Append(String.Format(@" INNER JOIN [{0}] as [EdgeDegrees] ON [EdgeDegrees].[TableSchema] = [Edge].[TableSchema] AND [EdgeDegrees].[TableName] = [Edge].[TableName] AND [EdgeDegrees].[ColumnName] = [Edge].[ColumnName]", GraphViewConnection.MetadataTables[3])); using (var command = Tx.Connection.CreateCommand()) { command.Transaction = Tx; command.CommandText = declareParameter + sb.ToString(); using (var reader = command.ExecuteReader()) { var srcNodeStatisticsDict = graph.SourceNodeStatisticsDict; while (reader.Read()) { MatchEdge edge = null; bool isReversed = reader["isReversed"].ToString().Equals("1"); if (!isReversed && !graph.TryGetEdge(reader["Alias"].ToString(), out edge)) throw new GraphViewException(string.Format("Edge {0} not exists", reader["Alias"].ToString())); if (isReversed && !graph.TryGetEdge(reader["OriginalEdgeAlias"].ToString(), out edge)) throw new GraphViewException(string.Format("Edge {0} not exists", reader["OriginalEdgeAlias"].ToString())); if (isReversed) edge = graph.ReversedEdgeDict[edge.EdgeAlias]; var srcBytes = reader["Src"] as byte[]; var cursor = 0; if (srcBytes != null) { var srcList = new List<long>(); while (cursor < srcBytes.Length) { var src = BitConverter.ToInt64(srcBytes, cursor); cursor += 8; srcList.Add(src); } var tmpEdge = new MatchEdge(); Statistics.UpdateEdgeHistogram(tmpEdge, srcList); srcNodeStatisticsDict[new Tuple<string, bool>(edge.EdgeAlias, isReversed)] = tmpEdge.Statistics; } else srcNodeStatisticsDict[new Tuple<string, bool>(edge.EdgeAlias, isReversed)] = null; var sinkBytes = reader["Sink"] as byte[]; if (sinkBytes == null) { edge.Statistics = new Statistics { Density = 0, Histogram = new Dictionary<long, Tuple<double, bool>>(), MaxValue = 0, RowCount = 0, //Selectivity = 1.0 }; continue; } List<long> sinkList = new List<long>(); cursor = 0; while (cursor < sinkBytes.Length) { var sink = BitConverter.ToInt64(sinkBytes, cursor); cursor += 8; sinkList.Add(sink); } Statistics.UpdateEdgeHistogram(edge, sinkList); edge.AverageDegree = Convert.ToDouble(reader["AverageDegree"])*sinkList.Count*1.0/ Convert.ToInt64(reader["SampleRowCount"]); var path = edge as MatchPath; if (path != null) { if (path.AverageDegree > 1) if (path.MaxLength != -1) { path.AverageDegree = Math.Pow(path.AverageDegree, path.MaxLength) - (path.MinLength > 0 ? Math.Pow(path.AverageDegree, path.MinLength - 1) : 0); } else path.AverageDegree = double.MaxValue; } } } // Retrieves density value for each node table string tempTableName = Path.GetRandomFileName().Replace(".", "").Substring(0, 8); var dbccDensityQuery = new StringBuilder(); dbccDensityQuery.Append(string.Format(@"CREATE TABLE #{0} (Density float, Len int, Col sql_variant); INSERT INTO #{0} EXEC('", tempTableName)); Dictionary<Tuple<string, string>, List<MatchNode>> schemaTableToNodeListMapping = new Dictionary<Tuple<string, string>, List<MatchNode>>(); foreach (var subGraph in graph.ConnectedSubGraphs) { foreach (var node in subGraph.Nodes.Values) { var tableTuple = WNamedTableReference.SchemaNameToTuple(node.NodeTableObjectName); if (_graphMetaData.NodeViewMapping.ContainsKey(tableTuple)) { node.GlobalNodeIdDensity = Statistics.DefaultDensity; } else { var nodeList = schemaTableToNodeListMapping.GetOrCreate(tableTuple); nodeList.Add(node); } } } foreach (var tableTuple in schemaTableToNodeListMapping.Keys) { dbccDensityQuery.Append(string.Format( "DBCC SHOW_STATISTICS (\"{0}.{1}\", [{0}{1}_PK_GlobalNodeId]) with DENSITY_VECTOR;\n", tableTuple.Item1, tableTuple.Item2)); } dbccDensityQuery.Append("');\n"); dbccDensityQuery.Append(string.Format("SELECT Density FROM #{0} WHERE Col = 'GlobalNodeId'", tempTableName)); command.CommandText = dbccDensityQuery.ToString(); using (var reader = command.ExecuteReader()) { foreach (var item in schemaTableToNodeListMapping) { double density; if (!reader.Read()) density = Statistics.DefaultDensity; else { density = Convert.ToDouble(reader["Density"]); if (Math.Abs(density - 1.0) < 0.0001) density = Statistics.DefaultDensity; } foreach (var node in item.Value) { node.GlobalNodeIdDensity = density; } } } } }
/// <summary> /// Item1: current node. A query will be sent to the server to fetch this node if this is the first time it appears in the whole list. /// Item2: the traversalEdge whose sink is current node. /// Item3: traversalEdges whose source is currentNode. /// This list will either contain 0 or 1 traversal edge in the current version, and it will be pushed to server if possible. /// Item4: backwardMatchingEdges. /// Item5: forwardMatchingEdges. /// </summary> /// <param name="traversalChain"></param> /// <returns></returns> protected List <Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> > > GenerateTraversalOrderFromTraversalChain (List <Tuple <MatchNode, MatchEdge, MatchNode, List <MatchEdge>, List <MatchEdge> > > traversalChain) { Dictionary <string, int> nodeFetchingOrderDict = new Dictionary <string, int>(); List <Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> > > optimizedTraversalOrder = new List <Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> > >(); foreach (Tuple <MatchNode, MatchEdge, MatchNode, List <MatchEdge>, List <MatchEdge> > tuple in traversalChain) { MatchNode srcNode = tuple.Item1; MatchEdge traversalEdge = tuple.Item2; int nodeFetchingOrder; if (nodeFetchingOrderDict.TryGetValue(srcNode.NodeAlias, out nodeFetchingOrder)) { List <MatchEdge> traversalEdges = optimizedTraversalOrder[nodeFetchingOrder].Item3; if (traversalEdges.Count == 0) { traversalEdges.Add(traversalEdge); } else { optimizedTraversalOrder.Add( new Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> >( srcNode, null, new List <MatchEdge> { traversalEdge }, new List <MatchEdge>(), new List <MatchEdge>())); } } else { nodeFetchingOrderDict.Add(srcNode.NodeAlias, optimizedTraversalOrder.Count); optimizedTraversalOrder.Add( new Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> >( srcNode, null, traversalEdge != null ? new List <MatchEdge> { traversalEdge } : new List <MatchEdge>(), new List <MatchEdge>(), new List <MatchEdge>())); } if (traversalEdge != null) { MatchNode sinkNode = tuple.Item3; List <MatchEdge> backwardEdges = tuple.Item4; List <MatchEdge> forwardEdges = tuple.Item5; nodeFetchingOrderDict.Add(sinkNode.NodeAlias, optimizedTraversalOrder.Count); optimizedTraversalOrder.Add( new Tuple <MatchNode, MatchEdge, List <MatchEdge>, List <MatchEdge>, List <MatchEdge> >( sinkNode, traversalEdge, new List <MatchEdge>(), backwardEdges, forwardEdges)); } } return(optimizedTraversalOrder); }
/// <summary> /// Span the table given the edge using cross apply /// </summary> /// <param name="tableRef"></param> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <param name="dumbNode"></param> /// <returns></returns> public WTableReference SpanTableRef(WTableReference tableRef, MatchEdge edge, string nodeAlias, string dumbNode, GraphMetaData metaData) { tableRef = new WUnqualifiedJoin { FirstTableRef = tableRef, SecondTableRef = edge.ToSchemaObjectFunction(nodeAlias, dumbNode, metaData), UnqualifiedJoinType = UnqualifiedJoinType.CrossApply, }; return tableRef; }
public ColumnStatistics GetEdgeStatistics(MatchEdge edge) { return(_edgeStatisticses[edge]); }
public ColumnStatistics GetEdgeStatistics(MatchEdge edge) { return _edgeStatisticses[edge]; }
internal bool TryGetEdge(string alias, out MatchEdge edge) { return(this.GraphPattern.TryGetEdge(alias, out edge)); }
public void AddEdgeReference(MatchEdge edge) { var edgeAlias = edge.EdgeAlias; if (_nodeTableDictionary.ContainsKey(edgeAlias) || _edgeDictionary.ContainsKey(edgeAlias)) throw new GraphViewException("Duplicate Alias"); _edgeDictionary.Add(edgeAlias, new Tuple<WSchemaObjectName, WColumnReferenceExpression>(edge.SourceNode.NodeTableObjectName, edge.EdgeColumn)); }
/// <summary> /// Update the statistics histogram for the edge given the sink id list. /// Bucket size is pre-defined /// </summary> /// <param name="edge"></param> /// <param name="sinkList"></param> private void UpdateEdgeHistogram(MatchEdge edge, List<long> sinkList) { sinkList.Sort(); var rowCount = sinkList.Count; var statistics = new ColumnStatistics { RowCount = rowCount }; var height = (int)(rowCount / BucketNum); var popBucketCount = 0; var popValueCount = 0; var bucketCount = 0; // If number in each bucket is very small, then generate a Frequency Histogram if (height < 2) { bucketCount = rowCount; long preValue = sinkList[0]; int count = 1; int distCount = 1; for (int i = 1; i < rowCount; i++) { var curValue = sinkList[i]; if (curValue == preValue) { count++; } else { if (count > 1) { popBucketCount += count; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple<double, bool>(count, count > 1)); count = 1; preValue = curValue; distCount++; } } if (count > 1) { popBucketCount += count; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple<double, bool>(count, count > 1)); statistics.MaxValue = preValue; // Simple Denstity //statistics.Density = 1.0 / distCount; // Advanced Density statistics.Density = bucketCount == popBucketCount ? 0 : 1.0 * (bucketCount - popBucketCount) / bucketCount / (distCount - popValueCount); } // Generate a Height-balanced Histogram else { long preValue = sinkList[0]; int count = 0; int distCount = 1; for (int i = 1; i < rowCount; i++) { if (i % height == height - 1) { bucketCount++; var curValue = sinkList[i]; if (curValue == preValue) count += height; else { distCount++; if (count > height) { popBucketCount += count / height; popValueCount++; } //count = count == 0 ? height : count; statistics.Histogram.Add(preValue, new Tuple<double, bool>(count, count > height)); preValue = curValue; count = height; } } } if (count > height) { popBucketCount += count / height; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple<double, bool>(count, count > height)); statistics.MaxValue = preValue; // Simple Density //statistics.Density = 1.0 / distCount; // Advanced Density statistics.Density = bucketCount == popBucketCount ? 0 : 1.0 * (bucketCount - popBucketCount) / bucketCount / (distCount - popValueCount); } _context.AddEdgeStatistics(edge, statistics); }
/// <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; }
private void UpdateComponent(MatchComponent curComponent, CandidateJoinUnit candidateTree) { Dictionary <string, MatchNode> nodes = curComponent.Nodes; Dictionary <MatchEdge, bool> edgeMaterializedDict = curComponent.EdgeMaterilizedDict; Dictionary <MatchNode, List <MatchEdge> > unmaterializedNodeMapping = curComponent.UnmaterializedNodeMapping; MatchNode root = candidateTree.TreeRoot; if (!nodes.ContainsKey(root.NodeAlias)) { nodes.Add(root.NodeAlias, new MatchNode(root)); } curComponent.MaterializedNodeSplitCount[root] = 0; List <Tuple <MaterializedOrder, MatchEdge> > inEdges = candidateTree.PreMatIncomingEdges.Select( e => new Tuple <MaterializedOrder, MatchEdge>(MaterializedOrder.Pre, e)) .Union( candidateTree.PostMatIncomingEdges.Select( e => new Tuple <MaterializedOrder, MatchEdge>(MaterializedOrder.Post, e))) .ToList(); List <Tuple <MaterializedOrder, MatchEdge> > outEdges = candidateTree.PreMatOutgoingEdges.Select( e => new Tuple <MaterializedOrder, MatchEdge>(MaterializedOrder.Pre, e)) .Union( candidateTree.PostMatOutgoingEdges.Select( e => new Tuple <MaterializedOrder, MatchEdge>(MaterializedOrder.Post, e))) .ToList(); if (inEdges.Any()) { unmaterializedNodeMapping.Remove(root); foreach (Tuple <MaterializedOrder, MatchEdge> t in inEdges) { MaterializedOrder order = t.Item1; MatchEdge edge = t.Item2; edgeMaterializedDict[edge] = true; List <string> adjListProperties = this.PopulateAdjacencyListProperties(edge); MatchNode node = curComponent.Nodes[edge.SourceNode.NodeAlias]; foreach (string adjListProperty in adjListProperties) { node.Properties.Add(adjListProperty); } } } if (outEdges.Any()) { foreach (Tuple <MaterializedOrder, MatchEdge> t in outEdges) { MaterializedOrder order = t.Item1; MatchEdge edge = t.Item2; edgeMaterializedDict[edge] = true; List <string> adjListProperties = this.PopulateAdjacencyListProperties(edge); MatchNode node = curComponent.Nodes[edge.SourceNode.NodeAlias]; foreach (string adjListProperty in adjListProperties) { node.Properties.Add(adjListProperty); } } } List <MatchEdge> unmatEdges = candidateTree.UnmaterializedEdges; foreach (MatchEdge unmatEdge in unmatEdges) { edgeMaterializedDict[unmatEdge] = false;; List <MatchEdge> unmatNodeInEdges = unmaterializedNodeMapping.GetOrCreate(unmatEdge.SinkNode); unmatNodeInEdges.Add(unmatEdge); } }
/// <summary> /// Updates the statistics histogram for the edge given the sink id list. /// Bucket size is pre-defined /// </summary> /// <param name="edge"></param> /// <param name="sinkList">sink id of the edge sampling</param> internal static void UpdateEdgeHistogram(MatchEdge edge, List <long> sinkList) { sinkList.Sort(); var rowCount = sinkList.Count; var statistics = new Statistics { RowCount = rowCount, }; var height = (int)(rowCount / BucketNum); var popBucketCount = 0; var popValueCount = 0; var bucketCount = 0; // If number in each bucket is very small, then generate a Frequency Histogram if (height < 2) { bucketCount = rowCount; long preValue = sinkList[0]; int count = 1; int distCount = 1; for (int i = 1; i < rowCount; i++) { var curValue = sinkList[i]; if (curValue == preValue) { count++; } else { if (count > 1) { popBucketCount += count; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple <double, bool>(count, count > 1)); count = 1; preValue = curValue; distCount++; } } if (count > 1) { popBucketCount += count; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple <double, bool>(count, count > 1)); statistics.MaxValue = preValue; // Simple Denstity //statistics.Density = 1.0 / distCount; // Advanced Density statistics.Density = bucketCount == popBucketCount ? 0 : 1.0 * (bucketCount - popBucketCount) / bucketCount / (distCount - popValueCount); } // Generates a Height-balanced Histogram else { long preValue = sinkList[0]; int count = 0; int distCount = 1; for (int i = 1; i < rowCount; i++) { if (i % height == height - 1) { bucketCount++; var curValue = sinkList[i]; if (curValue == preValue) { count += height; } else { distCount++; if (count > height) { popBucketCount += count / height; popValueCount++; } //count = count == 0 ? height : count; statistics.Histogram.Add(preValue, new Tuple <double, bool>(count, count > height)); preValue = curValue; count = height; } } } if (count > height) { popBucketCount += count / height; popValueCount++; } statistics.Histogram.Add(preValue, new Tuple <double, bool>(count, count > height)); statistics.MaxValue = preValue; // Simple Density //statistics.Density = 1.0 / distCount; // Advanced Density statistics.Density = bucketCount == popBucketCount ? 0 : 1.0 * (bucketCount - popBucketCount) / bucketCount / (distCount - popValueCount); } edge.Statistics = statistics; }
/// <summary> /// Generate the Table-Valued Function by the edge given the node alias /// </summary> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <returns></returns> private static WTableReference EdgeToTableReference(MatchEdge edge, string nodeAlias) { var edgeColumn = edge.EdgeColumn; var edgeIdentifiers = edge.EdgeColumn.MultiPartIdentifier.Identifiers; if (nodeAlias != edgeIdentifiers.First().Value) { var identifiers = new List<Identifier>(edgeIdentifiers); identifiers.RemoveAt(0); identifiers.Insert(0, new Identifier { Value = nodeAlias }); edgeColumn = new WColumnReferenceExpression { MultiPartIdentifier = new WMultiPartIdentifier { Identifiers = identifiers } }; } var columnName = edgeIdentifiers.Last().Value; var deColIdentifiers = new Identifier[] { edgeColumn.MultiPartIdentifier.Identifiers.First(), new Identifier {Value = columnName + "DeleteCol"} }; var decoderFunction = new Identifier { Value = edge.SourceNode.TableObjectName.SchemaIdentifier.Value + '_' + edge.SourceNode.TableObjectName.BaseIdentifier.Value + '_' + columnName + '_' + "Decoder", }; var tableRef = new WSchemaObjectFunctionTableReference { SchemaObject = new WSchemaObjectName( new Identifier {Value = "dbo"}, decoderFunction), Parameters = new List<WScalarExpression> { edgeColumn, new WColumnReferenceExpression { MultiPartIdentifier = new WMultiPartIdentifier(deColIdentifiers) } }, Alias = new Identifier { Value = edge.EdgeAlias, } }; return tableRef; }
public void AddEdgeStatistics(MatchEdge edge, ColumnStatistics statistics) { _edgeStatisticses.Add(edge, statistics); }
/// <summary> /// Span the table given the edge using cross apply /// </summary> /// <param name="tableRef"></param> /// <param name="edge"></param> /// <param name="nodeAlias"></param> /// <returns></returns> public static WTableReference SpanTableRef(WTableReference tableRef, MatchEdge edge, string nodeAlias) { tableRef = new WUnqualifiedJoin { FirstTableRef = tableRef, SecondTableRef = EdgeToTableReference(edge, nodeAlias), UnqualifiedJoinType = UnqualifiedJoinType.CrossApply, }; return tableRef; }
public bool TryGetEdge(string key, out MatchEdge edge) { foreach (var subGraph in ConnectedSubGraphs) { if (subGraph.Edges.TryGetValue(key, out edge)) { return true; } } edge = null; return false; }
// 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); }