@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
        Object... nodeOutputs) throws SemanticException {
      FilterOperator filterOp = (FilterOperator) nd;
      ExprNodeDesc predicate = filterOp.getConf().getPredicate();

      // Generate the list bucketing pruning predicate as 2 separate IN clauses
      // containing the partitioning and non-partitioning columns.
      ExprNodeDesc newPredicate = generateInClauses(predicate);
      if (newPredicate != null) {
        // Replace filter in current FIL with new FIL
        LOG.debug("Generated new predicate with IN clause: {}", newPredicate);
        final List<ExprNodeDesc> subExpr =
                new ArrayList<ExprNodeDesc>(2);
        subExpr.add(predicate);
        subExpr.add(newPredicate);
        ExprNodeGenericFuncDesc newFilterPredicate = new ExprNodeGenericFuncDesc(
                TypeInfoFactory.booleanTypeInfo,
                FunctionRegistry.getFunctionInfo(AND_UDF).getGenericUDF(), subExpr);
        filterOp.getConf().setPredicate(newFilterPredicate);
      }

      return null;
    }
This optimization will take a Filter expression, and if its predicate contains
an IN operator whose children are constant structs or structs containing constant fields,
it will try to generate predicate with IN clauses containing only partition columns.
This predicate is in turn used by the partition pruner to prune the columns that are not
part of the original IN(STRUCT(..)..) predicate.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/PartitionColumnsSeparator.java