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

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

/**************************************************************************************
* 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.epl.expression.ExprIdentNode;
import com.espertech.esper.epl.expression.ExprNode;
import com.espertech.esper.epl.expression.ExprNodeUtility;
import com.espertech.esper.epl.expression.ExprValidationException;
import com.espertech.esper.epl.join.hint.ExcludePlanHint;
import com.espertech.esper.epl.lookup.*;
import com.espertech.esper.util.JavaClassHelper;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
* Build query index plans.
*/
public class QueryPlanIndexBuilder
{
    /**
     * Build index specification from navigability info.
     * <p>
     * Looks at each stream and determines which properties in the stream must be indexed
     * in order for other streams to look up into the stream. Determines the unique set of properties
     * to avoid building duplicate indexes on the same set of properties.
     * @param queryGraph - navigability info
     * @return query index specs for each stream
     */
    public static QueryPlanIndex[] buildIndexSpec(QueryGraph queryGraph, EventType[] typePerStream, String[][][] indexedStreamsUniqueProps)
    {
        int numStreams = queryGraph.getNumStreams();
        QueryPlanIndex[] indexSpecs = new QueryPlanIndex[numStreams];

        // For each stream compile a list of index property sets.
        for (int streamIndexed = 0; streamIndexed < numStreams; streamIndexed++)
        {
            List<QueryPlanIndexItem> indexesSet = new ArrayList<QueryPlanIndexItem>();

            // Look at the index from the viewpoint of the stream looking up in the index
            for (int streamLookup = 0; streamLookup < numStreams; streamLookup++)
            {
                if (streamIndexed == streamLookup)
                {
                    continue;
                }

                QueryGraphValue value = queryGraph.getGraphValue(streamLookup, streamIndexed);
                QueryGraphValuePairHashKeyIndex hashKeyAndIndexProps = value.getHashKeyProps();

                // Sort index properties, but use the sorted properties only to eliminate duplicates
                String[] hashIndexProps = hashKeyAndIndexProps.getIndexed();
                List<QueryGraphValueEntryHashKeyed> hashKeyProps = hashKeyAndIndexProps.getKeys();
                CoercionDesc indexCoercionTypes = CoercionUtil.getCoercionTypesHash(typePerStream, streamLookup, streamIndexed, hashKeyProps, hashIndexProps);
                Class[] hashCoercionTypeArr = indexCoercionTypes.getCoercionTypes();

                QueryGraphValuePairRangeIndex rangeAndIndexProps = value.getRangeProps();
                String[] rangeIndexProps = rangeAndIndexProps.getIndexed();
                List<QueryGraphValueEntryRange> rangeKeyProps = rangeAndIndexProps.getKeys();
                CoercionDesc rangeCoercionTypes = CoercionUtil.getCoercionTypesRange(typePerStream, streamIndexed, rangeIndexProps, rangeKeyProps);
                Class[] rangeCoercionTypeArr = rangeCoercionTypes.getCoercionTypes();

                if (hashIndexProps.length == 0 && rangeIndexProps.length == 0) {
                    QueryGraphValuePairInKWSingleIdx singles = value.getInKeywordSingles();
                    if (!singles.getKey().isEmpty()) {
                        String indexedProp = singles.getIndexed()[0];
                        QueryPlanIndexItem indexItem = new QueryPlanIndexItem(new String[] {indexedProp}, null, null, null, false);
                        checkDuplicateOrAdd(indexItem, indexesSet);
                    }

                    List<QueryGraphValuePairInKWMultiIdx> multis = value.getInKeywordMulti();
                    if (!multis.isEmpty()) {
                        QueryGraphValuePairInKWMultiIdx multi = multis.get(0);
                        for (ExprNode propIndexed : multi.getIndexed()) {
                            ExprIdentNode identNode = (ExprIdentNode) propIndexed;
                            QueryPlanIndexItem indexItem = new QueryPlanIndexItem(new String[] {identNode.getResolvedPropertyName()}, null, null, null, false);
                            checkDuplicateOrAdd(indexItem, indexesSet);
                        }
                    }
                    continue;
                }

                // reduce to any unique index if applicable
                boolean unique = false;
                QueryPlanIndexUniqueHelper.ReducedHashKeys reduced = QueryPlanIndexUniqueHelper.reduceToUniqueIfPossible(hashIndexProps, hashCoercionTypeArr, hashKeyProps, indexedStreamsUniqueProps[streamIndexed]);
                if (reduced != null) {
                    hashIndexProps = reduced.getPropertyNames();
                    hashCoercionTypeArr = reduced.getCoercionTypes();
                    unique = true;
                    rangeIndexProps = new String[0];
                    rangeCoercionTypeArr = new Class[0];
                }

                QueryPlanIndexItem proposed = new QueryPlanIndexItem(hashIndexProps, hashCoercionTypeArr, rangeIndexProps, rangeCoercionTypeArr, unique);
                checkDuplicateOrAdd(proposed, indexesSet);
            }

            // create full-table-scan
            if (indexesSet.isEmpty()) {
                indexesSet.add(new QueryPlanIndexItem(null, null, null, null, false));
            }

            indexSpecs[streamIndexed] = QueryPlanIndex.makeIndex(indexesSet);
        }

        return indexSpecs;
    }

    public static SubordPropPlan getJoinProps(ExprNode filterExpr, int outsideStreamCount, EventType[] allStreamTypesZeroIndexed, ExcludePlanHint excludePlanHint)
    {
        // No filter expression means full table scan
        if (filterExpr == null)
        {
            return new SubordPropPlan();
        }

        // analyze query graph
        QueryGraph queryGraph = new QueryGraph(outsideStreamCount + 1, excludePlanHint, true);
        FilterExprAnalyzer.analyze(filterExpr, queryGraph, false);

        // Build a list of streams and indexes
        LinkedHashMap<String, SubordPropHashKey> joinProps = new LinkedHashMap<String, SubordPropHashKey>();
        LinkedHashMap<String, SubordPropRangeKey> rangeProps = new LinkedHashMap<String, SubordPropRangeKey>();
        for (int stream = 0; stream <  outsideStreamCount; stream++)
        {
            int lookupStream = stream + 1;

            QueryGraphValue queryGraphValue = queryGraph.getGraphValue(lookupStream, 0);
            QueryGraphValuePairHashKeyIndex hashKeysAndIndexes = queryGraphValue.getHashKeyProps();

            // handle key-lookups
            List<QueryGraphValueEntryHashKeyed> keyPropertiesJoin = hashKeysAndIndexes.getKeys();
            String[] indexPropertiesJoin = hashKeysAndIndexes.getIndexed();
            if (!keyPropertiesJoin.isEmpty())
            {
                if (keyPropertiesJoin.size() != indexPropertiesJoin.length)
                {
                    throw new IllegalStateException("Invalid query key and index property collection for stream " + stream);
                }

                for (int i = 0; i < keyPropertiesJoin.size(); i++)
                {
                    QueryGraphValueEntryHashKeyed keyDesc = keyPropertiesJoin.get(i);
                    ExprNode compareNode = keyDesc.getKeyExpr();

                    Class keyPropType = JavaClassHelper.getBoxedType(compareNode.getExprEvaluator().getType());
                    Class indexedPropType = JavaClassHelper.getBoxedType(allStreamTypesZeroIndexed[0].getPropertyType(indexPropertiesJoin[i]));
                    Class coercionType = indexedPropType;
                    if (keyPropType != indexedPropType)
                    {
                        coercionType = JavaClassHelper.getCompareToCoercionType(keyPropType, indexedPropType);
                    }

                    SubordPropHashKey desc;
                    if (keyPropertiesJoin.get(i) instanceof QueryGraphValueEntryHashKeyedExpr) {
                        QueryGraphValueEntryHashKeyedExpr keyExpr = (QueryGraphValueEntryHashKeyedExpr) keyPropertiesJoin.get(i);
                        Integer keyStreamNum = keyExpr.isRequiresKey() ? stream : null;
                        desc = new SubordPropHashKey(keyDesc, keyStreamNum, coercionType);
                    }
                    else {
                        QueryGraphValueEntryHashKeyedProp prop = (QueryGraphValueEntryHashKeyedProp) keyDesc;
                        desc = new SubordPropHashKey(prop, stream, coercionType);
                    }
                    joinProps.put(indexPropertiesJoin[i], desc);
                }
            }

            // handle range lookups
            QueryGraphValuePairRangeIndex rangeKeysAndIndexes = queryGraphValue.getRangeProps();
            String[] rangeIndexes = rangeKeysAndIndexes.getIndexed();
            List<QueryGraphValueEntryRange> rangeDescs = rangeKeysAndIndexes.getKeys();
            if (rangeDescs.isEmpty()) {
                continue;
            }

            // get all ranges lookups
            int count = -1;
            for (QueryGraphValueEntryRange rangeDesc : rangeDescs) {
                count++;
                String rangeIndexProp = rangeIndexes[count];

                SubordPropRangeKey subqRangeDesc = rangeProps.get(rangeIndexProp);

                // other streams may specify the start or end endpoint of a range, therefore this operation can be additive
                if (subqRangeDesc != null) {
                    if (subqRangeDesc.getRangeInfo().getType().isRange()) {
                        continue;
                    }

                    // see if we can make this additive by using a range
                    QueryGraphValueEntryRangeRelOp relOpOther = (QueryGraphValueEntryRangeRelOp) subqRangeDesc.getRangeInfo();
                    QueryGraphValueEntryRangeRelOp relOpThis = (QueryGraphValueEntryRangeRelOp) rangeDesc;

                    QueryGraphRangeConsolidateDesc opsDesc = QueryGraphRangeUtil.getCanConsolidate(relOpThis.getType(), relOpOther.getType());
                    if (opsDesc != null) {
                        ExprNode start;
                        ExprNode end;
                        if (!opsDesc.isReverse()) {
                            start = relOpOther.getExpression();
                            end = relOpThis.getExpression();
                        }
                        else {
                            start = relOpThis.getExpression();
                            end = relOpOther.getExpression();
                        }
                        boolean allowRangeReversal = relOpOther.isBetweenPart() && relOpThis.isBetweenPart();
                        QueryGraphValueEntryRangeIn rangeIn = new QueryGraphValueEntryRangeIn(opsDesc.getType(), start, end, allowRangeReversal);

                        Class indexedPropType = JavaClassHelper.getBoxedType(allStreamTypesZeroIndexed[0].getPropertyType(rangeIndexProp));
                        Class coercionType = indexedPropType;
                        Class proposedType = CoercionUtil.getCoercionTypeRangeIn(indexedPropType, rangeIn.getExprStart(), rangeIn.getExprEnd());
                        if (proposedType != null && proposedType != indexedPropType)
                        {
                            coercionType = proposedType;
                        }

                        subqRangeDesc = new SubordPropRangeKey(rangeIn, coercionType);
                        rangeProps.put(rangeIndexProp, subqRangeDesc);
                    }
                    // ignore
                    continue;
                }

                // an existing entry has not been found
                if (rangeDesc.getType().isRange()) {
                    QueryGraphValueEntryRangeIn rangeIn = (QueryGraphValueEntryRangeIn) rangeDesc;
                    Class indexedPropType = JavaClassHelper.getBoxedType(allStreamTypesZeroIndexed[0].getPropertyType(rangeIndexProp));
                    Class coercionType = indexedPropType;
                    Class proposedType = CoercionUtil.getCoercionTypeRangeIn(indexedPropType, rangeIn.getExprStart(), rangeIn.getExprEnd());
                    if (proposedType != null && proposedType != indexedPropType)
                    {
                        coercionType = proposedType;
                    }
                    subqRangeDesc = new SubordPropRangeKey(rangeDesc, coercionType);
                }
                else {
                    QueryGraphValueEntryRangeRelOp relOp = (QueryGraphValueEntryRangeRelOp) rangeDesc;
                    Class keyPropType = relOp.getExpression().getExprEvaluator().getType();
                    Class indexedPropType = JavaClassHelper.getBoxedType(allStreamTypesZeroIndexed[0].getPropertyType(rangeIndexProp));
                    Class coercionType = indexedPropType;
                    if (keyPropType != indexedPropType)
                    {
                        coercionType = JavaClassHelper.getCompareToCoercionType(keyPropType, indexedPropType);
                    }
                    subqRangeDesc = new SubordPropRangeKey(rangeDesc, coercionType);
                }
                rangeProps.put(rangeIndexProp, subqRangeDesc);
            }
        }

        SubordPropInKeywordSingleIndex inKeywordSingleIdxProp = null;
        SubordPropInKeywordMultiIndex inKeywordMultiIdxProp = null;
        if (joinProps.isEmpty() && rangeProps.isEmpty()) {
            for (int stream = 0; stream <  outsideStreamCount; stream++) {
                int lookupStream = stream + 1;
                QueryGraphValue queryGraphValue = queryGraph.getGraphValue(lookupStream, 0);

                QueryGraphValuePairInKWSingleIdx inkwSingles = queryGraphValue.getInKeywordSingles();
                if (inkwSingles.getIndexed().length != 0) {
                    ExprNode[] keys = inkwSingles.getKey().get(0).getKeyExprs();
                    String key = inkwSingles.getIndexed()[0];
                    if (inKeywordSingleIdxProp != null) {
                        continue;
                    }
                    Class coercionType = keys[0].getExprEvaluator().getType()// for in-comparison the same type is required
                    inKeywordSingleIdxProp = new SubordPropInKeywordSingleIndex(key, coercionType, keys);
                }

                List<QueryGraphValuePairInKWMultiIdx> inkwMultis = queryGraphValue.getInKeywordMulti();
                if (!inkwMultis.isEmpty()) {
                    QueryGraphValuePairInKWMultiIdx multi = inkwMultis.get(0);
                    inKeywordMultiIdxProp = new SubordPropInKeywordMultiIndex(ExprNodeUtility.getIdentResolvedPropertyNames(multi.getIndexed()), multi.getIndexed()[0].getExprEvaluator().getType(), multi.getKey().getKeyExpr());
                }

                if (inKeywordSingleIdxProp != null && inKeywordMultiIdxProp != null) {
                    inKeywordMultiIdxProp = null;
                }
            }
        }

        return new SubordPropPlan(joinProps, rangeProps, inKeywordSingleIdxProp, inKeywordMultiIdxProp);
    }

    private static void checkDuplicateOrAdd(QueryPlanIndexItem proposed, List<QueryPlanIndexItem> indexesSet) {
        boolean found = false;
        for (QueryPlanIndexItem index : indexesSet) {
            if (proposed.equalsCompareSortedProps(index)) {
                found = true;
                break;
            }
        }

        if (!found) {
            indexesSet.add(proposed);
        }
    }
}
TOP

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

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.