Chapter Parquet menutup dengan satu nama yang belum kita bahas: ORC. Apache ORC (Optimized Row Columnar) adalah format kolom yang lahir dari proyek Apache Hive pada tahun 2013 untuk menjawab kebutuhan khas gudang data Hadoop: file self-describing, terkompresi, dan memiliki indeks bawaan agar query tidak membaca seluruh berkas. Hive, Spark, dan Trino di klaster Hadoop banyak menyimpan tabelnya sebagai ORC. Pada chapter ini kita bedah anatomi file ORC, menulis dan membacanya lewat pustaka pyorc, lalu membuktikan bagaimana statistik min/max membuat query bisa melewati blok data yang tidak relevan.

Apa Itu ORC #

ORC menyimpan data per kolom seperti Parquet, tetapi membawa tiga ciri khas dari ekosistem Hive. Pertama, tipe data dinyatakan lengkap di dalam berkas dengan sintaks struct<kolom:tipe> — id:int dan kasir:string pada skema kita adalah contohnya. Kedua, setiap kolom menyimpan statistik (jumlah nilai, minimum, maksimum) yang bisa dipakai mesin query untuk menyaring data sebelum dibaca. Ketiga, ORC menjadi format resmi tabel transaksional Hive sehingga operasi UPDATE dan DELETE baris didukung penuh di ekosistem tersebut — sesuatu yang tidak dimiliki Parquet. Detail lengkapnya terdokumentasi di dokumentasi resmi ORC .

Anatomi File ORC: Stripe dan Row Index #

File ORC tersusun dari tiga bagian utama berikut:

BagianIsiPeran
Postscriptparameter kompresi dan panjang footertitik masuk pembacaan file
Footerskema tipe, daftar stripe, statistik kolomkatalog isi file
Stripedata baris per kolom + row indexunit baca paralel

Satu stripe secara bawaan berukuran 64 MB pada pyorc dan berisi tiga segmen: index data, row data, dan footer stripe. Index data menyimpan posisi setiap row group — kelompok baris yang diindeks setiap row_index_stride baris (bawaan 10.000, bisa kita perkecil untuk eksperimen). Untuk setiap row group dan setiap kolom, ORC mencatat statistik minimum, maksimum, dan jumlah baris. Statistik inilah fondasi predicate pushdown yang kita uji nanti.

Kita pakai dataset transaksi toko yang sama dengan chapter sebelumnya. Pustaka pyorc menerima skema sebagai string struct, menulis lewat Writer, dan membaca lewat Reader:

python
import pyorc

transaksi = [
    (1, "Budi", "Kopi Robusta", 2, 45000),
    (2, "Siti", "Teh Melati", 3, 15000),
    (3, "Budi", "Gula Aren 500g", 1, 25000),
    (4, "Dewi", "Susu UHT 1L", 2, 18000),
    (5, "Dewi", "Kopi Robusta", 8, 45000),
    (6, "Siti", "Susu UHT 1L", 4, 18000),
]

skema = "struct<id:int,kasir:string,produk:string,qty:int,harga:int>"

with open("transaksi.orc", "wb") as f:
    with pyorc.Writer(f, skema, compression=pyorc.CompressionKind.SNAPPY,
                      row_index_stride=2) as writer:
        writer.writerows(transaksi)

with open("transaksi.orc", "rb") as f:
    reader = pyorc.Reader(f)
    print("schema        :", reader.schema)
    print("jumlah baris  :", len(reader))
    print("jumlah stripe :", reader.num_of_stripes)
    print("kompresi      :", reader.compression.name)
    for baris in reader:
        print(baris)

Output yang Dihasilkan:

text
schema        : struct<id:int,kasir:string,produk:string,qty:int,harga:int>
jumlah baris  : 6
jumlah stripe : 1
kompresi      : SNAPPY
(1, 'Budi', 'Kopi Robusta', 2, 45000)
(2, 'Siti', 'Teh Melati', 3, 15000)
(3, 'Budi', 'Gula Aren 500g', 1, 25000)
(4, 'Dewi', 'Susu UHT 1L', 2, 18000)
(5, 'Dewi', 'Kopi Robusta', 8, 45000)
(6, 'Siti', 'Susu UHT 1L', 4, 18000)

Mari kita telaah baris-baris kode di atas:

  1. Baris 12 (skema = "struct<...>"): mendeklarasikan tipe setiap kolom — int untuk id, qty, harga, dan string untuk kasir, produk. Tipe ini tertanam permanen di footer file, sama seperti Parquet.
  2. Baris 14-17 (with pyorc.Writer(...)): membuka writer dengan kompresi SNAPPY; row_index_stride=2 membuat row group berisi hanya 2 baris agar mekanisme indeks mudah diamati (di produksi biarkan nilai bawaan 10.000).
  3. Baris 17 (writerows(transaksi)): menulis seluruh baris sekaligus; writer menutup stripe dan footer secara rapi saat blok with berakhir.
  4. Baris 19-26 (pyorc.Reader): len(reader) membaca jumlah baris dari metadata footer tanpa memindai data, lalu iterasi for mengembalikan setiap baris sebagai tuple.

Statistik Min/Max untuk Predicate Pushdown #

Sekarang bagian yang membuat ORC (dan Parquet) unggul untuk analitik: predicate pushdown. Kita memberikan syarat qty < 3 kepada Reader. Pembaca membandingkan syarat tersebut dengan statistik min/max setiap row group lalu melewati grup yang mustahil memuat baris cocok:

python
import pyorc
from pyorc.predicates import PredicateColumn

qty = PredicateColumn(pyorc.TypeKind.INT, name="qty")

with open("transaksi.orc", "rb") as f:
    reader = pyorc.Reader(f, predicate=(qty < 3))
    kandidat = list(reader)

print("baris kandidat :", len(kandidat))
hasil = [baris for baris in kandidat if baris[3] < 3]
print("baris cocok    :", len(hasil))
for baris in hasil:
    print(baris)

Output yang Dihasilkan:

text
baris kandidat : 4
baris cocok    : 3
(1, 'Budi', 'Kopi Robusta', 2, 45000)
(3, 'Budi', 'Gula Aren 500g', 1, 25000)
(4, 'Dewi', 'Susu UHT 1L', 2, 18000)

Enam baris file terbagi tiga row group berisi dua baris: grup A (baris 1-2, qty 2 dan 3), grup B (baris 3-4, qty 1 dan 2), dan grup C (baris 5-6, qty 8 dan 4). Statistik grup C memuat minimum qty = 4, sehingga syarat qty < 3 membuat grup C seluruhnya dilewati — dua baris terakhir tidak pernah dibuka. Grup A dan B lolos sebagai kandidat, menghasilkan empat baris; dari situ hanya tiga baris yang benar-benar memenuhi syarat.

ORC vs Parquet #

Kedua format kolom ini mirip secara kemampuan; pilihan sering kali ditentukan ekosistem, bukan performa semata:

AspekORCParquet
Ekosistem asalHive / HadoopHadoop umum, kini lintas platform
Unit baca paralelstriperow group
Indeks bawaanrow index + statistik min/maxstatistik row group dan page
Kompresi bawaanZLIB (pyorc)SNAPPY (pyarrow)
Update barisdidukung Hive (tabel ACID)tidak didukung, file immutable
Sebaran toolHive, Spark, TrinoSpark, DuckDB, BigQuery, Snowflake, dan lainnya

Sebagai gambaran nyata: dataset 6 baris di atas menghasilkan file ORC 1.012 byte versus Parquet 1.572 byte; pada dataset 200.000 baris dengan kompresi zstd yang sama, ORC menghasilkan 1.022.171 byte versus Parquet 1.234.239 byte. ORC sedikit lebih kecil pada kedua pengujian, tetapi selisih ini bergantung pada data, dictionary encoding, dan konfigurasi — angka ini bukan alasan mutlak memilih ORC. Bila tim sudah memakai Hive atau kebutuhan update baris muncul, ORC adalah pilihan alami; di luar itu Parquet menang dari sisi sebaran tool.

Kita sudah melihat dua format kolom milik dunia Hadoop. Chapter berikutnya membahas format biner ber-skema yang lahir dari dunia microservices dan kini merambah pipeline streaming: Protobuf.