/**************************************************************************************
* 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.join.base;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.collection.MultiKey;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.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++;
}
}
}