try {
List<LogicalOperator> predecessors = mPlan.getPredecessors(limit);
if (predecessors.size()!=1) {
int errCode = 2008;
String msg = "Limit cannot have more than one input. Found " + predecessors.size() + " inputs.";
throw new OptimizerException(msg, errCode, PigException.BUG);
}
LogicalOperator predecessor = predecessors.get(0);
// Limit cannot be pushed up
if (predecessor instanceof LOCogroup || predecessor instanceof LOFilter ||
predecessor instanceof LOLoad || predecessor instanceof LOSplit ||
predecessor instanceof LOSplitOutput || predecessor instanceof LODistinct || predecessor instanceof LOJoin)
{
return;
}
// Limit can be pushed in front of ForEach if it does not have a flatten
else if (predecessor instanceof LOForEach)
{
LOForEach loForEach = (LOForEach)predecessor;
List<Boolean> mFlatten = loForEach.getFlatten();
boolean hasFlatten = false;
for (Boolean b:mFlatten)
if (b.equals(true)) hasFlatten = true;
// We can safely move LOLimit up
if (!hasFlatten)
{
// Get operator before LOFilter
LogicalOperator prepredecessor = mPlan.getPredecessors(predecessor).get(0);
if (prepredecessor!=null)
{
try {
mPlan.removeAndReconnect(limit);
insertBetween(prepredecessor, limit, predecessor, null);
} catch (Exception e) {
int errCode = 2009;
String msg = "Can not move LOLimit up";
throw new OptimizerException(msg, errCode, PigException.BUG, e);
}
}
else
{
int errCode = 2010;
String msg = "LOForEach should have one input";
throw new OptimizerException(msg, errCode, PigException.BUG);
}
// we can move LOLimit even further, recursively optimize LOLimit
processNode(limit);
}
}
// Limit can be duplicated, and the new instance pushed in front of an operator for the following operators
// (that is, if you have X->limit, you can transform that to limit->X->limit):
else if (predecessor instanceof LOCross || predecessor instanceof LOUnion)
{
LOLimit newLimit = null;
List<LogicalOperator> nodesToProcess = new ArrayList<LogicalOperator>();
for (LogicalOperator prepredecessor:mPlan.getPredecessors(predecessor))
nodesToProcess.add(prepredecessor);
for (LogicalOperator prepredecessor:nodesToProcess)
{
try {
newLimit = limit.duplicate();
insertBetween(prepredecessor, newLimit, predecessor, null);
} catch (Exception e) {
int errCode = 2011;
String msg = "Can not insert LOLimit clone";
throw new OptimizerException(msg, errCode, PigException.BUG, e);
}
// we can move the new LOLimit even further, recursively optimize LOLimit
processNode(newLimit);
}
}
// Limit can be merged into LOSort, result a "limited sort"
else if (predecessor instanceof LOSort)
{
if(mode == ExecType.LOCAL) {
//We don't need this optimisation to happen in the local mode.
//so we do nothing here.
} else {
LOSort sort = (LOSort)predecessor;
if (sort.getLimit()==-1)
sort.setLimit(limit.getLimit());
else
sort.setLimit(sort.getLimit()<limit.getLimit()?sort.getLimit():limit.getLimit());
try {
mPlan.removeAndReconnect(limit);
} catch (Exception e) {
int errCode = 2012;
String msg = "Can not remove LOLimit after LOSort";
throw new OptimizerException(msg, errCode, PigException.BUG, e);
}
}
}
// Limit is merged into another LOLimit
else if (predecessor instanceof LOLimit)
{
LOLimit beforeLimit = (LOLimit)predecessor;
beforeLimit.setLimit(beforeLimit.getLimit()<limit.getLimit()?beforeLimit.getLimit():limit.getLimit());
try {
mPlan.removeAndReconnect(limit);
} catch (Exception e) {
int errCode = 2012;
String msg = "Can not remove LOLimit after LOLimit";
throw new OptimizerException(msg, errCode, PigException.BUG, e);
}
}
else {
int errCode = 2013;
String msg = "Moving LOLimit in front of " + predecessor.getClass().getSimpleName() + " is not implemented";
throw new OptimizerException(msg, errCode, PigException.BUG);
}
} catch (OptimizerException oe) {
throw oe;
} catch (Exception e) {
int errCode = 2050;
String msg = "Internal error. Unable to optimize limit operator.";
throw new OptimizerException(msg, errCode, PigException.BUG);
}
}