// return false
if (predecessors.size() == 0 || predecessors.size() > 1) {
return false;
}
LogicalOperator predecessor = predecessors.get(0);
// if the predecessor is one of LOLoad/LOStore/LOStream/LOLimit/LONative
// return false
if (predecessor instanceof LOLoad || predecessor instanceof LOStore
|| predecessor instanceof LOStream
|| predecessor instanceof LOLimit
|| predecessor instanceof LONative) {
return false;
}
// TODO
// for now filters cannot be combined
// remove this check when filters can be combined
if (predecessor instanceof LOFilter)
return false;
// TODO
// same rule as filters
if (predecessor instanceof LOSplitOutput) {
return false;
}
if (predecessor instanceof LOSplit) {
return false;
}
UDFFinder udfFinder = new UDFFinder(filter.getComparisonPlan());
udfFinder.visit();
// if the filter's inner plan contains any UDF then return false
if (udfFinder.foundAnyUDF()) {
return false;
}
CastFinder castFinder = new CastFinder(filter.getComparisonPlan());
castFinder.visit();
// if the filter's inner plan contains any casts then return false
if (castFinder.foundAnyCast()) {
return false;
}
List<RequiredFields> filterRequiredFields = filter
.getRequiredFields();
if (filterRequiredFields == null) {
return false;
}
RequiredFields requiredField = filterRequiredFields.get(0);
// the filter's conditions contain constant expression
// return false
if (requiredField.needNoFields()) {
return false;
}
// if the predecessor is a multi-input operator then detailed
// checks are required
if (predecessor instanceof LOCross
|| predecessor instanceof LOUnion
|| predecessor instanceof LOCogroup
|| predecessor instanceof LOJoin) {
// check if the filter's required fields in conjunction with the
// predecessor's projection map. If the filter needs more than
// one input then the filter's expressions have to be split
List<LogicalOperator> grandParents = mPlan
.getPredecessors(predecessor);
// if the predecessor does not have predecessors return false
if (grandParents == null || grandParents.size() == 0) {
return false;
}
// check if the predecessor is a group by
if (grandParents.size() == 1) {
if (predecessor instanceof LOCogroup) {
mSwap = true;
return true;
} else {
// only a group by can have a single input
return false;
}
}
if (requiredField.needAllFields()) {
return false;
}
Pair<Boolean, Set<Integer>> mappingResult = isRequiredFieldMapped(requiredField, predecessor.getProjectionMap());
boolean mapped = mappingResult.first;
Set<Integer> grandParentIndexes = mappingResult.second;
if (!mapped) {
return false;
}
// TODO
// the filter's conditions requires more than one input of its
// predecessor
// when the filter's conditions are splittable return true
if ((grandParentIndexes == null)
|| (grandParentIndexes.size() == 0)
|| (grandParentIndexes.size() > 1)) {
return false;
}
if (predecessor instanceof LOCogroup) {
// check for outer
if (isAnyOuter((LOCogroup) predecessor)) {
return false;
}
}
mPushBeforeInput = grandParentIndexes.iterator().next();
if (predecessor instanceof LOJoin) {
boolean otherBranchContainOuter = false;
boolean sawInner = false;
for (int i=0;i<=mPlan.getSuccessors(predecessor).size();i++) {
// We do not push filter if any other branch is outer
// See PIG-1289
// Also in LOJoin, innerFlag==true indicate that branch is the outer join side
// which has the exact opposite semantics
// If all innerFlag is true, that implies a regular join
// If all innerFlag is false, means a outer join, in this case, we can not push up filter for any path (See PIG-1507)
if (i!=mPushBeforeInput && ((LOJoin)predecessor).getInnerFlags()[i]) {
otherBranchContainOuter = true;
}
if (((LOJoin)predecessor).getInnerFlags()[i]==false) {
sawInner = true;
}
}
if (!otherBranchContainOuter && ((LOJoin)predecessor).getInnerFlags()[mPushBeforeInput]==false) // all innerFlag is false, implies an outer join
{
mPushBeforeInput = -1;
return false;
}
if (otherBranchContainOuter && sawInner) // If it is not a regular join and the path we push is on inner side
{
mPushBeforeInput = -1;
return false;
}
}
mPushBefore = true;
return true;
} 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;
}
}
// TODO
// A better check is to examine each column in the filter's
// required fields. If the column is the result of a flatten
// then
// return false else return true
// for now if the foreach has a flatten then return false
if (hasFlatten) {
return false;
}
Pair<Boolean, Set<Integer>> mappingResult = isRequiredFieldMapped(requiredField, predecessor.getProjectionMap());
boolean mapped = mappingResult.first;
// Check if it is a direct mapping, that is, project optionally followed by cast, so if project->project, it is not
// considered as a mapping
for (Pair<Integer, Integer> pair : requiredField.getFields())