/************************************************************************************** * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package com.espertech.esper.epl.join.plan; import com.espertech.esper.client.EventType; import com.espertech.esper.client.annotation.HintEnum; import com.espertech.esper.core.service.StreamJoinAnalysisResult; import com.espertech.esper.epl.expression.ExprEvaluatorContext; import com.espertech.esper.epl.expression.ExprValidationException; import com.espertech.esper.epl.join.base.HistoricalViewableDesc; import com.espertech.esper.epl.join.table.HistoricalStreamIndexList; import com.espertech.esper.epl.spec.OuterJoinDesc; import com.espertech.esper.type.OuterJoinType; import com.espertech.esper.util.AuditPath; import com.espertech.esper.util.DependencyGraph; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.lang.annotation.Annotation; import java.util.List; /** * Build a query plan based on filtering information. */ public class QueryPlanBuilder { private static final Log queryPlanLog = LogFactory.getLog(AuditPath.QUERYPLAN_LOG); /** * Build query plan using the filter. * @param typesPerStream - event types for each stream * @param outerJoinDescList - list of outer join criteria, or null if there are no outer joins * @param queryGraph - relationships between streams based on filter expressions and outer-join on-criteria * @param streamNames - names of streams * @param dependencyGraph - dependencies between historical streams * @param historicalStreamIndexLists - index management, populated for the query plan * @param streamJoinAnalysisResult * @return query plan * @throws ExprValidationException if the query plan fails */ public static QueryPlan getPlan(EventType[] typesPerStream, List<OuterJoinDesc> outerJoinDescList, QueryGraph queryGraph, String[] streamNames, HistoricalViewableDesc historicalViewableDesc, DependencyGraph dependencyGraph, HistoricalStreamIndexList[] historicalStreamIndexLists, StreamJoinAnalysisResult streamJoinAnalysisResult, boolean isQueryPlanLogging, Annotation[] annotations, ExprEvaluatorContext exprEvaluatorContext) throws ExprValidationException { String methodName = ".getPlan "; int numStreams = typesPerStream.length; if (numStreams < 2) { throw new IllegalArgumentException("Number of join stream types is less then 2"); } if (outerJoinDescList.size() >= numStreams) { throw new IllegalArgumentException("Too many outer join descriptors found"); } if (numStreams == 2) { OuterJoinType outerJoinType = null; if (!outerJoinDescList.isEmpty()) { outerJoinType = outerJoinDescList.get(0).getOuterJoinType(); } QueryPlan queryPlan = TwoStreamQueryPlanBuilder.build(typesPerStream, queryGraph, outerJoinType, streamJoinAnalysisResult.getUniqueKeys()); removeUnidirectional(queryPlan, streamJoinAnalysisResult); if (log.isDebugEnabled()) { log.debug(methodName + "2-Stream queryPlan=" + queryPlan); } return queryPlan; } boolean hasPreferMergeJoin = HintEnum.PREFER_MERGE_JOIN.getHint(annotations) != null; boolean hasForceNestedIter = HintEnum.FORCE_NESTED_ITER.getHint(annotations) != null; boolean isAllInnerJoins = outerJoinDescList.isEmpty() || OuterJoinDesc.consistsOfAllInnerJoins(outerJoinDescList); if (isAllInnerJoins && !hasPreferMergeJoin) { QueryPlan queryPlan = NStreamQueryPlanBuilder.build(queryGraph, typesPerStream, historicalViewableDesc, dependencyGraph, historicalStreamIndexLists, hasForceNestedIter, streamJoinAnalysisResult.getUniqueKeys()); if (queryPlan != null) { removeUnidirectional(queryPlan, streamJoinAnalysisResult); if (log.isDebugEnabled()) { log.debug(methodName + "N-Stream inner-join queryPlan=" + queryPlan); } return queryPlan; } if (isQueryPlanLogging && queryPlanLog.isInfoEnabled()) { log.info("Switching to Outer-NStream algorithm for query plan"); } } QueryPlan queryPlan = NStreamOuterQueryPlanBuilder.build(queryGraph, outerJoinDescList, streamNames, typesPerStream, historicalViewableDesc, dependencyGraph, historicalStreamIndexLists, exprEvaluatorContext, streamJoinAnalysisResult.getUniqueKeys()); removeUnidirectional(queryPlan, streamJoinAnalysisResult); return queryPlan; } // Remove plans for non-unidirectional streams private static void removeUnidirectional(QueryPlan queryPlan, StreamJoinAnalysisResult streamJoinAnalysisResult) { for (int streamNum = 0; streamNum < queryPlan.getExecNodeSpecs().length; streamNum++) { if (streamJoinAnalysisResult.isUnidirectional() && !streamJoinAnalysisResult.getUnidirectionalInd()[streamNum]) { queryPlan.getExecNodeSpecs()[streamNum] = new QueryPlanNodeNoOp(); } } } private static final Log log = LogFactory.getLog(QueryPlanBuilder.class); }