2 poin oleh GN⁺ 2024-10-23 | Belum ada komentar. | Bagikan ke WhatsApp
  • ClickHouse memperkenalkan tipe JSON baru yang menempatkan nilai per path JSON di penyimpanan kolumnar sungguhan, untuk menghindari bottleneck akibat menyimpan dokumen JSON sebagai string lalu mem-parsing-nya setiap kali
  • Inti implementasinya adalah tipe Variant dan Dynamic; meski path JSON yang sama berisi tipe berbeda seperti integer, string, atau array, nilainya tidak dipaksa disatukan ke tipe umum minimum
  • Nilai default max_dynamic_paths adalah 1024 dan max_dynamic_types adalah 32, membatasi jumlah subkolom dan file per tipe untuk mengendalikan peningkatan file descriptor dan biaya merge
  • Cara penyimpanan per path dapat disesuaikan dengan type hint, SKIP, dan SKIP REGEXP, sementara nilai dapat dibaca dengan sintaks subkolom seperti C.a.b
  • Tipe baru ini bertujuan menggantikan Object('json') yang sudah deprecated, dan perbaikan untuk menggunakan path key JSON sebagai primary key atau data-skipping index masih ada di roadmap

Tantangan menyesuaikan JSON dengan penyimpanan kolumnar

  • JSON digunakan sebagai format umum untuk menangani data semi-terstruktur dan tidak terstruktur dalam log, observability, streaming data real-time, penyimpanan aplikasi mobile, dan pipeline machine learning
  • ClickHouse adalah database yang benar-benar berorientasi kolom, menyimpan tabel sebagai kumpulan file data kolom di disk untuk menjalankan kompresi serta filter dan agregasi terv Ditaksikan
  • Untuk memperoleh performa yang sama pada JSON, alih-alih menyimpan dokumen di kolom string lalu mem-parsing-nya belakangan, nilai dari setiap path JSON unik harus disimpan seperti kolom

Empat batasan yang ditangani tipe JSON baru

  • Penyimpanan kolumnar per path

    • Nilai per path JSON juga harus dapat dikompresi seperti kolom biasa, misalnya tipe numerik, serta difilter dan diagregasi secara terv Difaktorkan
  • Tipe yang berubah secara dinamis

    • Path JSON yang sama a dapat berisi tipe berbeda seperti integer, floating point, atau array
    • ClickHouse tidak dapat mengetahuinya terlebih dahulu, dan tipe-tipe tersebut mungkin tidak kompatibel satu sama lain; jika digabungkan ke tipe umum minimum, informasi dapat hilang
  • Mencegah ledakan file kolom

    • Jika file kolom baru dibuat untuk setiap path JSON baru, jumlah file disk akan melonjak pada data dengan banyak key unik
    • File descriptor menggunakan memori, dan makin banyak file yang harus diproses juga memengaruhi performa merge
  • Penyimpanan padat untuk key yang sparse

    • Saat ada banyak key JSON yang unik tetapi sparse, sistem tidak boleh berulang kali menyimpan NULL atau nilai default untuk setiap baris yang tidak memiliki nilai
    • Hanya nilai nyata yang harus disimpan secara padat agar tetap dapat diskalakan untuk analisis skala PB

Tipe Variant: fondasi yang tidak memaksa penyatuan tipe

  • Tipe data Variant adalah fitur independen yang dapat digunakan terpisah dari JSON, dan memungkinkan penyimpanan serta pembacaan nilai dengan tipe data berbeda dalam satu kolom tabel
  • Kolom ClickHouse yang sudah ada memiliki tipe tetap, dan nilai yang dimasukkan harus bertipe tersebut atau dikonversi secara implisit
    • Kolom Nullable menggunakan file mask NULL selain file nilai
    • Array menyimpan ukuran array di file terpisah dan menghitung offset darinya
  • Kolom Variant menyimpan nilai dengan tipe konkret yang sama dalam subkolom per tipe
    • Contoh: semua nilai Int64 disimpan di C.Int64.bin, semua nilai String disimpan di C.String.bin
  • Tipe apa yang digunakan setiap baris dilacak dengan kolom discriminator UInt8
    • Nilai discriminator adalah indeks dalam daftar nama tipe yang diurutkan
    • Discriminator 255 adalah nilai cadangan untuk NULL
    • Karena desain ini, Variant dapat memiliki hingga 255 tipe konkret
  • File data per tipe memakai struktur penyimpanan padat yang hanya berisi baris yang memiliki nilai
    • File per tipe tidak menyimpan nilai NULL
    • Untuk menemukan posisi baris pada file tipe nyata dari baris discriminator, digunakan kolom offset UInt64 di memori
    • Offset ini tidak disimpan di disk dan dapat dibuat seketika dari file kolom discriminator
  • Variant mendukung nesting arbitrer
    • Urutan tipe pada Variant(T1, T2) dan Variant(T2, T1) memiliki makna yang sama
    • Variant dapat dimasukkan lagi di dalam Variant
  • Nilai tipe bersarang tertentu dibaca dengan menambahkan nama tipe seperti subkolom
    • Contoh: C.Int64

Tipe Dynamic: menyimpan tanpa mengetahui daftar tipe terlebih dahulu

  • Tipe Dynamic adalah fitur independen yang diimplementasikan di atas Variant, dan dapat digunakan di luar konteks JSON
  • Dynamic menambahkan dua kemampuan pada Variant
    • Menyimpan nilai dengan tipe arbitrer dalam satu kolom tanpa perlu menentukan daftar tipe terlebih dahulu
    • Membatasi jumlah tipe yang disimpan sebagai file data kolom terpisah
  • Cara penyimpanan internalnya sama seperti Variant, tetapi ditambah file C.dynamic_structure.bin
    • File ini berisi daftar tipe yang disimpan sebagai subkolom dan statistik ukuran file data kolom per tipe
    • Metadata tersebut digunakan untuk pembacaan subkolom dan merge data part
  • Dynamic(max_types=N) membatasi jumlah tipe yang akan disimpan sebagai file terpisah
    • 0 <= N < 255
    • Nilai defaultnya adalah 32
  • Saat batas tercapai, nilai tipe sisanya disimpan dalam satu file kolom seperti C.SharedVariant.bin
    • Tipe file ini adalah String
    • Setiap baris berisi nilai string berstruktur <binary_encoded_data_type><binary_value>
    • Nilai dari berbagai tipe dapat disimpan dalam satu file kolom lalu dibaca kembali
  • Dynamic juga dapat membaca nilai tipe tertentu dengan menggunakan nama tipe sebagai subkolom, seperti Variant
    • Contoh: C.Int64

Deklarasi tipe JSON dan struktur penyimpanan

  • Tipe JSON baru menyimpan objek JSON dengan struktur arbitrer dan memungkinkan setiap nilai JSON dibaca sebagai subkolom berbasis path
  • Deklarasi tipe dapat memiliki parameter dan hint opsional
<column_name> JSON(
    max_dynamic_paths=N,
    max_dynamic_types=M,
    some.path TypeName,
    SKIP path.to.skip,
    SKIP REGEXP 'paths_regexp')
  • max_dynamic_paths
    • Nilai defaultnya adalah 1024
    • Menentukan jumlah path key JSON yang akan disimpan sebagai subkolom terpisah
    • Path yang melewati batas disimpan bersama dalam satu subkolom berstruktur khusus
  • max_dynamic_types
    • Nilai defaultnya adalah 32
    • Rentang nilainya dari 0 sampai 254
    • Menentukan jumlah tipe data pada satu kolom path key JSON yang akan disimpan sebagai file data kolom terpisah
    • Tipe baru yang melewati batas disimpan bersama dalam satu file data kolom khusus
  • some.path TypeName
    • Ini adalah type hint untuk path JSON tertentu
    • Path tersebut selalu disimpan sebagai subkolom dengan tipe yang ditentukan, sehingga memberikan jaminan performa
  • SKIP path.to.skip
    • Melewati path JSON tertentu saat parsing
    • Path tersebut tidak disimpan di kolom JSON
    • Jika path yang ditentukan adalah objek JSON bersarang, seluruh objek bersarang tersebut dilewati
  • SKIP REGEXP 'path_regexp'
    • Melewati path yang cocok dengan regular expression saat parsing JSON
    • Path yang cocok tidak disimpan di kolom JSON

Cara membaca path JSON seperti kolom

  • Setiap nilai leaf path unik dari kolom JSON disimpan di disk dengan salah satu dari dua cara
    • Path yang memiliki type hint disimpan sebagai file data kolom biasa
    • Path dengan tipe yang dapat berubah secara dinamis disimpan sebagai subkolom Dynamic
  • Tipe JSON menggunakan file khusus bernama object_structure
    • Berisi metadata untuk path dinamis
    • Berisi statistik nilai non-null dari setiap path dinamis
    • Digunakan untuk pembacaan subkolom dan merge data part
  • Ledakan file kolom dikendalikan dengan batas dua tahap
    • max_dynamic_types membatasi jumlah tipe dalam satu path key JSON yang disimpan sebagai file terpisah
    • max_dynamic_paths membatasi jumlah path key JSON yang disimpan sebagai subkolom terpisah
  • Path JSON dinamis tambahan yang melewati batas max_dynamic_paths disimpan sebagai shared data
    • Contoh file: C.object_shared_data.size0.bin, C.object_shared_data.paths.bin, C.object_shared_data.values.bin
    • object_shared_data.values bertipe String
    • Setiap entri memiliki struktur <binary_encoded_data_type><binary_value>
  • Untuk shared data, statistik tambahan juga disimpan di object_structure.bin
    • Saat ini statistik nilai non-null disimpan untuk 10000 path pertama di antara path yang tersimpan dalam kolom shared data

Sintaks path JSON dan objek bersarang

  • Tipe JSON dapat membaca nilai leaf dari setiap path sebagai subkolom berbasis nama path
    • Contoh: C.a.b
  • Nilai pada path yang tidak diberi type hint selalu bertipe Dynamic
    • Contoh: tipe C.a.d adalah Dynamic
  • Subkolom subtipe dari tipe Dynamic dibaca dengan sintaks JSON khusus
    • Contoh: C.a.d.:Int64
  • Objek JSON bersarang dapat dibaca seperti subkolom tipe JSON dengan sintaks JSON_column.^some.path
    • Contoh: C.^a
  • Saat ini sintaks dot tidak membaca objek bersarang karena alasan performa
    • Untuk membaca nilai literal per path, struktur penyimpanan saat ini efisien
    • Membaca seluruh sub-objek per path dapat menjadi lambat karena perlu membaca lebih banyak data
    • Untuk mengembalikan objek, diperlukan sintaks .^
    • ClickHouse berencana menyatukan dua sintaks . tersebut

Serialisasi discriminator compact

  • Banyak path JSON dinamis mungkin sebagian besar memiliki tipe nilai yang sama
  • Jika ada banyak path JSON yang unik tetapi sparse, file discriminator untuk setiap path sebagian besar akan berisi 255, yaitu nilai NULL
  • File seperti ini terkompresi dengan baik, tetapi jika nilai semua baris sama, masih ada banyak duplikasi
  • ClickHouse mengimplementasikan format compact untuk serialisasi discriminator
    • Alih-alih menulis semua nilai discriminator UInt8 seperti biasanya, jika semua discriminator pada granule target sama, hanya 3 nilai yang diserialisasi
    • Penanda compact granule format
    • Penanda jumlah nilai dalam granule tersebut
    • Nilai discriminator
  • Optimasi ini dikendalikan oleh pengaturan MergeTree use_compact_variant_discriminators_serialization
    • Nilai defaultnya aktif
    • Dalam beberapa kasus, alih-alih menyimpan 8192 nilai berdasarkan index granularity umum, hanya 3 nilai yang disimpan

Status rilis dan langkah berikutnya

  • Tipe JSON baru dirancang untuk menggantikan tipe Object('json') yang sudah deprecated
  • Implementasinya tersedia sebagai fitur experimental untuk tujuan pengujian dalam rilis ClickHouse 24.08
  • Roadmap JSON mencakup perbaikan untuk menggunakan path key JSON dalam primary key tabel atau data-skipping index
  • Komponen seperti Variant dan Dynamic juga menjadi fondasi dukungan tipe semi-terstruktur tambahan seperti XML dan YAML di luar JSON
  • Pengguna ClickHouse Cloud yang ingin menguji tipe data JSON baru harus menghubungi tim dukungan ClickHouse untuk meminta akses private preview

Belum ada komentar.

Belum ada komentar.