¿Cómo vincula un archivo de ORC columnStatistics con el nombre de la columna definido en el esquema (typedescription) usando java?

    Reader reader = OrcFile.createReader(ignored);
    TypeDescription schema = reader.getSchema();
    ColumnStatistics[] stats = reader.getStatistics();

Las estadísticas de la columna contienen estadísticas para todos los tipos de columnas en una matriz plana. El esquema, sin embargo, es un árbol de esquemas. ¿Las estadísticas de la columna son un traidor de árbol (profundidad primero?) Del esquema?

Intenté usar orc-statistics, pero eso solo emite la ID de la columna.

0
Joe 14 jul. 2019 a las 23:46

1 respuesta

La mejor respuesta

Resulta que las estadísticas de archivos coinciden con un Traversal de esquema DFS. El recorrido incluye esquemas intermedios que no tienen datos como la estructura y la lista. Además, el recorrido incluye el esquema general como el primer nodo. Esto se explica en los documentos para Especificación de ORC V1 :

El árbol de tipo se aplana en una lista a través de un recorrido previo a pedido, donde se asigna cada tipo a la siguiente ID. Claramente, la raíz del árbol de tipo siempre es ID de tipo 0. Los tipos compuestos tienen un campo llamado subtipos que contiene la lista de ID de tipo de sus hijos.

El código completo para obtener una lista aplanada de nombres de esquema de un ORC TypeDescription:

final class OrcSchemas {
  private OrcSchemas() {}

  /**
   * Returns all schema names in a depth-first traversal of schema.
   *
   * <p>The given schema is represented as '<ROOT>'. Intermediate, unnamed schemas like
   * StructColumnVector and ListColumnVector are represented using their category, like:
   * 'parent::<STRUCT>::field'.
   *
   * <p>This method is useful because some Orc file methods like statistics return all column stats
   * in a single flat array. The single flat array is a depth-first traversal of all columns in a
   * schema, including intermediate columns like structs and lists.
   */
  static ImmutableList<String> flattenNames(TypeDescription schema) {
    if (schema.getChildren().isEmpty()) {
      return ImmutableList.of();
    }
    ArrayList<String> names = Lists.newArrayListWithExpectedSize(schema.getChildren().size());
    names.add("<ROOT>");
    mutateAddNamesDfs("", schema, names);
    return ImmutableList.copyOf(names);
  }

  private static void mutateAddNamesDfs(
      String parentName, TypeDescription schema, List<String> dfsNames) {
    String separator = "::";
    ImmutableList<String> schemaNames = getFieldNames(parentName, schema);
    ImmutableList<TypeDescription> children = getChildren(schema);
    for (int i = 0; i < children.size(); i++) {
      String name = schemaNames.get(i);
      dfsNames.add(name);
      TypeDescription childSchema = schema.getChildren().get(i);
      mutateAddNamesDfs(name + separator, childSchema, dfsNames);
    }
  }

  private static ImmutableList<TypeDescription> getChildren(TypeDescription schema) {
    return Optional.ofNullable(schema.getChildren())
        .map(ImmutableList::copyOf)
        .orElse(ImmutableList.of());
  }

  private static ImmutableList<String> getFieldNames(String parentName, TypeDescription schema) {
    final List<String> names;
    try {
      // For some reason, getFieldNames doesn't handle null.
      names = schema.getFieldNames();
    } catch (NullPointerException e) {
      // If there's no children, there's definitely no field names.
      if (schema.getChildren() == null) {
        return ImmutableList.of();
      }
      // There are children, so use the category since there's no names. This occurs with
      // structs and lists.
      return schema.getChildren().stream()
          .map(child -> parentName + "<" + child.getCategory() + ">")
          .collect(toImmutableList());
    }
    return names.stream().map(n -> parentName + n).collect(toImmutableList());
  }
}
0
Joe 16 jul. 2019 a las 04:41