/**************************************************************************************
* 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.core;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.epl.agg.service.AggregationService;
import com.espertech.esper.epl.agg.rollup.GroupByRollupKey;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.ExprEvaluatorContext;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import java.util.*;
/**
* An order-by processor that sorts events according to the expressions
* in the order_by clause.
*/
public class OrderByProcessorImpl implements OrderByProcessor {
private final OrderByProcessorFactoryImpl factory;
private final AggregationService aggregationService;
public OrderByProcessorImpl(OrderByProcessorFactoryImpl factory, AggregationService aggregationService) {
this.factory = factory;
this.aggregationService = aggregationService;
}
public Object getSortKey(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
return getSortKeyInternal(eventsPerStream, isNewData, exprEvaluatorContext, factory.getOrderBy());
}
public Object getSortKey(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext, OrderByElement[] elementsForLevel) {
return getSortKeyInternal(eventsPerStream, isNewData, exprEvaluatorContext, elementsForLevel);
}
private static Object getSortKeyInternal(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext, OrderByElement[] elements) {
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(eventsPerStream, elements);}
if (elements.length == 1) {
if (InstrumentationHelper.ENABLED) {
Object value = elements[0].getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
InstrumentationHelper.get().aOrderBy(value);
return value;
}
return elements[0].getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
}
Object[] values = new Object[elements.length];
int count = 0;
for (OrderByElement sortPair : elements) {
values[count++] = sortPair.getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(values);}
return new MultiKeyUntyped(values);
}
public Object[] getSortKeyPerRow(EventBean[] generatingEvents, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
if (generatingEvents == null)
{
return null;
}
Object[] sortProperties = new Object[generatingEvents.length];
int count = 0;
EventBean[] evalEventsPerStream = new EventBean[1];
if (factory.getOrderBy().length == 1) {
ExprEvaluator singleEval = factory.getOrderBy()[0].getExpr();
for (EventBean theEvent : generatingEvents)
{
evalEventsPerStream[0] = theEvent;
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(evalEventsPerStream, factory.getOrderBy());}
sortProperties[count] = singleEval.evaluate(evalEventsPerStream, isNewData, exprEvaluatorContext);
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(sortProperties[count]);}
count++;
}
}
else {
for (EventBean theEvent : generatingEvents)
{
Object[] values = new Object[factory.getOrderBy().length];
int countTwo = 0;
evalEventsPerStream[0] = theEvent;
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(evalEventsPerStream, factory.getOrderBy());}
for (OrderByElement sortPair : factory.getOrderBy()) {
values[countTwo++] = sortPair.getExpr().evaluate(evalEventsPerStream, isNewData, exprEvaluatorContext);
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(values);}
sortProperties[count] = new MultiKeyUntyped(values);
count++;
}
}
return sortProperties;
}
public EventBean[] sort(EventBean[] outgoingEvents, EventBean[][] generatingEvents, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
if (outgoingEvents == null || outgoingEvents.length < 2)
{
return outgoingEvents;
}
// Get the group by keys if needed
Object[] groupByKeys = null;
if (factory.isNeedsGroupByKeys())
{
groupByKeys = generateGroupKeys(generatingEvents, isNewData, exprEvaluatorContext);
}
return sort(outgoingEvents, generatingEvents, groupByKeys, isNewData, exprEvaluatorContext);
}
public EventBean[] sort(EventBean[] outgoingEvents, List<GroupByRollupKey> currentGenerators, boolean isNewData, AgentInstanceContext exprEvaluatorContext, OrderByElement[][] elementsPerLevel)
{
List<Object> sortValuesMultiKeys = createSortPropertiesWRollup(currentGenerators, elementsPerLevel, isNewData, exprEvaluatorContext);
return sortInternal(outgoingEvents, sortValuesMultiKeys, factory.getComparator());
}
public EventBean[] sort(EventBean[] outgoingEvents, EventBean[][] generatingEvents, Object[] groupByKeys, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
if (outgoingEvents == null || outgoingEvents.length < 2) {
return outgoingEvents;
}
// Create the multikeys of sort values
List<Object> sortValuesMultiKeys = createSortProperties(generatingEvents, groupByKeys, isNewData, exprEvaluatorContext);
return sortInternal(outgoingEvents, sortValuesMultiKeys, factory.getComparator());
}
private List<Object> createSortProperties(EventBean[][] generatingEvents, Object[] groupByKeys, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
Object[] sortProperties = new Object[generatingEvents.length];
OrderByElement[] elements = factory.getOrderBy();
if (elements.length == 1) {
int count = 0;
for (EventBean[] eventsPerStream : generatingEvents)
{
// Make a new multikey that contains the sort-by values.
if (factory.isNeedsGroupByKeys())
{
aggregationService.setCurrentAccess(groupByKeys[count], exprEvaluatorContext.getAgentInstanceId(), null);
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(eventsPerStream, factory.getOrderBy());}
sortProperties[count] = elements[0].getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(sortProperties[count]);}
count++;
}
}
else {
int count = 0;
for (EventBean[] eventsPerStream : generatingEvents)
{
// Make a new multikey that contains the sort-by values.
if (factory.isNeedsGroupByKeys())
{
aggregationService.setCurrentAccess(groupByKeys[count], exprEvaluatorContext.getAgentInstanceId(), null);
}
Object[] values = new Object[factory.getOrderBy().length];
int countTwo = 0;
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(eventsPerStream, factory.getOrderBy());}
for (OrderByElement sortPair : factory.getOrderBy()) {
values[countTwo++] = sortPair.getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(values);}
sortProperties[count] = new MultiKeyUntyped(values);
count++;
}
}
return Arrays.asList(sortProperties);
}
public EventBean[] sort(EventBean[] outgoingEvents, Object[] orderKeys, ExprEvaluatorContext exprEvaluatorContext)
{
TreeMap<Object, Object> sort = new TreeMap<Object, Object>(factory.getComparator());
if (outgoingEvents == null || outgoingEvents.length < 2)
{
return outgoingEvents;
}
for (int i = 0; i < outgoingEvents.length; i++)
{
Object entry = sort.get(orderKeys[i]);
if (entry == null)
{
sort.put(orderKeys[i], outgoingEvents[i]);
}
else if (entry instanceof EventBean)
{
List<EventBean> list = new ArrayList<EventBean>();
list.add((EventBean)entry);
list.add(outgoingEvents[i]);
sort.put(orderKeys[i], list);
}
else
{
List<EventBean> list = (List<EventBean>) entry;
list.add(outgoingEvents[i]);
}
}
EventBean[] result = new EventBean[outgoingEvents.length];
int count = 0;
for (Object entry : sort.values())
{
if (entry instanceof List)
{
List<EventBean> output = (List<EventBean>) entry;
for(EventBean theEvent : output)
{
result[count++] = theEvent;
}
}
else
{
result[count++] = (EventBean) entry;
}
}
return result;
}
private Object[] generateGroupKeys(EventBean[][] generatingEvents, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
Object keys[] = new Object[generatingEvents.length];
int count = 0;
for (EventBean[] eventsPerStream : generatingEvents)
{
keys[count++] = generateGroupKey(eventsPerStream, isNewData, exprEvaluatorContext);
}
return keys;
}
private Object generateGroupKey(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
{
ExprEvaluator[] evals = factory.getGroupByNodes();
if (evals.length == 1) {
return evals[0].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
}
Object[] keys = new Object[evals.length];
int count = 0;
for (ExprEvaluator exprNode : evals)
{
keys[count] = exprNode.evaluate(eventsPerStream, isNewData, exprEvaluatorContext);
count++;
}
return new MultiKeyUntyped(keys);
}
private List<Object> createSortPropertiesWRollup(List<GroupByRollupKey> currentGenerators, OrderByElement[][] elementsPerLevel, boolean isNewData, AgentInstanceContext exprEvaluatorContext) {
Object[] sortProperties = new Object[currentGenerators.size()];
OrderByElement[] elements = factory.getOrderBy();
if (elements.length == 1) {
int count = 0;
for (GroupByRollupKey rollup : currentGenerators) {
// Make a new multikey that contains the sort-by values.
if (factory.isNeedsGroupByKeys()) {
aggregationService.setCurrentAccess(rollup.getGroupKey(), exprEvaluatorContext.getAgentInstanceId(), rollup.getLevel());
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(rollup.getGenerator(), factory.getOrderBy());}
sortProperties[count] = elementsPerLevel[rollup.getLevel().getLevelNumber()][0].getExpr().evaluate(rollup.getGenerator(), isNewData, exprEvaluatorContext);
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(sortProperties[count]);}
count++;
}
}
else {
int count = 0;
for (GroupByRollupKey rollup : currentGenerators) {
// Make a new multikey that contains the sort-by values.
if (factory.isNeedsGroupByKeys()) {
aggregationService.setCurrentAccess(rollup.getGroupKey(), exprEvaluatorContext.getAgentInstanceId(), rollup.getLevel());
}
Object[] values = new Object[factory.getOrderBy().length];
int countTwo = 0;
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qOrderBy(rollup.getGenerator(), factory.getOrderBy());}
for (OrderByElement sortPair : elementsPerLevel[rollup.getLevel().getLevelNumber()]) {
values[countTwo++] = sortPair.getExpr().evaluate(rollup.getGenerator(), isNewData, exprEvaluatorContext);
}
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aOrderBy(values);}
sortProperties[count] = new MultiKeyUntyped(values);
count++;
}
}
return Arrays.asList(sortProperties);
}
private static EventBean[] sortInternal(EventBean[] outgoingEvents, List<Object> sortValuesMultiKeys, Comparator<Object> comparator) {
// Map the sort values to the corresponding outgoing events
Map<Object, List<EventBean>> sortToOutgoing = new HashMap<Object, List<EventBean>>();
int countOne = 0;
for (Object sortValues : sortValuesMultiKeys)
{
List<EventBean> list = sortToOutgoing.get(sortValues);
if (list == null)
{
list = new ArrayList<EventBean>();
}
list.add(outgoingEvents[countOne++]);
sortToOutgoing.put(sortValues, list);
}
// Sort the sort values
Collections.sort(sortValuesMultiKeys, comparator);
// Sort the outgoing events in the same order
Set<Object> sortSet = new LinkedHashSet<Object>(sortValuesMultiKeys);
EventBean[] result = new EventBean[outgoingEvents.length];
int countTwo = 0;
for (Object sortValues : sortSet)
{
Collection<EventBean> output = sortToOutgoing.get(sortValues);
for(EventBean theEvent : output)
{
result[countTwo++] = theEvent;
}
}
return result;
}
}