Package org.drools.core.util.index

Source Code of org.drools.core.util.index.IndexUtil$Factory

package org.drools.core.util.index;

import org.drools.core.RuleBaseConfiguration;
import org.drools.core.reteoo.BetaMemory;
import org.drools.core.reteoo.BetaNode;
import org.drools.core.reteoo.LeftTupleMemory;
import org.drools.core.reteoo.NodeTypeEnums;
import org.drools.core.reteoo.RightTupleMemory;
import org.drools.core.rule.ContextEntry;
import org.drools.core.rule.IndexableConstraint;
import org.drools.core.rule.constraint.MvelConstraint;
import org.drools.core.spi.BetaNodeFieldConstraint;
import org.drools.core.spi.Constraint;
import org.drools.core.util.AbstractHashTable.FieldIndex;
import org.kie.internal.conf.IndexPrecedenceOption;

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

import static org.drools.core.util.ClassUtils.getter2property;

public class IndexUtil {

    private static final boolean USE_COMPARISON_INDEX = true;
    private static final boolean USE_RANGE_INDEX = USE_COMPARISON_INDEX && false;

    public static boolean compositeAllowed(BetaNodeFieldConstraint[] constraints, short betaNodeType) {
        // 1) If there is 1 or more unification restrictions it cannot be composite
        // 2) Ensures any non unification restrictions are first
        int firstUnification = -1;
        int firstNonUnification = -1;
        for ( int i = 0, length = constraints.length; i < length; i++ ) {
            if ( isIndexable(constraints[i], betaNodeType) ) {
                final boolean isUnification = ((IndexableConstraint) constraints[i]).isUnification();
                if ( isUnification && firstUnification == -1 ) {
                    firstUnification = i;
                } else if ( !isUnification &&firstNonUnification == -1 ) {
                    firstNonUnification = i;
                }
            }
            if ( firstUnification != -1 && firstNonUnification != -1) {
                break;
            }
        }

        if (firstNonUnification != -1 && firstNonUnification > 0) {
            // Make sure a nonunification indexable constraint is first
            swap(constraints, 0, firstNonUnification);
        }

        return (firstUnification == -1);
    }

    public static boolean isIndexable(BetaNodeFieldConstraint constraint, short nodeType) {
        return constraint instanceof IndexableConstraint && ((IndexableConstraint)constraint).isIndexable(nodeType);
    }

    private static boolean canHaveRangeIndex(short nodeType) {
        return USE_COMPARISON_INDEX && ( nodeType == NodeTypeEnums.NotNode || nodeType == NodeTypeEnums.ExistsNode );
    }

    public static boolean isIndexableForNode(short nodeType, BetaNodeFieldConstraint constraint) {
        if ( !(constraint instanceof IndexableConstraint) ) {
            return false;
        }

        ConstraintType constraintType = ((IndexableConstraint)constraint).getConstraintType();
        return constraintType.isIndexableForNode(nodeType);
    }

    public static boolean[] isIndexableForNode(IndexPrecedenceOption indexPrecedenceOption, short nodeType, int keyDepth, BetaNodeFieldConstraint[] constraints) {
        if (keyDepth < 1) {
            return new boolean[constraints.length];
        }

        return indexPrecedenceOption == IndexPrecedenceOption.EQUALITY_PRIORITY ?
                findIndexableWithEqualityPriority(nodeType, keyDepth, constraints) :
                findIndexableWithPatternOrder(nodeType, keyDepth, constraints);
    }

    private static boolean[] findIndexableWithEqualityPriority(short nodeType, int keyDepth, BetaNodeFieldConstraint[] constraints) {
        boolean[] indexable = new boolean[constraints.length];
        if (hasEqualIndexable(keyDepth, indexable, constraints)) {
            return indexable;
        }

        if (!canHaveRangeIndex(nodeType)) {
            return indexable;
        }

        for (int i = 0; i < constraints.length; i++) {
            if (isIndexable(constraints[i], nodeType)) {
                sortRangeIndexable(constraints, indexable, i);
                break;
            }
        }

        return indexable;
    }

    private static boolean[] findIndexableWithPatternOrder(short nodeType, int keyDepth, BetaNodeFieldConstraint[] constraints) {
        boolean[] indexable = new boolean[constraints.length];
        for (int i = 0; i < constraints.length; i++) {
            if (isIndexable(constraints[i], nodeType)) {
                if (isEqualIndexable(constraints[i])) {
                    sortEqualIndexable(keyDepth, indexable, constraints, i);
                } else {
                    sortRangeIndexable(constraints, indexable, i);
                }
                break;
            }
        }

        return indexable;
    }

    private static boolean hasEqualIndexable(int keyDepth, boolean[] indexable, BetaNodeFieldConstraint[] constraints) {
        return sortEqualIndexable(keyDepth, indexable, constraints, 0);
    }

    private static boolean sortEqualIndexable(int keyDepth, boolean[] indexable, BetaNodeFieldConstraint[] constraints, int start) {
        boolean hasEqualIndexable = false;
        int indexableCouter = 0;
        for (int i = start; i < constraints.length; i++) {
            if (isEqualIndexable(constraints[i])) {
                hasEqualIndexable = true;
                if (keyDepth > indexableCouter) {
                    swap(constraints, i, indexableCouter);
                    indexable[indexableCouter++] = true;
                }
            }
        }
        return hasEqualIndexable;
    }

    private static void sortRangeIndexable(BetaNodeFieldConstraint[] constraints, boolean[] indexable, int i) {
        int dualConstraintPosition = findDualConstraint(constraints, i);
        swap(constraints, i, 0);
        indexable[0] = true;
        if (dualConstraintPosition > 0) {
            swap(constraints, dualConstraintPosition, 1);
            indexable[1] = true;
        }
    }

    private static int findDualConstraint(BetaNodeFieldConstraint[] constraints, int comparisonPos) {
        if ( !(USE_RANGE_INDEX && constraints[comparisonPos] instanceof MvelConstraint) ) {
            return -1;
        }
        MvelConstraint firstConstraint = (MvelConstraint) constraints[comparisonPos];
        String leftValue = getLeftValueInExpression(firstConstraint.getExpression());
        for (int i = comparisonPos+1; i < constraints.length; i++) {
            if (constraints[i] instanceof MvelConstraint) {
                MvelConstraint dualConstraint = (MvelConstraint) constraints[i];
                if (isDual(firstConstraint, leftValue, dualConstraint)) {
                    return i;
                }
            }
        }
        return -1;
    }

    private static boolean isEqualIndexable(BetaNodeFieldConstraint constraint) {
        return constraint instanceof IndexableConstraint && ((IndexableConstraint)constraint).getConstraintType() == ConstraintType.EQUAL;
    }

    private static void swap(BetaNodeFieldConstraint[] constraints, int p1, int p2) {
        if (p1 != p2) {
            BetaNodeFieldConstraint temp = constraints[p2];
            constraints[p2] = constraints[p1];
            constraints[p1] = temp;
        }
    }

    public enum ConstraintType {
        EQUAL(true),
        NOT_EQUAL(false),
        GREATER_THAN(true),
        GREATER_OR_EQUAL(true),
        LESS_THAN(true),
        LESS_OR_EQUAL(true),
        RANGE(true),
        UNKNOWN(false);

        private final boolean indexable;

        private ConstraintType(boolean indexable) {
            this.indexable = indexable;
        }

        public boolean isComparison() {
            return isAscending() || isDescending();
        }

        public boolean isEquality() {
            return this == EQUAL || this == NOT_EQUAL;
        }

        public boolean isAscending() {
            return this == GREATER_THAN || this == GREATER_OR_EQUAL;
        }

        public boolean isDescending() {
            return this == LESS_THAN || this == LESS_OR_EQUAL;
        }

        public boolean isIndexable() {
            return indexable;
        }

        public boolean isIndexableForNode(short nodeType) {
            switch (this) {
                case EQUAL:
                    return true;
                case NOT_EQUAL:
                case UNKNOWN:
                    return false;
                default:
                    return canHaveRangeIndex(nodeType);
            }
        }

        public static ConstraintType decode(String operator) {
            if (operator.equals("==")) {
                return EQUAL;
            }
            if (operator.equals("!=")) {
                return NOT_EQUAL;
            }
            if (operator.equals(">")) {
                return GREATER_THAN;
            }
            if (operator.equals(">=")) {
                return GREATER_OR_EQUAL;
            }
            if (operator.equals("<")) {
                return LESS_THAN;
            }
            if (operator.equals("<=")) {
                return LESS_OR_EQUAL;
            }
            return UNKNOWN;
        }

        public static ConstraintType getType(Constraint constraint) {
            return constraint instanceof IndexableConstraint ? ((IndexableConstraint)constraint).getConstraintType() : UNKNOWN;
        }
    }

    public static List<String> getIndexedProperties(BetaNode betaNode, RuleBaseConfiguration config) {
        int keyDepth = config.getCompositeKeyDepth();
        if (config.getCompositeKeyDepth() < 1) {
            return Collections.emptyList();
        }

        Factory.IndexSpec indexSpec = new Factory.IndexSpec(config.getIndexPrecedenceOption(), keyDepth, betaNode.getType(), betaNode.getConstraints());
        List<String> indexedProps = new ArrayList<String>();
        for (FieldIndex fieldIndex : indexSpec.indexes) {
            indexedProps.add( getter2property(fieldIndex.getExtractor().getNativeReadMethodName()) );
        }

        return indexedProps;
    }

    public static class Factory {
        public static BetaMemory createBetaMemory(RuleBaseConfiguration config, short nodeType, BetaNodeFieldConstraint... constraints) {
            int keyDepth = config.getCompositeKeyDepth();
            if (config.getCompositeKeyDepth() < 1) {
                return new BetaMemory( config.isSequential() ? null : new LeftTupleList(),
                                       new RightTupleList(),
                                       createContext(constraints),
                                       nodeType );
            }

            IndexSpec indexSpec = new IndexSpec(config.getIndexPrecedenceOption(), keyDepth, nodeType, constraints);
            return new BetaMemory( createLeftMemory(config, indexSpec),
                                   createRightMemory(config, indexSpec),
                                   createContext(constraints),
                                   nodeType );
        }

        private static RightTupleMemory createRightMemory(RuleBaseConfiguration config, IndexSpec indexSpec) {
            if ( !config.isIndexRightBetaMemory() || !indexSpec.constraintType.isIndexable() ) {
                return new RightTupleList();
            }

            if (indexSpec.constraintType == ConstraintType.EQUAL) {
                return new RightTupleIndexHashTable( indexSpec.indexes );
            }

            if (indexSpec.constraintType.isComparison()) {
                return new RightTupleIndexRBTree( indexSpec.constraintType, indexSpec.indexes[0] );
            }

            if (indexSpec.constraintType == ConstraintType.RANGE) {
                // missing TreeMap based implementation for range indexes
                return new RightTupleIndexRangeRBTree( indexSpec.ascendingConstraintType, indexSpec.indexes[0],
                                                       indexSpec.descendingConstraintType, indexSpec.indexes[1] );
            }

            return new RightTupleList();
        }

        private static LeftTupleMemory createLeftMemory(RuleBaseConfiguration config, IndexSpec indexSpec) {
            if (config.isSequential()) {
                return null;
            }
            if ( !config.isIndexLeftBetaMemory() || !indexSpec.constraintType.isIndexable() ) {
                return new LeftTupleList();
            }

            if (indexSpec.constraintType == ConstraintType.EQUAL) {
                return new LeftTupleIndexHashTable( indexSpec.indexes );
            }

            if (indexSpec.constraintType.isComparison()) {
                return new LeftTupleIndexRBTree( indexSpec.constraintType, indexSpec.indexes[0] );
            }

            if (indexSpec.constraintType == ConstraintType.RANGE) {
                // missing TreeMap based implementation for range indexes
                return new LeftTupleIndexRangeRBTree( indexSpec.ascendingConstraintType, indexSpec.indexes[0],
                                                      indexSpec.descendingConstraintType, indexSpec.indexes[1] );
            }

            return new LeftTupleList();
        }

        public static ContextEntry[] createContext(BetaNodeFieldConstraint... constraints) {
            ContextEntry[] entries = new ContextEntry[constraints.length];
            for (int i = 0; i < constraints.length; i++) {
                entries[i] = constraints[i].createContextEntry();
            }
            return entries;
        }

        private static class IndexSpec {
            private ConstraintType constraintType = ConstraintType.UNKNOWN;
            private FieldIndex[] indexes;

            private ConstraintType ascendingConstraintType = null;
            private ConstraintType descendingConstraintType = null;

            private IndexSpec(IndexPrecedenceOption indexPrecedenceOption, int keyDepth, short nodeType, BetaNodeFieldConstraint[] constraints) {
                init(indexPrecedenceOption, keyDepth, nodeType, constraints);
            }

            private void init(IndexPrecedenceOption indexPrecedenceOption, int keyDepth, short nodeType, BetaNodeFieldConstraint[] constraints) {
                int firstIndexableConstraint = indexPrecedenceOption == IndexPrecedenceOption.EQUALITY_PRIORITY ?
                        determineTypeWithEqualityPriority(nodeType, constraints) :
                        determineTypeWithPatternOrder(nodeType, constraints);

                if (constraintType == ConstraintType.EQUAL) {
                    List<FieldIndex> indexList = new ArrayList<FieldIndex>();
                    indexList.add(((IndexableConstraint)constraints[firstIndexableConstraint]).getFieldIndex());

                    // look for other EQUAL constraint to eventually add them to the index
                    for (int i = firstIndexableConstraint+1; i < constraints.length && indexList.size() < keyDepth; i++) {
                        if ( ConstraintType.getType(constraints[i]) == ConstraintType.EQUAL && ! ((IndexableConstraint) constraints[i]).isUnification() ) {
                            indexList.add(((IndexableConstraint)constraints[i]).getFieldIndex());
                        }
                    }
                    indexes = indexList.toArray(new FieldIndex[indexList.size()]);

                } else if (constraintType.isComparison()) {
                    // look for a dual constraint to create a range index
                    if (USE_RANGE_INDEX && constraints[firstIndexableConstraint] instanceof MvelConstraint) {
                        MvelConstraint firstConstraint = (MvelConstraint) constraints[firstIndexableConstraint];
                        String leftValue = getLeftValueInExpression(firstConstraint.getExpression());
                        for (int i = firstIndexableConstraint+1; i < constraints.length; i++) {
                            if (constraints[i] instanceof MvelConstraint) {
                                MvelConstraint dualConstraint = (MvelConstraint) constraints[i];
                                if (isDual(firstConstraint, leftValue, dualConstraint)) {
                                    constraintType = ConstraintType.RANGE;
                                    if (firstConstraint.getConstraintType().isAscending()) {
                                        ascendingConstraintType = firstConstraint.getConstraintType();
                                        descendingConstraintType = dualConstraint.getConstraintType();
                                        indexes = new FieldIndex[]{ firstConstraint.getFieldIndex(), dualConstraint.getFieldIndex() };
                                    } else {
                                        ascendingConstraintType = dualConstraint.getConstraintType();
                                        descendingConstraintType = firstConstraint.getConstraintType();
                                        indexes = new FieldIndex[]{ dualConstraint.getFieldIndex(), firstConstraint.getFieldIndex() };
                                    }
                                    return;
                                }
                            }
                        }
                    }

                    indexes = new FieldIndex[]{ ((IndexableConstraint)constraints[firstIndexableConstraint]).getFieldIndex() };
                }
            }

            private int determineTypeWithEqualityPriority(short nodeType, BetaNodeFieldConstraint[] constraints) {
                int indexedConstraintPos = 0;
                for (int i = 0; i < constraints.length; i++) {
                    if (constraints[i] instanceof IndexableConstraint) {
                        IndexableConstraint indexableConstraint = (IndexableConstraint) constraints[i];
                        ConstraintType type = indexableConstraint.getConstraintType();
                        if (type == ConstraintType.EQUAL) {
                            constraintType = type;
                            return i;
                        } else if (constraintType == ConstraintType.UNKNOWN && type.isIndexableForNode(nodeType)) {
                            constraintType = type;
                            indexedConstraintPos = i;
                        }
                    }
                }
                return indexedConstraintPos;
            }

            private int determineTypeWithPatternOrder(short nodeType, BetaNodeFieldConstraint[] constraints) {
                for (int i = 0; i < constraints.length; i++) {
                    ConstraintType type = ConstraintType.getType(constraints[i]);
                    if ( type.isIndexableForNode(nodeType) ) {
                        constraintType = type;
                        return i;
                    }
                }
                return constraints.length;
            }

        }
    }

    private static boolean isDual(MvelConstraint firstConstraint, String leftValue, MvelConstraint dualConstraint) {
        return dualConstraint.getConstraintType().isComparison() &&
                dualConstraint.getConstraintType().isAscending() != firstConstraint.getConstraintType().isAscending() &&
                leftValue.equals( getLeftValueInExpression(dualConstraint.getExpression()) );
    }

    private static String getLeftValueInExpression(String expression) {
        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);
            if ( !Character.isJavaIdentifierPart(ch) && ch != '.' ) {
                return expression.substring(0, i);
            }
        }
        return expression;
    }
}
TOP

Related Classes of org.drools.core.util.index.IndexUtil$Factory

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.
ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');