/* *************************************************************************************** * 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.join.base; import com.espertech.esper.client.EventBean; import com.espertech.esper.collection.MultiKey; import com.espertech.esper.epl.expression.core.ExprEvaluator; import com.espertech.esper.epl.expression.core.ExprEvaluatorContext; import com.espertech.esper.epl.join.pollindex.PollResultIndexingStrategy; import com.espertech.esper.epl.join.table.EventTable; import com.espertech.esper.view.HistoricalEventViewable; import java.util.Iterator; import java.util.Set; /** * Query strategy for use with {@link HistoricalEventViewable} * to perform lookup for a given stream using the poll method on a viewable. */ public class HistoricalDataQueryStrategy implements QueryStrategy { private final int myStreamNumber; private final int historicalStreamNumber; private final HistoricalEventViewable historicalEventViewable; private final EventBean[][] lookupRows1Event; private final boolean isOuterJoin; private final ExprEvaluator outerJoinCompareNode; private final HistoricalIndexLookupStrategy indexLookupStrategy; private final PollResultIndexingStrategy pollResultIndexingStrategy; /** * Ctor. * * @param myStreamNumber is the strategy's stream number * @param historicalStreamNumber is the stream number of the view to be polled * @param historicalEventViewable is the view to be polled from * @param isOuterJoin is this is an outer join * @param outerJoinCompareNode is the node to perform the on-comparison for outer joins * @param indexLookupStrategy the strategy to use for limiting the cache result set * to only those rows that match filter criteria * @param pollResultIndexingStrategy the strategy for indexing poll-results such that a * strategy can use the index instead of a full table scan to resolve rows */ public HistoricalDataQueryStrategy(int myStreamNumber, int historicalStreamNumber, HistoricalEventViewable historicalEventViewable, boolean isOuterJoin, ExprEvaluator outerJoinCompareNode, HistoricalIndexLookupStrategy indexLookupStrategy, PollResultIndexingStrategy pollResultIndexingStrategy) { this.myStreamNumber = myStreamNumber; this.historicalStreamNumber = historicalStreamNumber; this.historicalEventViewable = historicalEventViewable; this.isOuterJoin = isOuterJoin; this.outerJoinCompareNode = outerJoinCompareNode; lookupRows1Event = new EventBean[1][]; lookupRows1Event[0] = new EventBean[2]; this.indexLookupStrategy = indexLookupStrategy; this.pollResultIndexingStrategy = pollResultIndexingStrategy; } public void lookup(EventBean[] lookupEvents, Set<MultiKey<EventBean>> joinSet, ExprEvaluatorContext exprEvaluatorContext) { EventBean[][] lookupRows; // If looking up a single event, reuse the buffered array if (lookupEvents.length == 1) { lookupRows = lookupRows1Event; lookupRows[0][myStreamNumber] = lookupEvents[0]; } else { // Prepare rows with each row N events where N is the number of streams lookupRows = new EventBean[lookupEvents.length][]; for (int i = 0; i < lookupEvents.length; i++) { lookupRows[i] = new EventBean[2]; lookupRows[i][myStreamNumber] = lookupEvents[i]; } } EventTable[][] indexPerLookupRow = historicalEventViewable.poll(lookupRows, pollResultIndexingStrategy, exprEvaluatorContext); int count = 0; for (EventTable[] index : indexPerLookupRow) { // Using the index, determine a subset of the whole indexed table to process, unless // the strategy is a full table scan Iterator<EventBean> subsetIter = indexLookupStrategy.lookup(lookupEvents[count], index, exprEvaluatorContext); // In an outer join if (isOuterJoin && ((subsetIter == null || (!subsetIter.hasNext())))) { EventBean[] resultRow = new EventBean[2]; resultRow[myStreamNumber] = lookupEvents[count]; joinSet.add(new MultiKey<EventBean>(resultRow)); } else { boolean foundMatch = false; if (subsetIter != null) { // Add each row to the join result or, for outer joins, run through the outer join filter for (; subsetIter.hasNext(); ) { EventBean[] resultRow = new EventBean[2]; resultRow[myStreamNumber] = lookupEvents[count]; resultRow[historicalStreamNumber] = subsetIter.next(); // In an outer join compare the on-fields if (outerJoinCompareNode != null) { Boolean compareResult = (Boolean) outerJoinCompareNode.evaluate(resultRow, true, exprEvaluatorContext); if ((compareResult != null) && compareResult) { joinSet.add(new MultiKey<EventBean>(resultRow)); foundMatch = true; } } else { joinSet.add(new MultiKey<EventBean>(resultRow)); } } } if (isOuterJoin && (!foundMatch)) { EventBean[] resultRow = new EventBean[2]; resultRow[myStreamNumber] = lookupEvents[count]; joinSet.add(new MultiKey<EventBean>(resultRow)); } } count++; } } }