Package com.espertech.esper.epl.join.plan

Source Code of com.espertech.esper.epl.join.plan.TwoStreamQueryPlanBuilder

/**************************************************************************************
* 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.collection.Pair;
import com.espertech.esper.epl.expression.ExprIdentNode;
import com.espertech.esper.epl.expression.ExprNode;
import com.espertech.esper.type.OuterJoinType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
* Builds a query plan for the simple 2-stream scenario.
*/
public class TwoStreamQueryPlanBuilder
{
    /**
     * Build query plan.
     * @param queryGraph - navigability info
     * @param optionalOuterJoinType - outer join type, null if not an outer join
     * @param typesPerStream - event types for each stream
     * @return query plan
     */
    public static QueryPlan build(EventType[] typesPerStream, QueryGraph queryGraph, OuterJoinType optionalOuterJoinType, String[][][] uniqueIndexProps)
    {
        QueryPlanIndex[] indexSpecs = new QueryPlanIndex[2];
        QueryPlanNode[] execNodeSpecs = new QueryPlanNode[2];

        TableLookupPlan lookupPlans[] = new TableLookupPlan[2];

        // plan lookup from 1 to zero
        Pair<QueryPlanIndex, TableLookupPlan> plan = planQuery(1, 0, typesPerStream, queryGraph, uniqueIndexProps[0]);
        indexSpecs[0] = plan.getFirst();
        lookupPlans[1] = plan.getSecond();

        // plan lookup from zero to 1
        plan = planQuery(0, 1, typesPerStream, queryGraph, uniqueIndexProps[1]);
        indexSpecs[1] = plan.getFirst();
        lookupPlans[0] = plan.getSecond();

        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);
    }

    private static Pair<QueryPlanIndex, TableLookupPlan> planQuery(int lookupStream, int indexedStream, EventType[] typesPerStream, QueryGraph queryGraph, String[][] indexStreamsUniqueProps) {

        // not navigable, full table scan
        if (!queryGraph.isNavigableAtAll(lookupStream, indexedStream)) {
            return getFullTableScan(lookupStream, indexedStream);
        }

        QueryGraphValue queryGraphValue = queryGraph.getGraphValue(lookupStream, indexedStream);

        // determine hash coercion types - these are the same regardless of direction
        QueryGraphValuePairHashKeyIndex hashKeyIndexPair = queryGraphValue.getHashKeyProps();
        List<QueryGraphValueEntryHashKeyed> hashKeyFunctions = hashKeyIndexPair.getKeys();
        String[] hashIndexProps = hashKeyIndexPair.getIndexed();
        CoercionDesc hashCoercionTypesDesc = CoercionUtil.getCoercionTypesHash(typesPerStream, lookupStream, indexedStream, hashKeyFunctions, hashIndexProps);
        Class[] hashCoercionTypes = hashCoercionTypesDesc.isCoerce() ? hashCoercionTypesDesc.getCoercionTypes() : null;

        // determine range coercion types, these may not be the same
        QueryGraphValuePairRangeIndex rangeKeyIndexPair = queryGraphValue.getRangeProps();
        String[] rangeIndexedProps = rangeKeyIndexPair.getIndexed();
        CoercionDesc rangeCoercionTypeDesc = CoercionUtil.getCoercionTypesRange(typesPerStream, indexedStream, rangeIndexedProps, rangeKeyIndexPair.getKeys());
        Class[] rangeCoercionType = rangeCoercionTypeDesc.isCoerce() ? rangeCoercionTypeDesc.getCoercionTypes() : null;

        // reduce to any unique index if applicable
        boolean unique = false;
        QueryPlanIndexUniqueHelper.ReducedHashKeys reduced = QueryPlanIndexUniqueHelper.reduceToUniqueIfPossible(hashIndexProps, hashCoercionTypes, hashKeyFunctions, indexStreamsUniqueProps);
        if (reduced != null) {
            hashIndexProps = reduced.getPropertyNames();
            hashCoercionTypes = reduced.getCoercionTypes();
            hashKeyFunctions = reduced.getHashKeyFunctions();
            unique = true;
            rangeIndexedProps = new String[0];
            rangeCoercionType = new Class[0];
            rangeKeyIndexPair = new QueryGraphValuePairRangeIndex(rangeIndexedProps, Collections.<QueryGraphValueEntryRange>emptyList());
        }

        if (hashIndexProps.length == 0 && rangeIndexedProps.length == 0) {
            QueryGraphValuePairInKWSingleIdx singles = queryGraphValue.getInKeywordSingles();
            if (!singles.getKey().isEmpty()) {
                String indexedProp = singles.getIndexed()[0];
                QueryGraphValueEntryInKeywordSingleIdx single = singles.getKey().get(0);
                QueryPlanIndexItem indexItem = new QueryPlanIndexItem(new String[] {indexedProp}, null, null, null, false);
                QueryPlanIndex queryPlanIndex = QueryPlanIndex.makeIndex(indexItem);
                String indexName = queryPlanIndex.getFirstIndexNum();
                TableLookupPlan plan = new InKeywordTableLookupPlanSingleIdx(lookupStream, indexedStream, indexName, single.getKeyExprs());
                return new Pair<QueryPlanIndex, TableLookupPlan>(queryPlanIndex, plan);
            }

            List<QueryGraphValuePairInKWMultiIdx> multis = queryGraphValue.getInKeywordMulti();
            if (!multis.isEmpty()) {
                QueryGraphValuePairInKWMultiIdx multi = multis.get(0);
                List<QueryPlanIndexItem> indexSet = new ArrayList<QueryPlanIndexItem>();
                for (ExprNode propIndexed : multi.getIndexed()) {
                    ExprIdentNode identNode = (ExprIdentNode) propIndexed;
                    QueryPlanIndexItem indexItem = new QueryPlanIndexItem(new String[] {identNode.getResolvedPropertyName()}, null, null, null, false);
                    indexSet.add(indexItem);
                }
                QueryPlanIndex queryPlanIndex = QueryPlanIndex.makeIndex(indexSet);
                Set<String> indexNames = queryPlanIndex.getItems().keySet();
                String[] indexNameArray = indexNames.toArray(new String[indexNames.size()]);
                TableLookupPlan plan = new InKeywordTableLookupPlanMultiIdx(lookupStream, indexedStream, indexNameArray, multi.getKey().getKeyExpr());
                return new Pair<QueryPlanIndex, TableLookupPlan>(queryPlanIndex, plan);
            }

            return getFullTableScan(lookupStream, indexedStream);
        }

        // build index description
        QueryPlanIndexItem indexItem = new QueryPlanIndexItem(hashIndexProps, hashCoercionTypes, rangeIndexedProps, rangeCoercionType, unique);
        QueryPlanIndex queryPlanIndex = QueryPlanIndex.makeIndex(indexItem);
        String indexName = queryPlanIndex.getFirstIndexNum();

        // straight no-range case means direct index lookup
        TableLookupPlan lookupPlan;
        if (rangeKeyIndexPair.getKeys().isEmpty()) {
            if (hashKeyFunctions.size() == 1) {
                QueryGraphValueEntryHashKeyed first = hashKeyFunctions.get(0);
                lookupPlan = new IndexedTableLookupPlanSingle(lookupStream, indexedStream, indexName, first);
            }
            else {
                lookupPlan = new IndexedTableLookupPlanMulti(lookupStream, indexedStream, indexName, hashKeyFunctions);
            }
        }
        // we have ranges
        else {
            // stream zero-to-one
            if (hashKeyFunctions.isEmpty() && rangeKeyIndexPair.getKeys().size() == 1) {
                lookupPlan = new SortedTableLookupPlan(lookupStream, indexedStream, indexName, rangeKeyIndexPair.getKeys().get(0));
            }
            else {
                lookupPlan = new CompositeTableLookupPlan(lookupStream, indexedStream, indexName, hashKeyFunctions, rangeKeyIndexPair.getKeys());
            }
        }
        return new Pair<QueryPlanIndex, TableLookupPlan>(queryPlanIndex, lookupPlan);
    }

    private static Pair<QueryPlanIndex, TableLookupPlan> getFullTableScan(int lookupStream, int indexedStream) {
        QueryPlanIndex index = QueryPlanIndex.makeIndex(new QueryPlanIndexItem(null, null, null, null, false));
        FullTableScanLookupPlan plan = new FullTableScanLookupPlan(lookupStream, indexedStream, index.getFirstIndexNum());
        return new Pair<QueryPlanIndex, TableLookupPlan>(index, plan);
    }
}
TOP

Related Classes of com.espertech.esper.epl.join.plan.TwoStreamQueryPlanBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.