Apache ORC Documentation

repository·main·Indexed 20 days ago

https://github.com/apache/orc

A high-performance, type-aware columnar file format optimized for large-scale Hadoop workloads. It features efficient storage, fast read access via predicate pushdown and indexing, and support for complex Hive types. The project provides both Java and C++ libraries, with C++ supporting AVX512 SIMD optimizations.

Tokens
56.6K
Snippets
150
Records
230
Agent score
73%

What's inside Apache ORC

  1. What is Apache ORC?

    main

    Apache ORC (Optimized Row Columnar) is a self-describing, type-aware columnar file format designed for Hadoop workloads. It is optimized for large streaming reads and supports predicate pushdown, allowing readers to use internal indexes to quickly find required rows or stripes.

    Key features:

    • Columnar Storage: Enables reading, decompressing, and processing only the specific columns required for a query.
    • Type Awareness: The writer automatically selects the most appropriate encoding for each data type.
    • Complex Type Support: Supports the complete set of Hive types, including structs, lists, maps, and unions.
    • Indexing: Built-in indexes allow for efficient row-level searches (narrowing down to sets of 10,000 rows).
  2. Summary of ORC 2.1.0 Key Changes

    main

    ORC 2.1.0 includes several significant updates:

    C++ Features

    • Async Prefetch: Support for async prefetch in the Orc reader.
    • Schema Evolution: Expanded support for evolving types (decimal, timestamp, string, numeric).
    • Performance: Improved writing performance for encoded string columns.

    Java & Build

    • Hadoop Upgrade: Upgraded to Hadoop 3.4.1.
    • Dependency Updates: Significant bumps to guava, slf4j, zstd-jni, and protobuf-java.
    • Tooling: Added merge command documentation for Java tools.
  3. Integration of Apache ORC with Big Data Ecosystems

    main

    Apache ORC is widely adopted across the Big Data ecosystem, providing high-performance storage and retrieval for various engines. Key integrations include:

    • Apache Hadoop: Supports reading and writing from MapReduce. Since ORC 1.1.0, OrcStruct implements WritableComparable, allowing serialization through the MapReduce shuffle without requiring Hive's execution JAR.
    • Apache Spark: Supports reading and writing ORC files with column projection and predicate pushdown.
    • Apache Flink: Supports the ORC format via the Table API for reading and writing.
    • Apache Hive: The primary use case for ORC, leveraging its strong type system, compression, column projection, predicate pushdown, and vectorization.
    • Apache Impala: Reads ORC Hive tables by leveraging the ORC C++ library.
    • Apache Iceberg: Supports the ORC specification for use in ORC-backed tables.
    • Apache Druid: Uses an ORC extension to ingest and understand the format.
    • Apache Arrow: Supports reading and writing the ORC file format.
    • Trino (formerly Presto SQL): Integrated into the SQL engine for high-speed data processing.
    • EEL (Scala BigData API): Provides an in-process low-level API for ETL-style applications, supporting ORC predicate and projection pushdowns and complex type conversions (maps, lists, nested structs).
  4. Choosing between timestamp and timestamp with local time zone

    main

    ORC provides two distinct timestamp types. The choice depends on whether you need the time to be relative to the reader's location or a fixed point in time.

    • timestamp: Represents a date and time without a time zone. The value remains constant regardless of the reader's time zone (e.g., 10:00 remains 10:00 in both Los Angeles and New York).
    • timestamp with local time zone: Represents a fixed instant in time. The displayed value changes based on the reader's time zone to reflect that specific instant.

    Recommendation: Unless your application uses UTC consistently, timestamp with local time zone is strongly preferred for most use cases to ensure events are correctly interpreted as specific points in time.

  5. Supported ORC scalar and compound types

    main

    ORC files are self-describing and contain all type and encoding information required to interpret the data without external metadata like the Hive Metastore. ORC supports a variety of scalar and compound types, and all types (including compound types) can accept null values.

    Scalar Types

    • Integer: boolean (1 bit), tinyint (8 bit), smallint (16 bit), int (32 bit), bigint (64 bit)
    • Floating point: float, double
    • String types: string, char, varchar
    • Binary blobs: binary
    • Decimal: decimal
    • Date/time: timestamp, timestamp with local time zone, date

    Compound Types

    Compound types use child columns to store sub-elements:

    • struct: Contains one child column for each field.
    • list: Contains a single child column for the element values.
    • map: Contains two child columns.
    • union: Contains one child column for each of the variants.
  6. Understand VectorizedRowBatch in Core Java

    main

    The Core ORC API uses VectorizedRowBatch to pass data efficiently. A VectorizedRowBatch contains data for 1024 rows, optimized for speed by allowing direct field access. It consists of an array of ColumnVector objects (cols) and an integer size representing the number of rows in the batch.

    To work with vectorized data, you must interact with the cols array and respect the size property to avoid accessing uninitialized rows.

    package org.apache.hadoop.hive.ql.exec.vector;
    
    public class VectorizedRowBatch {
      public ColumnVector[] cols;
      public int size;
      ...
    }
  7. Integer Run Length Encoding (RLEv2) sub-encodings

    main

    ORC uses RLEv2 for integer compression, which selects one of four sub-encodings based on the data pattern to optimize compression and expansion speed:

    • Short Repeat: For short sequences of repeated values. Minimizes header overhead.
    • Direct: For random sequences with a relatively constant bit width. Uses fixed-width big endian encoding.
    • Patched Base: For sequences with highly variable bit widths. It uses a base value and a 95th percentile bit width, applying 'patches' for the remaining 5% of values.
    • Delta: For monotonically increasing or decreasing sequences. Encodes the first value and then the deltas between subsequent values.
  8. Understand ORC Stripes and encryption IDs

    main

    The Body is divided into Stripes. Each stripe contains:

    • Indexes: For rows within the stripe.
    • Data: The actual column data.
    • Stripe Footer: Metadata for the stripe.

    Encryption in Stripes: For files using column encryption, the encryptStripeId and encryptedLocalKeys are set on the first stripe. Subsequent stripes use encryptStripeId + 1 and the same keys. If you are building a tool that reorders or partially merges stripes, you must ensure these IDs are updated correctly to maintain decryption capabilities.

    message StripeInformation {
     // the start of the stripe within the file
     optional uint64 offset = 1;
     // the length of the indexes in bytes
     optional uint64 indexLength = 2;
     // the length of the data in bytes
     optional uint64 dataLength = 3;
     // the length of the footer in bytes
     optional uint64 footerLength = 4;
     // the number of rows in the stripe
     optional uint64 numberOfRows = 5;
     // If this is present, the reader should use this value for the encryption
     // stripe id for setting the encryption IV. Otherwise, the reader should
     // use one larger than the previous stripe's encryptStripeId.
     optional uint64 encryptStripeId = 6;
     // For each encryption variant, the new encrypted local key to use until we
     // find a replacement.
     repeated bytes encryptedLocalKeys = 7;
    }
  9. Understanding Row Index Positions

    main

    To record positions in the RowIndex, the method depends on whether the stream is compressed:

    • Uncompressed streams: The position is the byte offset of the RLE run's start location, followed by the number of values that need to be consumed from the run.
    • Compressed streams: The position consists of the start of the compression chunk in the stream, the number of decompressed bytes that need to be consumed, and finally the number of values consumed in the RLE.
  10. How ORC compound types structure columns

    main

    ORC files represent data as logically sequenced objects. While Hive typically uses a struct as the root object type to represent top-level columns, this is not a requirement of the ORC format.

    Compound types create a tree structure of child columns. For example, a map will always have two child columns, and a union will have one child column for every possible variant.

    Example schema structure:

    create table Foobar (
     myInt int,
     myMap map<string, struct<myString : string, myDouble: double>>,
     myTime timestamp
    );

    In this example, the myMap column would branch into child columns for the map keys and values, and the value column would further branch into child columns for the struct fields (myString and myDouble).

  11. Understand Compression Chunking

    main

    When using generic compression codecs (like zlib or snappy), ORC writes data in independent chunks to allow readers to skip over compressed bytes without decompressing the entire stream.

    Chunk Structure:

    • Each chunk has a 3-byte header.
    • The header contains a little-endian value: (compressedLength * 2 + isOriginal).
    • If the compressed data is larger than the original, the isOriginal flag is set and the original uncompressed data is stored instead.
    • The default chunk size is 256K, though writers can adjust this. Larger chunks improve compression ratios but increase memory requirements.
    • The chunk size is recorded in the Postscript so readers can allocate appropriate buffers.
  12. Understand Data Masks in ORC

    main

    ORC supports static data masking, where user data is masked before the unencrypted variant is written to the file. This masking is purely informational for readers.

    Standard masks include:

    • nullify: All values become null (default).
    • redact: Replaces characters with constants (e.g., X or 9).
    • sha256: Replaces a string with its SHA-256 hash.

    Constraints:

    • Masks cannot change the data type of a column, only the values.
    • Users may define custom masks.