/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pig.pen; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pig.backend.executionengine.ExecException; import org.apache.pig.data.BagFactory; import org.apache.pig.data.DataBag; import org.apache.pig.data.DataByteArray; import org.apache.pig.data.DataType; import org.apache.pig.data.Tuple; import org.apache.pig.data.TupleFactory; import org.apache.pig.impl.logicalLayer.BinaryExpressionOperator; import org.apache.pig.impl.logicalLayer.ExpressionOperator; import org.apache.pig.impl.logicalLayer.FrontendException; import org.apache.pig.impl.logicalLayer.LOAdd; import org.apache.pig.impl.logicalLayer.LOAnd; import org.apache.pig.impl.logicalLayer.LOCast; import org.apache.pig.impl.logicalLayer.LOCogroup; import org.apache.pig.impl.logicalLayer.LOConst; import org.apache.pig.impl.logicalLayer.LOCross; import org.apache.pig.impl.logicalLayer.LODistinct; import org.apache.pig.impl.logicalLayer.LODivide; import org.apache.pig.impl.logicalLayer.LOEqual; import org.apache.pig.impl.logicalLayer.LOFilter; import org.apache.pig.impl.logicalLayer.LOForEach; import org.apache.pig.impl.logicalLayer.LOGreaterThan; import org.apache.pig.impl.logicalLayer.LOGreaterThanEqual; import org.apache.pig.impl.logicalLayer.LOLesserThan; import org.apache.pig.impl.logicalLayer.LOLesserThanEqual; import org.apache.pig.impl.logicalLayer.LOLoad; import org.apache.pig.impl.logicalLayer.LOMod; import org.apache.pig.impl.logicalLayer.LOMultiply; import org.apache.pig.impl.logicalLayer.LONot; import org.apache.pig.impl.logicalLayer.LONotEqual; import org.apache.pig.impl.logicalLayer.LOOr; import org.apache.pig.impl.logicalLayer.LOProject; import org.apache.pig.impl.logicalLayer.LORegexp; import org.apache.pig.impl.logicalLayer.LOSort; import org.apache.pig.impl.logicalLayer.LOSplit; import org.apache.pig.impl.logicalLayer.LOStore; import org.apache.pig.impl.logicalLayer.LOSubtract; import org.apache.pig.impl.logicalLayer.LOUnion; import org.apache.pig.impl.logicalLayer.LOVisitor; import org.apache.pig.impl.logicalLayer.LogicalOperator; import org.apache.pig.impl.logicalLayer.LogicalPlan; import org.apache.pig.impl.logicalLayer.schema.Schema; import org.apache.pig.impl.plan.DepthFirstWalker; import org.apache.pig.impl.plan.VisitorException; import org.apache.pig.pen.util.ExampleTuple; import org.apache.pig.pen.util.PreOrderDepthFirstWalker; //This is used to generate synthetic data //Synthetic data generation is done by making constraint tuples for each operator as we traverse the plan //and try to replace the constraints with values as far as possible. We only deal with simple conditions right now public class AugmentBaseDataVisitor extends LOVisitor { Map<LOLoad, DataBag> baseData = null; Map<LOLoad, DataBag> newBaseData = new HashMap<LOLoad, DataBag>(); Map<LogicalOperator, DataBag> derivedData = null; Map<LogicalOperator, DataBag> outputConstraintsMap = new HashMap<LogicalOperator, DataBag>(); Log log = LogFactory.getLog(getClass()); // Augmentation moves from the leaves to root and hence needs a // depthfirstwalker public AugmentBaseDataVisitor(LogicalPlan plan, Map<LOLoad, DataBag> baseData, Map<LogicalOperator, DataBag> derivedData) { super(plan, new PreOrderDepthFirstWalker<LogicalOperator, LogicalPlan>( plan)); this.baseData = baseData; this.derivedData = derivedData; } public Map<LOLoad, DataBag> getNewBaseData() { for (Map.Entry<LOLoad, DataBag> e : baseData.entrySet()) { DataBag bag = newBaseData.get(e.getKey()); if (bag == null) { bag = BagFactory.getInstance().newDefaultBag(); newBaseData.put(e.getKey(), bag); } bag.addAll(e.getValue()); } return newBaseData; } @Override protected void visit(LOCogroup cg) throws VisitorException { // we first get the outputconstraints for the current cogroup DataBag outputConstraints = outputConstraintsMap.get(cg); outputConstraintsMap.remove(cg); boolean ableToHandle = true; // we then check if we can handle this cogroup and try to collect some // information about grouping List<List<Integer>> groupSpecs = new LinkedList<List<Integer>>(); int numCols = -1; int minGroupSize = (cg.getInputs().size() == 1) ? 1 : 2; for (LogicalOperator op : cg.getInputs()) { List<LogicalPlan> groupByPlans = (List<LogicalPlan>) cg .getGroupByPlans().get(op); List<Integer> groupCols = new ArrayList<Integer>(); for (LogicalPlan plan : groupByPlans) { LogicalOperator leaf = plan.getLeaves().get(0); if (leaf instanceof LOProject) { groupCols.add(((LOProject) leaf).getCol()); } else { ableToHandle = false; break; } } if (numCols == -1) { numCols = groupCols.size(); } if (groupCols.size() != groupByPlans.size() || groupCols.size() != numCols) { // we came across an unworkable cogroup plan break; } else { groupSpecs.add(groupCols); } } // we should now have some workable data at this point to synthesize // tuples try { if (ableToHandle) { // we need to go through the output constraints first int numInputs = cg.getInputs().size(); if (outputConstraints != null) { for (Iterator<Tuple> it = outputConstraints.iterator(); it .hasNext();) { Tuple outputConstraint = it.next(); Object groupLabel = outputConstraint.get(0); for (int input = 0; input < numInputs; input++) { int numInputFields = cg.getInputs().get(input) .getSchema().size(); List<Integer> groupCols = groupSpecs.get(input); DataBag output = outputConstraintsMap.get(cg .getInputs().get(input)); if (output == null) { output = BagFactory.getInstance() .newDefaultBag(); outputConstraintsMap.put(cg.getInputs().get( input), output); } for (int i = 0; i < minGroupSize; i++) { Tuple inputConstraint = GetGroupByInput( groupLabel, groupCols, numInputFields); if (inputConstraint != null) output.add(inputConstraint); } } } } // then, go through all organic data groups and add input // constraints to make each group big enough DataBag outputData = derivedData.get(cg); for (Iterator<Tuple> it = outputData.iterator(); it.hasNext();) { Tuple groupTup = it.next(); Object groupLabel = groupTup.get(0); for (int input = 0; input < numInputs; input++) { int numInputFields = cg.getInputs().get(input) .getSchema().size(); List<Integer> groupCols = groupSpecs.get(input); DataBag output = outputConstraintsMap.get(cg .getInputs().get(input)); if (output == null) { output = BagFactory.getInstance().newDefaultBag(); outputConstraintsMap.put(cg.getInputs().get(input), output); } int numTupsToAdd = minGroupSize - (int) ((DataBag) groupTup.get(input + 1)) .size(); for (int i = 0; i < numTupsToAdd; i++) { Tuple inputConstraint = GetGroupByInput(groupLabel, groupCols, numInputFields); if (inputConstraint != null) output.add(inputConstraint); } } } } } catch (Exception e) { log .error("Error visiting Cogroup during Augmentation phase of Example Generator! " + e.getMessage()); throw new VisitorException( "Error visiting Cogroup during Augmentation phase of Example Generator! " + e.getMessage()); } } @Override protected void visit(LOCross cs) throws VisitorException { } @Override protected void visit(LODistinct dt) throws VisitorException { } @Override protected void visit(LOFilter filter) throws VisitorException { DataBag outputConstraints = outputConstraintsMap.get(filter); outputConstraintsMap.remove(filter); LogicalPlan filterCond = filter.getComparisonPlan(); DataBag inputConstraints = outputConstraintsMap.get(filter.getInput()); if (inputConstraints == null) { inputConstraints = BagFactory.getInstance().newDefaultBag(); outputConstraintsMap.put(filter.getInput(), inputConstraints); } DataBag outputData = derivedData.get(filter); DataBag inputData = derivedData.get(filter.getInput()); try { if (outputConstraints != null && outputConstraints.size() > 0) { // there // 's // one // or // more // output // constraints // ; // generate // corresponding // input // constraints for (Iterator<Tuple> it = outputConstraints.iterator(); it .hasNext();) { Tuple outputConstraint = it.next(); ExampleTuple inputConstraint = GenerateMatchingTuple( outputConstraint, filterCond, false); if (inputConstraint != null) inputConstraints.add(inputConstraint); } } else if (outputData.size() == 0) { // no output constraints, but // output is empty; generate // one input that will pass the // filter ExampleTuple inputConstraint = GenerateMatchingTuple(filter .getSchema(), filterCond, false); if (inputConstraint != null) inputConstraints.add(inputConstraint); } // if necessary, insert a negative example (i.e. a tuple that does // not pass the filter) if (outputData.size() == inputData.size()) { // all tuples pass the // filter; generate one // input that will not // pass the filter ExampleTuple inputConstraint = GenerateMatchingTuple(filter .getSchema(), filterCond, true); if (inputConstraint != null) inputConstraints.add(inputConstraint); } } catch (Exception e) { log .error("Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); throw new VisitorException( "Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); } } @Override protected void visit(LOForEach forEach) throws VisitorException { DataBag outputConstraints = outputConstraintsMap.get(forEach); outputConstraintsMap.remove(forEach); List<LogicalPlan> plans = forEach.getForEachPlans(); boolean ableToHandle = true; List<Integer> cols = new ArrayList<Integer>(); boolean cast = false; if (outputConstraints == null || outputConstraints.size() == 0) // we dont have to do anything in this case return; for (LogicalPlan plan : plans) { LogicalOperator op = plan.getLeaves().get(0); if (op instanceof LOCast) { cast = true; op = ((LOCast) op).getExpression(); } if (!(op instanceof LOProject)) { ableToHandle = false; break; } else { cols.add(((LOProject) op).getCol()); } } if (ableToHandle) { // we can only handle simple projections DataBag output = BagFactory.getInstance().newDefaultBag(); for (Iterator<Tuple> it = outputConstraints.iterator(); it .hasNext();) { Tuple outputConstraint = it.next(); try { Tuple inputConstraint = BackPropConstraint( outputConstraint, cols, (forEach.getPlan() .getPredecessors(forEach)).get(0) .getSchema(), cast); output.add(inputConstraint); } catch (Exception e) { e.printStackTrace(); throw new VisitorException( "Operator error during Augmenting Phase in Example Generator " + e.getMessage()); } } outputConstraintsMap.put(forEach.getPlan().getPredecessors(forEach) .get(0), output); } } @Override protected void visit(LOLoad load) throws VisitorException { DataBag inputData = baseData.get(load); DataBag newInputData = newBaseData.get(load); if (newInputData == null) { newInputData = BagFactory.getInstance().newDefaultBag(); newBaseData.put(load, newInputData); } Schema schema; try { schema = load.getSchema(); if (schema == null) throw new RuntimeException( "Example Generator requires a schema. Please provide a schema while loading data"); } catch (FrontendException e) { log .error("Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); throw new VisitorException( "Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); } DataBag outputConstraints = outputConstraintsMap.get(load); outputConstraintsMap.remove(load); // check if the inputData exists if (inputData == null || inputData.size() == 0) { log.error("No input data found!"); throw new RuntimeException("No input data found!"); } // first of all, we are required to guarantee that there is at least one // output tuple if (outputConstraints == null || outputConstraints.size() == 0) { outputConstraints = BagFactory.getInstance().newDefaultBag(); outputConstraints.add(TupleFactory.getInstance().newTuple( schema.getFields().size())); } // create example tuple to steal values from when we encounter // "don't care" fields (i.e. null fields) Tuple exampleTuple = inputData.iterator().next(); // run through output constraints; for each one synthesize a tuple and // add it to the base data // (while synthesizing individual fields, try to match fields that exist // in the real data) for (Iterator<Tuple> it = outputConstraints.iterator(); it.hasNext();) { Tuple outputConstraint = it.next(); // sanity check: if (outputConstraint.size() != schema.getFields().size()) throw new RuntimeException( "Internal error: incorrect number of fields in constraint tuple."); Tuple inputT = TupleFactory.getInstance().newTuple( outputConstraint.size()); ExampleTuple inputTuple = new ExampleTuple(inputT); try { for (int i = 0; i < inputTuple.size(); i++) { Object d = outputConstraint.get(i); if (d == null) d = exampleTuple.get(i); inputTuple.set(i, d); } } catch (ExecException e) { log .error("Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); throw new VisitorException( "Error visiting Load during Augmentation phase of Example Generator! " + e.getMessage()); } if (!inputTuple.equals(exampleTuple)) inputTuple.synthetic = true; newInputData.add(inputTuple); } } @Override protected void visit(LOSort s) throws VisitorException { DataBag outputConstraints = outputConstraintsMap.get(s); outputConstraintsMap.remove(s); if (outputConstraints == null) outputConstraintsMap.put(s.getInput(), BagFactory.getInstance() .newDefaultBag()); else outputConstraintsMap.put(s.getInput(), outputConstraints); } @Override protected void visit(LOSplit split) throws VisitorException { } @Override protected void visit(LOStore store) throws VisitorException { DataBag outputConstraints = outputConstraintsMap.get(store); if (outputConstraints == null) { outputConstraintsMap.put(store.getPlan().getPredecessors(store) .get(0), BagFactory.getInstance().newDefaultBag()); } else { outputConstraintsMap.remove(store); outputConstraintsMap.put(store.getPlan().getPredecessors(store) .get(0), outputConstraints); } } @Override protected void visit(LOUnion u) throws VisitorException { DataBag outputConstraints = outputConstraintsMap.get(u); outputConstraintsMap.remove(u); if (outputConstraints == null || outputConstraints.size() == 0) { // we dont need to do anything // we just find the inputs, create empty bags as their // outputConstraints and return for (LogicalOperator op : u.getInputs()) { DataBag constraints = BagFactory.getInstance().newDefaultBag(); outputConstraintsMap.put(op, constraints); } return; } // since we have some outputConstraints, we apply them to the inputs // round-robin int count = 0; List<LogicalOperator> inputs = u.getInputs(); int noInputs = inputs.size(); for (LogicalOperator op : inputs) { DataBag constraint = BagFactory.getInstance().newDefaultBag(); outputConstraintsMap.put(op, constraint); } for (Iterator<Tuple> it = outputConstraints.iterator(); it.hasNext();) { DataBag constraint = outputConstraintsMap.get(inputs.get(count)); constraint.add(it.next()); count = (count + 1) % noInputs; } } Tuple GetGroupByInput(Object groupLabel, List<Integer> groupCols, int numFields) throws ExecException { Tuple t = TupleFactory.getInstance().newTuple(numFields); if (groupCols.size() == 1) { // GroupLabel would be a data atom t.set(groupCols.get(0), groupLabel); } else { if (!(groupLabel instanceof Tuple)) throw new RuntimeException("Unrecognized group label!"); Tuple group = (Tuple) groupLabel; for (int i = 0; i < groupCols.size(); i++) { t.set(groupCols.get(i), group.get(i)); } } return t; } Tuple BackPropConstraint(Tuple outputConstraint, List<Integer> cols, Schema inputSchema, boolean cast) throws ExecException { Tuple inputConst = TupleFactory.getInstance().newTuple( inputSchema.getFields().size()); Tuple inputConstraint = new ExampleTuple(inputConst); for (int outCol = 0; outCol < outputConstraint.size(); outCol++) { int inCol = cols.get(outCol); Object outVal = outputConstraint.get(outCol); Object inVal = inputConstraint.get(inCol); if (inVal == null && outVal != null) { // inputConstraint.set(inCol, outVal); inputConstraint.set(inCol, (cast) ? new DataByteArray(outVal .toString().getBytes()) : outVal); } else { if (outVal != null) { // unable to back-propagate, due to conflicting column // constraints, so give up return null; } } } return inputConstraint; } // generate a constraint tuple that conforms to the schema and passes the // predicate // (or null if unable to find such a tuple) ExampleTuple GenerateMatchingTuple(Schema schema, LogicalPlan plan, boolean invert) throws ExecException { return GenerateMatchingTuple(TupleFactory.getInstance().newTuple( schema.getFields().size()), plan, invert); } // generate a constraint tuple that conforms to the constraint and passes // the predicate // (or null if unable to find such a tuple) // // for now, constraint tuples are tuples whose fields are a blend of actual // data values and nulls, // where a null stands for "don't care" // // in the future, may want to replace "don't care" with a more rich // constraint language; this would // help, e.g. in the case of two filters in a row (you want the downstream // filter to tell the upstream filter // what predicate it wants satisfied in a given field) // ExampleTuple GenerateMatchingTuple(Tuple constraint, LogicalPlan predicate, boolean invert) throws ExecException { Tuple t = TupleFactory.getInstance().newTuple(constraint.size()); ExampleTuple tOut = new ExampleTuple(t); for (int i = 0; i < t.size(); i++) tOut.set(i, constraint.get(i)); GenerateMatchingTupleHelper(tOut, (ExpressionOperator) predicate .getLeaves().get(0), invert); tOut.synthetic = true; return tOut; } void GenerateMatchingTupleHelper(Tuple t, ExpressionOperator pred, boolean invert) throws ExecException { if (pred instanceof BinaryExpressionOperator) GenerateMatchingTupleHelper(t, (BinaryExpressionOperator) pred, invert); else if (pred instanceof LONot) GenerateMatchingTupleHelper(t, (LONot) pred, invert); else throw new ExecException("Unknown operator in filter predicate"); } void GenerateMatchingTupleHelper(Tuple t, BinaryExpressionOperator pred, boolean invert) throws ExecException { if (pred instanceof LOAnd) { GenerateMatchingTupleHelper(t, (LOAnd) pred, invert); return; } else if (pred instanceof LOOr) { GenerateMatchingTupleHelper(t, (LOOr) pred, invert); return; } // now we are sure that the expression operators are the roots of the // plan boolean leftIsConst = false, rightIsConst = false; Object leftConst = null, rightConst = null; byte leftDataType = 0, rightDataType = 0; int leftCol = -1, rightCol = -1; if (pred instanceof LOAdd || pred instanceof LOSubtract || pred instanceof LOMultiply || pred instanceof LODivide || pred instanceof LOMod || pred instanceof LORegexp) return; // We don't try to work around these operators right now if (pred.getLhsOperand() instanceof LOConst) { leftIsConst = true; leftConst = ((LOConst) (pred.getLhsOperand())).getValue(); } else { LogicalOperator lhs = pred.getLhsOperand(); if (lhs instanceof LOCast) lhs = ((LOCast) lhs).getExpression(); // if (!(pred.getLhsOperand() instanceof LOProject && ((LOProject) // pred // .getLhsOperand()).getProjection().size() == 1)) // return; // too hard if (!(lhs instanceof LOProject && ((LOProject) lhs).getProjection() .size() == 1)) return; leftCol = ((LOProject) lhs).getCol(); leftDataType = ((LOProject) lhs).getType(); Object d = t.get(leftCol); if (d != null) { leftIsConst = true; leftConst = d; } } if (pred.getRhsOperand() instanceof LOConst) { rightIsConst = true; rightConst = ((LOConst) (pred.getRhsOperand())).getValue(); } else { LogicalOperator rhs = pred.getRhsOperand(); if (rhs instanceof LOCast) rhs = ((LOCast) rhs).getExpression(); // if (!(pred.getRhsOperand() instanceof LOProject && ((LOProject) // pred // .getRhsOperand()).getProjection().size() == 1)) // return; // too hard if (!(rhs instanceof LOProject && ((LOProject) rhs).getProjection() .size() == 1)) return; rightCol = ((LOProject) rhs).getCol(); rightDataType = ((LOProject) rhs).getType(); Object d = t.get(rightCol); if (d != null) { rightIsConst = true; rightConst = d; } } if (leftIsConst && rightIsConst) return; // can't really change the result if both are constants // now we try to change some nulls to constants // convert some nulls to constants if (!invert) { if (pred instanceof LOEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, leftConst .toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, rightConst .toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "0")); } } else if (pred instanceof LONotEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetUnequalValue(leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetUnequalValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "1")); } } else if (pred instanceof LOGreaterThan || pred instanceof LOGreaterThanEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetSmallerValue(leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetLargerValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "1")); t.set(rightCol, generateData(rightDataType, "0")); } } else if (pred instanceof LOLesserThan || pred instanceof LOLesserThanEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetLargerValue( leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetSmallerValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "1")); } } } else { if (pred instanceof LOEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetUnequalValue(leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetUnequalValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "1")); } } else if (pred instanceof LONotEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, leftConst .toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, rightConst .toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "0")); } } else if (pred instanceof LOGreaterThan || pred instanceof LOGreaterThanEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetLargerValue( leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetSmallerValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "0")); t.set(rightCol, generateData(rightDataType, "1")); } } else if (pred instanceof LOLesserThan || pred instanceof LOLesserThanEqual) { if (leftIsConst) { t.set(rightCol, generateData(rightDataType, GetSmallerValue(leftConst).toString())); } else if (rightIsConst) { t.set(leftCol, generateData(leftDataType, GetLargerValue( rightConst).toString())); } else { t.set(leftCol, generateData(leftDataType, "1")); t.set(rightCol, generateData(rightDataType, "0")); } } } } void GenerateMatchingTupleHelper(Tuple t, LOAnd op, boolean invert) throws ExecException { ExpressionOperator input = op.getLhsOperand(); GenerateMatchingTupleHelper(t, input, invert); input = op.getRhsOperand(); GenerateMatchingTupleHelper(t, input, invert); } void GenerateMatchingTupleHelper(Tuple t, LOOr op, boolean invert) throws ExecException { ExpressionOperator input = op.getLhsOperand(); GenerateMatchingTupleHelper(t, input, invert); input = op.getRhsOperand(); GenerateMatchingTupleHelper(t, input, invert); } void GenerateMatchingTupleHelper(Tuple t, LONot op, boolean invert) throws ExecException { ExpressionOperator input = op.getOperand(); GenerateMatchingTupleHelper(t, input, !invert); } Object GetUnequalValue(Object v) { byte type = DataType.findType(v); if (type == DataType.BAG || type == DataType.TUPLE || type == DataType.MAP) return null; Object zero = generateData(type, "0"); if (v.equals(zero)) return generateData(type, "1"); return zero; } Object GetSmallerValue(Object v) { byte type = DataType.findType(v); if (type == DataType.BAG || type == DataType.TUPLE || type == DataType.MAP) return null; switch (type) { case DataType.CHARARRAY: String str = (String) v; if (str.length() > 0) return new String(str.substring(0, str.length() - 1)); else return null; case DataType.BYTEARRAY: DataByteArray data = (DataByteArray) v; if (data.size() > 0) return new DataByteArray(data.get(), 0, data.size() - 1); else return null; case DataType.INTEGER: return new Integer((Integer) v - 1); case DataType.LONG: return new Long((Long) v - 1); case DataType.FLOAT: return new Float((Float) v - 1); case DataType.DOUBLE: return new Double((Double) v - 1); default: return null; } } Object GetLargerValue(Object v) { byte type = DataType.findType(v); if (type == DataType.BAG || type == DataType.TUPLE || type == DataType.MAP) return null; switch (type) { case DataType.CHARARRAY: return new String((String) v + "0"); case DataType.BYTEARRAY: String str = ((DataByteArray) v).toString(); str = str + "0"; return new DataByteArray(str); case DataType.INTEGER: return new Integer((Integer) v + 1); case DataType.LONG: return new Long((Long) v + 1); case DataType.FLOAT: return new Float((Float) v + 1); case DataType.DOUBLE: return new Double((Double) v + 1); default: return null; } } Object generateData(byte type, String data) { switch (type) { case DataType.BOOLEAN: return new Boolean(data); case DataType.BYTEARRAY: return new DataByteArray(data.getBytes()); case DataType.DOUBLE: return new Double(data); case DataType.FLOAT: return new Float(data); case DataType.INTEGER: return new Integer(data); case DataType.LONG: return new Long(data); case DataType.CHARARRAY: return data; default: return null; } } }