/*
***************************************************************************************
* 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.epl.agg.util;
import com.espertech.esper.epl.agg.access.AggregationAccessor;
import com.espertech.esper.epl.agg.access.AggregationAccessorSlotPair;
import com.espertech.esper.epl.agg.service.AggregationMethodFactory;
import com.espertech.esper.epl.agg.service.AggregationServiceAggExpressionDesc;
import com.espertech.esper.epl.agg.service.AggregationStateFactory;
import com.espertech.esper.epl.expression.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.epl.expression.core.ExprNodeUtility;
import java.util.ArrayList;
import java.util.List;
/**
* - Each local-group-by gets its own access state factory, shared between same-local-group-by for compatible states
*/
public class AggregationGroupByLocalGroupByAnalyzer {
public static AggregationLocalGroupByPlan analyze(ExprEvaluator[] evaluators, AggregationMethodFactory[] prototypes, AggregationStateFactory[] accessAggregations, AggregationGroupByLocalGroupDesc localGroupDesc, ExprNode[] groupByExpressions, AggregationAccessorSlotPair[] accessors) {
if (groupByExpressions == null) {
groupByExpressions = ExprNodeUtility.EMPTY_EXPR_ARRAY;
}
AggregationLocalGroupByColumn[] columns = new AggregationLocalGroupByColumn[localGroupDesc.getNumColumns()];
List<AggregationLocalGroupByLevel> levelsList = new ArrayList<AggregationLocalGroupByLevel>();
AggregationLocalGroupByLevel optionalTopLevel = null;
// determine optional top level (level number is -1)
for (int i = 0; i < localGroupDesc.getLevels().length; i++) {
AggregationGroupByLocalGroupLevel levelDesc = localGroupDesc.getLevels()[i];
if (levelDesc.getPartitionExpr().length == 0) {
optionalTopLevel = getLevel(-1, levelDesc, evaluators, prototypes, accessAggregations, columns, groupByExpressions.length == 0, accessors);
}
}
// determine default (same as group-by) level, if any, assign level number 0
int levelNumber = 0;
for (int i = 0; i < localGroupDesc.getLevels().length; i++) {
AggregationGroupByLocalGroupLevel levelDesc = localGroupDesc.getLevels()[i];
if (levelDesc.getPartitionExpr().length == 0) {
continue;
}
boolean isDefaultLevel = groupByExpressions != null && ExprNodeUtility.deepEqualsIgnoreDupAndOrder(groupByExpressions, levelDesc.getPartitionExpr());
if (isDefaultLevel) {
AggregationLocalGroupByLevel level = getLevel(0, levelDesc, evaluators, prototypes, accessAggregations, columns, isDefaultLevel, accessors);
levelsList.add(level);
levelNumber++;
break;
}
}
// determine all other levels, assign level numbers
for (int i = 0; i < localGroupDesc.getLevels().length; i++) {
AggregationGroupByLocalGroupLevel levelDesc = localGroupDesc.getLevels()[i];
if (levelDesc.getPartitionExpr().length == 0) {
continue;
}
boolean isDefaultLevel = groupByExpressions != null && ExprNodeUtility.deepEqualsIgnoreDupAndOrder(groupByExpressions, levelDesc.getPartitionExpr());
if (isDefaultLevel) {
continue;
}
AggregationLocalGroupByLevel level = getLevel(levelNumber, levelDesc, evaluators, prototypes, accessAggregations, columns, isDefaultLevel, accessors);
levelsList.add(level);
levelNumber++;
}
// totals
int numMethods = 0;
int numAccesses = 0;
if (optionalTopLevel != null) {
numMethods += optionalTopLevel.getMethodFactories().length;
numAccesses += optionalTopLevel.getStateFactories().length;
}
for (AggregationLocalGroupByLevel level : levelsList) {
numMethods += level.getMethodFactories().length;
numAccesses += level.getStateFactories().length;
}
AggregationLocalGroupByLevel[] levels = levelsList.toArray(new AggregationLocalGroupByLevel[levelsList.size()]);
return new AggregationLocalGroupByPlan(numMethods, numAccesses, columns, optionalTopLevel, levels);
}
// Obtain those method and state factories for each level
private static AggregationLocalGroupByLevel getLevel(int levelNumber, AggregationGroupByLocalGroupLevel level, ExprEvaluator[] methodEvaluatorsAll, AggregationMethodFactory[] methodFactoriesAll, AggregationStateFactory[] stateFactoriesAll, AggregationLocalGroupByColumn[] columns, boolean defaultLevel, AggregationAccessorSlotPair[] accessors) {
ExprNode[] partitionExpr = level.getPartitionExpr();
ExprEvaluator[] partitionEvaluators = ExprNodeUtility.getEvaluators(partitionExpr);
List<ExprEvaluator> methodEvaluators = new ArrayList<ExprEvaluator>();
List<AggregationMethodFactory> methodFactories = new ArrayList<AggregationMethodFactory>();
List<AggregationStateFactory> stateFactories = new ArrayList<AggregationStateFactory>();
for (AggregationServiceAggExpressionDesc expr : level.getExpressions()) {
int column = expr.getColumnNum();
int methodOffset = -1;
boolean methodAgg = true;
AggregationAccessorSlotPair pair = null;
if (column < methodEvaluatorsAll.length) {
methodEvaluators.add(methodEvaluatorsAll[column]);
methodFactories.add(methodFactoriesAll[column]);
methodOffset = methodFactories.size() - 1;
} else {
// slot gives us the number of the state factory
int absoluteSlot = accessors[column - methodEvaluatorsAll.length].getSlot();
AggregationAccessor accessor = accessors[column - methodEvaluatorsAll.length].getAccessor();
AggregationStateFactory factory = stateFactoriesAll[absoluteSlot];
int relativeSlot = stateFactories.indexOf(factory);
if (relativeSlot == -1) {
stateFactories.add(factory);
relativeSlot = stateFactories.size() - 1;
}
methodAgg = false;
pair = new AggregationAccessorSlotPair(relativeSlot, accessor);
}
columns[column] = new AggregationLocalGroupByColumn(defaultLevel, partitionEvaluators, methodOffset, methodAgg, pair, levelNumber);
}
return new AggregationLocalGroupByLevel(methodEvaluators.toArray(new ExprEvaluator[methodEvaluators.size()]),
methodFactories.toArray(new AggregationMethodFactory[methodFactories.size()]),
stateFactories.toArray(new AggregationStateFactory[stateFactories.size()]), partitionEvaluators, defaultLevel);
}
}