@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
        Object... nodeOutputs) throws SemanticException {
      ExprNodeGenericFuncDesc fd = (ExprNodeGenericFuncDesc) nd;

      // 1. If it is not an OR operator, we bail out.
      if (!FunctionRegistry.isOpOr(fd)) {
        return null;
      }

      // 2. It is an OR operator with enough children
      List<ExprNodeDesc> children = fd.getChildren();
      if (children.size() < minOrExpr) {
        return null;
      }
      ListMultimap<String,Pair<ExprNodeColumnDesc, ExprNodeConstantDesc>> columnConstantsMap =
              ArrayListMultimap.create();
      boolean modeAnd = false;
      for (int i = 0; i < children.size(); i++) {
        ExprNodeDesc child = children.get(i);

        // - If the child is an AND operator, extract its children
        // - Otherwise, take the child itself
        final List<ExprNodeDesc> conjunctions;
        if (FunctionRegistry.isOpAnd(child)) {
          // If it is the first child, we set the mode variable value
          // Otherwise, if the mode we are working on is different, we
          // bail out
          if (i == 0) {
            modeAnd = true;
          } else {
            if (!modeAnd) {
              return null;
            }
          }

          // Multiple children
          conjunctions = child.getChildren();
        } else {
          // If it is the first child, we set the mode variable value
          // Otherwise, if the mode we are working on is different, we
          // bail out
          if (i == 0) {
            modeAnd = false;
          } else {
            if (modeAnd) {
              return null;
            }
          }

          // One child
          conjunctions = Collections.singletonList(child);
        }

        // 3. We will extract the literals to introduce in the IN clause.
        //    If the patterns OR-AND-EqOp or OR-EqOp are not matched, we bail out
        for (ExprNodeDesc conjunction: conjunctions) {
          if (!(conjunction instanceof ExprNodeGenericFuncDesc)) {
            return null;
          }

          ExprNodeGenericFuncDesc conjCall = (ExprNodeGenericFuncDesc) conjunction;
          Class<? extends GenericUDF> genericUdfClass = conjCall.getGenericUDF().getClass();
          if(GenericUDFOPEqual.class == genericUdfClass) {
            if (conjCall.getChildren().get(0) instanceof ExprNodeColumnDesc &&
                    conjCall.getChildren().get(1) instanceof ExprNodeConstantDesc) {
              ExprNodeColumnDesc ref = (ExprNodeColumnDesc) conjCall.getChildren().get(0);
              String refString = ref.toString();
              columnConstantsMap.put(refString,
                      new Pair<ExprNodeColumnDesc,ExprNodeConstantDesc>(
                              ref, (ExprNodeConstantDesc) conjCall.getChildren().get(1)));
              if (columnConstantsMap.get(refString).size() != i+1) {
                // If we have not added to this column desc before, we bail out
                return null;
              }
            } else if (conjCall.getChildren().get(1) instanceof ExprNodeColumnDesc &&
                    conjCall.getChildren().get(0) instanceof ExprNodeConstantDesc) {
              ExprNodeColumnDesc ref = (ExprNodeColumnDesc) conjCall.getChildren().get(1);
              String refString = ref.toString();
              columnConstantsMap.put(refString,
                      new Pair<ExprNodeColumnDesc,ExprNodeConstantDesc>(
                              ref, (ExprNodeConstantDesc) conjCall.getChildren().get(0)));
              if (columnConstantsMap.get(refString).size() != i+1) {
                // If we have not added to this column desc before, we bail out
                return null;
              }
            } else {
              // We bail out
              return null;
            }
          } else {
            // We bail out
            return null;
          }
        }
      }

      // 4. We build the new predicate and return it
      ExprNodeDesc newPredicate = null;
      List<ExprNodeDesc> newChildren = new ArrayList<ExprNodeDesc>(children.size());
      // 4.1 Create structs
      List<ExprNodeDesc> columns = new ArrayList<ExprNodeDesc>();
      List<String> names = new ArrayList<String>();
      List<TypeInfo> typeInfos = new ArrayList<TypeInfo>();
      for (int i = 0; i < children.size(); i++) {
        List<ExprNodeDesc> constantFields = new ArrayList<ExprNodeDesc>();

        for (String keyString : columnConstantsMap.keySet()) {
          Pair<ExprNodeColumnDesc, ExprNodeConstantDesc> columnConstant =
                  columnConstantsMap.get(keyString).get(i);
          if (i == 0) {
            columns.add(columnConstant.left);
            names.add(columnConstant.left.getColumn());
            typeInfos.add(columnConstant.left.getTypeInfo());
          }
          constantFields.add(columnConstant.right);
        }

        if (i == 0) {
          ExprNodeDesc columnsRefs;
          if (columns.size() == 1) {
            columnsRefs = columns.get(0);
          } else {
            columnsRefs = new ExprNodeGenericFuncDesc(
                    TypeInfoFactory.getStructTypeInfo(names, typeInfos),
                    FunctionRegistry.getFunctionInfo(STRUCT_UDF).getGenericUDF(),
                    columns);
          }
          newChildren.add(columnsRefs);
        }
        ExprNodeDesc values;
        if (constantFields.size() == 1) {
          values = constantFields.get(0);
        } else {
          values = new ExprNodeGenericFuncDesc(
                  TypeInfoFactory.getStructTypeInfo(names, typeInfos),
                  FunctionRegistry.getFunctionInfo(STRUCT_UDF).getGenericUDF(),
                  constantFields);
        }
        newChildren.add(values);
      }
      newPredicate = new ExprNodeGenericFuncDesc(TypeInfoFactory.booleanTypeInfo,
              FunctionRegistry.getFunctionInfo(IN_UDF).getGenericUDF(), newChildren);

      return newPredicate;
    }
This optimization will take a Filter expression, and if its predicate contains
an OR operator whose children are constant equality expressions, it will try
to generate an IN clause (which is more efficient). If the OR operator contains
AND operator children, the optimization might generate an IN clause that uses
structs.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/PointLookupOptimizer.java