/************************************************************************************** * 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.epl.agg.service.AggregationService; import com.espertech.esper.epl.expression.ExprEvaluator; import com.espertech.esper.epl.expression.ExprEvaluatorContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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 static final Log log = LogFactory.getLog(OrderByProcessorImpl.class); 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) { OrderByElement[] elements = factory.getOrderBy(); if (elements.length == 1) { return elements[0].getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext); } Object[] values = new Object[elements.length]; int count = 0; for (OrderByElement sortPair : factory.getOrderBy()) { values[count++] = sortPair.getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext); } 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; sortProperties[count] = singleEval.evaluate(evalEventsPerStream, isNewData, exprEvaluatorContext); count++; } } else { for (EventBean theEvent : generatingEvents) { Object[] values = new Object[factory.getOrderBy().length]; int countTwo = 0; evalEventsPerStream[0] = theEvent; for (OrderByElement sortPair : factory.getOrderBy()) { values[countTwo++] = sortPair.getExpr().evaluate(evalEventsPerStream, isNewData, exprEvaluatorContext); } 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, 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); // 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, factory.getComparator()); // 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; } 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()); } sortProperties[count] = elements[0].getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext); 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()); } Object[] values = new Object[factory.getOrderBy().length]; int countTwo = 0; for (OrderByElement sortPair : factory.getOrderBy()) { values[countTwo++] = sortPair.getExpr().evaluate(eventsPerStream, isNewData, exprEvaluatorContext); } 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); } }