private static List<Type> projectLeafTypes(
    List<Type> types,
    List<FieldNode> nodes) {
    List<Type> res = new ArrayList<>();
    if (nodes.isEmpty()) {
      return res;
    }
    Map<String, FieldNode> fieldMap = new HashMap<>();
    for (FieldNode n : nodes) {
      fieldMap.put(n.getFieldName().toLowerCase(), n);
    }
    for (Type type : types) {
      String tn = type.getName().toLowerCase();

      if (fieldMap.containsKey(tn)) {
        FieldNode f = fieldMap.get(tn);
        if (f.getNodes().isEmpty()) {
          // no child, no need for pruning
          res.add(type);
        } else {
          if (type instanceof GroupType) {
            GroupType groupType = type.asGroupType();
            List<Type> ts = projectLeafTypes(groupType.getFields(), f.getNodes());
            GroupType g = buildProjectedGroupType(groupType, ts);
            if (g != null) {
              res.add(g);
            }
          } else {
            throw new RuntimeException(
              "Primitive type " + f.getFieldName() + "should not " + "doesn't match type" + f
                .toString());
          }
        }
      }
    }
    return res;
  }
Return the columns which contains required nested attribute level
E.g., given struct a:<x:int, y:int> while 'x' is required and 'y' is not, the method will return
a pruned struct for 'a' which only contains the attribute 'x'

@param nestedColPaths the paths for required nested attribute
@return a map from the column to its selected nested column paths, of which the keys are all lower-cased.
ql/src/java/org/apache/hadoop/hive/ql/io/parquet/read/DataWritableReadSupport.java