public void TestCreateStreamPlan() { QueryPlanIndex[] indexes = QueryPlanIndexBuilder.BuildIndexSpec(_queryGraph, _typesPerStream, new string[_queryGraph.NumStreams][][]); for (int i = 0; i < indexes.Length; i++) { Log.Debug(".testCreateStreamPlan index " + i + " = " + indexes[i]); } QueryPlanNode plan = NStreamQueryPlanBuilder.CreateStreamPlan( 0, new int[] { 2, 4, 3, 1 }, _queryGraph, indexes, _typesPerStream, new bool[5], null, new TableMetadata[_queryGraph.NumStreams]); Log.Debug(".testCreateStreamPlan plan=" + plan); Assert.IsTrue(plan is NestedIterationNode); var nested = (NestedIterationNode)plan; var tableLookupSpec = (TableLookupNode)nested.ChildNodes[0]; // Check lookup strategy for first lookup var lookupStrategySpec = (IndexedTableLookupPlanSingle)tableLookupSpec.LookupStrategySpec; Assert.AreEqual("P01", ((QueryGraphValueEntryHashKeyedProp)lookupStrategySpec.HashKey).KeyProperty); Assert.AreEqual(0, lookupStrategySpec.LookupStream); Assert.AreEqual(2, lookupStrategySpec.IndexedStream); Assert.NotNull(lookupStrategySpec.IndexNum); // Check lookup strategy for last lookup tableLookupSpec = (TableLookupNode)nested.ChildNodes[3]; var unkeyedSpecScan = (FullTableScanLookupPlan)tableLookupSpec.LookupStrategySpec; Assert.AreEqual(1, unkeyedSpecScan.IndexedStream); Assert.NotNull(unkeyedSpecScan.IndexNum); }
/// <summary> /// Build query plan. /// </summary> /// <param name="typesPerStream">event types for each stream</param> /// <param name="queryGraph">navigability info</param> /// <param name="optionalOuterJoinType">outer join type, null if not an outer join</param> /// <param name="uniqueIndexProps">The unique index props.</param> /// <param name="tablesPerStream">The tables per stream.</param> /// <returns> /// query plan /// </returns> public static QueryPlan Build(EventType[] typesPerStream, QueryGraph queryGraph, OuterJoinType?optionalOuterJoinType, string[][][] uniqueIndexProps, TableMetadata[] tablesPerStream) { var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec(queryGraph, typesPerStream, uniqueIndexProps); var execNodeSpecs = new QueryPlanNode[2]; var lookupPlans = new TableLookupPlan[2]; // plan lookup from 1 to zero lookupPlans[1] = NStreamQueryPlanBuilder.CreateLookupPlan(queryGraph, 1, 0, indexSpecs[0], typesPerStream, tablesPerStream[0]); // plan lookup from zero to 1 lookupPlans[0] = NStreamQueryPlanBuilder.CreateLookupPlan(queryGraph, 0, 1, indexSpecs[1], typesPerStream, tablesPerStream[1]); execNodeSpecs[0] = new TableLookupNode(lookupPlans[0]); execNodeSpecs[1] = new TableLookupNode(lookupPlans[1]); if (optionalOuterJoinType != null) { if ((optionalOuterJoinType.Equals(OuterJoinType.LEFT)) || (optionalOuterJoinType.Equals(OuterJoinType.FULL))) { execNodeSpecs[0] = new TableOuterLookupNode(lookupPlans[0]); } if ((optionalOuterJoinType.Equals(OuterJoinType.RIGHT)) || (optionalOuterJoinType.Equals(OuterJoinType.FULL))) { execNodeSpecs[1] = new TableOuterLookupNode(lookupPlans[1]); } } return(new QueryPlan(indexSpecs, execNodeSpecs)); }
public void TestIndexAlreadyExists() { _queryGraph = new QueryGraph(5, null, false); _queryGraph.AddStrictEquals(0, "p00", Make(0, "p00"), 1, "p10", Make(1, "p10")); _queryGraph.AddStrictEquals(0, "p00", Make(0, "p00"), 2, "p20", Make(2, "p20")); QueryPlanIndex[] indexes = QueryPlanIndexBuilder.BuildIndexSpec(_queryGraph, _types, new String[_queryGraph.NumStreams][][]); String[][] expected = new String[][] { new [] { "p00" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[0].IndexProps, expected); }
public void TestBuildIndexSpec() { QueryPlanIndex[] indexes = QueryPlanIndexBuilder.BuildIndexSpec(_queryGraph, _types, new String[_queryGraph.NumStreams][][]); String[][] expected = new String[][] { new [] { "p00" }, new [] { "p01" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[0].IndexProps, expected); expected = new String[][] { new [] { "p10" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[1].IndexProps, expected); expected = new String[][] { new [] { "p20" }, new [] { "p21" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[2].IndexProps, expected); expected = new String[][] { new [] { "p30", "p31" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[3].IndexProps, expected); expected = new String[][] { new [] { "p42" }, new [] { "p40", "p41" } }; EPAssertionUtil.AssertEqualsExactOrder(indexes[4].IndexProps, expected); // Test no index, should have a single entry with a zero-length property name array _queryGraph = new QueryGraph(3, null, false); indexes = QueryPlanIndexBuilder.BuildIndexSpec(_queryGraph, _types, new String[_queryGraph.NumStreams][][]); Assert.AreEqual(1, indexes[1].IndexProps.Length); }
/// <summary> /// Build a query plan based on the stream property relationships indicated in queryGraph. /// </summary> /// <param name="queryGraph">navigation info between streams</param> /// <param name="typesPerStream">event types for each stream</param> /// <param name="historicalViewableDesc">The historical viewable desc.</param> /// <param name="dependencyGraph">dependencies between historical streams</param> /// <param name="historicalStreamIndexLists">index management, populated for the query plan</param> /// <param name="hasForceNestedIter">if set to <c>true</c> [has force nested iter].</param> /// <param name="indexedStreamsUniqueProps">The indexed streams unique props.</param> /// <param name="tablesPerStream">The tables per stream.</param> /// <returns> /// query plan /// </returns> internal static QueryPlan Build( QueryGraph queryGraph, EventType[] typesPerStream, HistoricalViewableDesc historicalViewableDesc, DependencyGraph dependencyGraph, HistoricalStreamIndexList[] historicalStreamIndexLists, bool hasForceNestedIter, string[][][] indexedStreamsUniqueProps, TableMetadata[] tablesPerStream) { if (Log.IsDebugEnabled) { Log.Debug(".build queryGraph=" + queryGraph); } var numStreams = queryGraph.NumStreams; var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec(queryGraph, typesPerStream, indexedStreamsUniqueProps); if (Log.IsDebugEnabled) { Log.Debug(".build Index build completed, indexes=" + QueryPlanIndex.Print(indexSpecs)); } // any historical streams don't get indexes, the lookup strategy accounts for cached indexes if (historicalViewableDesc.HasHistorical) { for (var i = 0; i < historicalViewableDesc.Historical.Length; i++) { if (historicalViewableDesc.Historical[i]) { indexSpecs[i] = null; } } } var planNodeSpecs = new QueryPlanNode[numStreams]; int worstDepth = int.MaxValue; for (var streamNo = 0; streamNo < numStreams; streamNo++) { // no plan for historical streams that are dependent upon other streams if ((historicalViewableDesc.Historical[streamNo]) && (dependencyGraph.HasDependency(streamNo))) { planNodeSpecs[streamNo] = new QueryPlanNodeNoOp(); continue; } var bestChainResult = ComputeBestPath(streamNo, queryGraph, dependencyGraph); var bestChain = bestChainResult.Chain; if (Log.IsDebugEnabled) { Log.Debug(".build For stream " + streamNo + " bestChain=" + bestChain.Render()); } if (bestChainResult.Depth < worstDepth) { worstDepth = bestChainResult.Depth; } planNodeSpecs[streamNo] = CreateStreamPlan(streamNo, bestChain, queryGraph, indexSpecs, typesPerStream, historicalViewableDesc.Historical, historicalStreamIndexLists, tablesPerStream); if (Log.IsDebugEnabled) { Log.Debug(".build spec=" + planNodeSpecs[streamNo]); } } // We use the merge/nested (outer) join algorithm instead. if ((worstDepth < numStreams - 1) && (!hasForceNestedIter)) { return(null); } return(new QueryPlan(indexSpecs, planNodeSpecs)); }
/// <summary> /// Build a query plan based on the stream property relationships indicated in queryGraph. /// </summary> /// <param name="queryGraph">navigation info between streams</param> /// <param name="outerJoinDescList">descriptors for all outer joins</param> /// <param name="streamNames">stream names</param> /// <param name="typesPerStream">event types for each stream</param> /// <param name="historicalViewableDesc">The historical viewable desc.</param> /// <param name="dependencyGraph">dependencies between historical streams</param> /// <param name="historicalStreamIndexLists">index management, populated for the query plan</param> /// <param name="exprEvaluatorContext">context for expression evalauation</param> /// <param name="indexedStreamsUniqueProps">The indexed streams unique props.</param> /// <param name="tablesPerStream">The tables per stream.</param> /// <returns> /// query plan /// </returns> /// <throws>ExprValidationException if the query planning failed</throws> internal static QueryPlan Build( QueryGraph queryGraph, OuterJoinDesc[] outerJoinDescList, string[] streamNames, EventType[] typesPerStream, HistoricalViewableDesc historicalViewableDesc, DependencyGraph dependencyGraph, HistoricalStreamIndexList[] historicalStreamIndexLists, ExprEvaluatorContext exprEvaluatorContext, string[][][] indexedStreamsUniqueProps, TableMetadata[] tablesPerStream) { if (Log.IsDebugEnabled) { Log.Debug(".build queryGraph=" + queryGraph); } var numStreams = queryGraph.NumStreams; var planNodeSpecs = new QueryPlanNode[numStreams]; // Build index specifications var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec(queryGraph, typesPerStream, indexedStreamsUniqueProps); if (Log.IsDebugEnabled) { Log.Debug(".build Index build completed, indexes=" + QueryPlanIndex.Print(indexSpecs)); } // any historical streams don't get indexes, the lookup strategy accounts for cached indexes if (historicalViewableDesc.HasHistorical) { for (var i = 0; i < historicalViewableDesc.Historical.Length; i++) { if (historicalViewableDesc.Historical[i]) { indexSpecs[i] = null; } } } // Build graph of the outer join to inner table relationships. // Build a map of inner joins. OuterInnerDirectionalGraph outerInnerGraph; InnerJoinGraph innerJoinGraph; if (outerJoinDescList.Length > 0) { outerInnerGraph = GraphOuterJoins(numStreams, outerJoinDescList); innerJoinGraph = InnerJoinGraph.GraphInnerJoins(numStreams, outerJoinDescList); } else { // all inner joins - thereby no (or empty) directional graph outerInnerGraph = new OuterInnerDirectionalGraph(numStreams); innerJoinGraph = new InnerJoinGraph(numStreams, true); } if (Log.IsDebugEnabled) { Log.Debug(".build directional graph=" + outerInnerGraph.Print()); } // For each stream determine the query plan for (var streamNo = 0; streamNo < numStreams; streamNo++) { // no plan for historical streams that are dependent upon other streams if ((historicalViewableDesc.Historical[streamNo]) && (dependencyGraph.HasDependency(streamNo))) { planNodeSpecs[streamNo] = new QueryPlanNodeNoOp(); continue; } var queryPlanNode = BuildPlanNode(numStreams, streamNo, streamNames, queryGraph, outerInnerGraph, outerJoinDescList, innerJoinGraph, indexSpecs, typesPerStream, historicalViewableDesc.Historical, dependencyGraph, historicalStreamIndexLists, exprEvaluatorContext, tablesPerStream); if (Log.IsDebugEnabled) { Log.Debug(".build spec for stream '" + streamNames[streamNo] + "' number " + streamNo + " is " + queryPlanNode); } planNodeSpecs[streamNo] = queryPlanNode; } var queryPlan = new QueryPlan(indexSpecs, planNodeSpecs); if (Log.IsDebugEnabled) { Log.Debug(".build query plan=" + queryPlan); } return(queryPlan); }