/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* 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.filter;
import com.espertech.esper.collection.Pair;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.util.JavaClassHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Helper to compile (validate and optimize) filter expressions as used in pattern and filter-based streams.
*/
public final class FilterSpecCompilerConsolidateUtil {
protected static void consolidate(FilterParamExprMap filterParamExprMap, String statementName) {
// consolidate or place in a boolean expression (by removing filter spec param from the map)
// any filter parameter that feature the same property name and filter operator,
// i.e. we are looking for "a!=5 and a!=6" to transform to "a not in (5,6)" which can match faster
// considering that "a not in (5,6) and a not in (7,8)" is "a not in (5, 6, 7, 8)" therefore
// we need to consolidate until there is no more work to do
Map<Pair<FilterSpecLookupable, FilterOperator>, List<FilterSpecParam>> mapOfParams = new HashMap<Pair<FilterSpecLookupable, FilterOperator>, List<FilterSpecParam>>();
boolean haveConsolidated;
do {
haveConsolidated = false;
mapOfParams.clear();
// sort into buckets of propertyName + filterOperator combination
for (FilterSpecParam currentParam : filterParamExprMap.getFilterParams()) {
FilterSpecLookupable lookupable = currentParam.getLookupable();
FilterOperator op = currentParam.getFilterOperator();
Pair<FilterSpecLookupable, FilterOperator> key = new Pair<FilterSpecLookupable, FilterOperator>(lookupable, op);
List<FilterSpecParam> existingParam = mapOfParams.get(key);
if (existingParam == null) {
existingParam = new ArrayList<FilterSpecParam>();
mapOfParams.put(key, existingParam);
}
existingParam.add(currentParam);
}
for (List<FilterSpecParam> entry : mapOfParams.values()) {
if (entry.size() > 1) {
haveConsolidated = true;
consolidate(entry, filterParamExprMap, statementName);
}
}
}
while (haveConsolidated);
}
// remove duplicate propertyName + filterOperator items making a judgement to optimize or simply remove the optimized form
private static void consolidate(List<FilterSpecParam> items, FilterParamExprMap filterParamExprMap, String statementName) {
FilterOperator op = items.get(0).getFilterOperator();
if (op == FilterOperator.NOT_EQUAL) {
handleConsolidateNotEqual(items, filterParamExprMap, statementName);
} else {
// for all others we simple remove the second optimized form (filter param with same prop name and filter op)
// and thus the boolean expression that started this is included
for (int i = 1; i < items.size(); i++) {
filterParamExprMap.removeValue(items.get(i));
}
}
}
// consolidate "val != 3 and val != 4 and val != 5"
// to "val not in (3, 4, 5)"
private static void handleConsolidateNotEqual(List<FilterSpecParam> parameters, FilterParamExprMap filterParamExprMap, String statementName) {
List<FilterSpecParamInValue> values = new ArrayList<FilterSpecParamInValue>();
ExprNode lastNotEqualsExprNode = null;
for (FilterSpecParam param : parameters) {
if (param instanceof FilterSpecParamConstant) {
FilterSpecParamConstant constantParam = (FilterSpecParamConstant) param;
Object constant = constantParam.getFilterConstant();
values.add(new FilterForEvalConstantAnyType(constant));
} else if (param instanceof FilterSpecParamEventProp) {
FilterSpecParamEventProp eventProp = (FilterSpecParamEventProp) param;
values.add(new FilterForEvalEventPropMayCoerce(eventProp.getResultEventAsName(), eventProp.getResultEventProperty(),
eventProp.isMustCoerce(), JavaClassHelper.getBoxedType(eventProp.getCoercionType())));
} else if (param instanceof FilterSpecParamEventPropIndexed) {
FilterSpecParamEventPropIndexed eventProp = (FilterSpecParamEventPropIndexed) param;
values.add(new FilterForEvalEventPropIndexedMayCoerce(eventProp.getResultEventAsName(), eventProp.getResultEventIndex(), eventProp.getResultEventProperty(),
eventProp.isMustCoerce(), JavaClassHelper.getBoxedType(eventProp.getCoercionType()), statementName));
} else {
throw new IllegalArgumentException("Unknown filter parameter:" + param.toString());
}
lastNotEqualsExprNode = filterParamExprMap.removeEntry(param);
}
FilterSpecParamIn param = new FilterSpecParamIn(parameters.get(0).getLookupable(), FilterOperator.NOT_IN_LIST_OF_VALUES, values);
filterParamExprMap.put(lastNotEqualsExprNode, param);
}
}