Jaq, Klon jq yang Berfokus pada Akurasi, Kecepatan, dan Kesederhanaan
(github.com/01mf02)- jaq adalah klon dari alat pemrosesan data JSON
jq, yang bertujuan menjadi implementasi yang lebih dapat diprediksi sambil tetap kompatibel denganjqdalam sebagian besar kasus - Program command-line
jaqdapat digunakan sebagai pengganti drop-in untukjq, dan pustaka Rustjaq-coredapat mengompilasi dan menjalankan program jq di dalam program Rust - Menyediakan dukungan YAML, CBOR, TOML, dan XML yang tidak ada di
jq;jaq-coreaman digunakan di lingkungan multithread dan mendukung tipe data arbitrer di luar JSON - Dalam evaluasi performa,
jaq-3.0menjadi yang tercepat pada 20 dari 31 benchmark, sementarajq-1.8.1tercepat pada 5 benchmark dangojq-0.12.18pada 6 benchmark - Dari sisi keamanan, jaq berupaya menjamin pencegahan panic, memory safety, serta pembatasan I/O untuk data input dan filter jq, tetapi tidak menangani kehabisan resource seperti waktu, memori, dan stack
Hal yang Disediakan jaq
- jaq adalah klon dari alat pemrosesan data JSON
jq, dilafalkan/ʒaːk/seperti Jacques - Memiliki dukungan format data yang tidak ada di
jq-
YAML
-
CBOR
-
TOML
- XML
- Memiliki manual terpisah dan dapat dicoba di playground
- jaq tersedia dalam dua bentuk
- Program command-line
jaq: dapat digunakan sebagai pengganti drop-in untukjq - Pustaka
jaq-core: dapat mengompilasi dan menjalankan program jq di dalam program Rust
-
Tujuan Desain
-
Akurasi
- jaq bertujuan menjadi implementasi jq yang lebih akurat dan dapat diprediksi, sambil tetap mempertahankan kompatibilitas dengan
jqdalam sebagian besar kasus
- jaq bertujuan menjadi implementasi jq yang lebih akurat dan dapat diprediksi, sambil tetap mempertahankan kompatibilitas dengan
-
Performa
- jaq awalnya dibuat karena waktu startup
jq 1.6yang panjang terasa merepotkan; di lingkungan tersebut, waktu startup sekitar 50 ms - Waktu startup ini sangat terasa saat memproses banyak file kecil
- Waktu startup sudah jauh membaik di
jq 1.7, tetapi jaq masih lebih cepat daripadajqdalam berbagai benchmark
- jaq awalnya dibuat karena waktu startup
-
Kesederhanaan
- jaq mengarah pada implementasi yang sederhana dan kecil untuk mengurangi kemungkinan bug serta memudahkan kontribusi
Instalasi dan Build
- Binary untuk Linux, Mac, dan Windows tersedia di releases page
- Di macOS atau Linux, jaq dapat diinstal dengan homebrew
brew install jaqbrew install --HEAD jaq
- Untuk build dari source, diperlukan toolchain Rust
cargo install --locked jaqcargo install --locked --git https://github.com/01mf02/jaq
- Jika sudah mengkloning repository, jaq dapat di-build atau diinstal dengan
cargo build --releaseataucargo install --locked --path jaq - jaq seharusnya berjalan di semua sistem yang didukung Rust; jika tidak, pengguna diminta untuk membuka issue
Evaluasi Performa
- Evaluasi performa terdiri dari beberapa benchmark yang membandingkan jaq, jq, dan gojq
- Benchmark
emptymengukur waktu startup dengan menjalankan filteremptysebanyaknkali pada input null - Benchmark
bf-fibmenjalankan skrip Brainfuck yang menghasilkan bilangan Fibonacci menggunakan interpreter Brainfuck yang ditulis dalam jq - Data benchmark dibuat di sistem Linux dengan AMD Ryzen 5 5500U
- Perintah yang digunakan adalah
bench.sh target/release/jaq jq-1.8.1 gojq-0.12.17 | tee bench.json - Tabel menampilkan hasil
jaq-3.0,jq-1.8.1, dangojq-0.12.18dalam satuan milidetik N/Aberarti terjadi error atau melebihi 10 detik
- Perintah yang digunakan adalah
- Ringkasan hasil
jaq-3.0menjadi yang tercepat pada 20 benchmarkjq-1.8.1menjadi yang tercepat pada 5 benchmarkgojq-0.12.18menjadi yang tercepat pada 6 benchmark
gojqjauh lebih cepat padatree-flattenkarena mengimplementasikan filterflattensecara native, bukan sebagai definisi
Model Keamanan dan Batasan
- jaq berupaya menjamin hal-hal berikut
- Tidak terjadi panic, kecuali dalam kasus kehabisan resource
- Memory safety yang tidak merusak memori
- Kecuali pembacaan file sebelum menjalankan filter jq, data input dan filter jq tidak dapat memulai operasi I/O
- Jika jaminan ini dilanggar, hal tersebut dianggap sebagai bug dan layak dilaporkan
- jaq tidak menangani kehabisan resource dalam bentuk apa pun
- Waktu eksekusi dapat menjadi panjang tanpa batas
- Memori dapat digunakan tanpa batas
- Ruang stack dapat digunakan tanpa batas
- Sebagai contoh, stack overflow dapat terjadi saat membaca data input atau menjalankan filter jq
jaq -nr 'repeat("[")' | jaqjaq -n 'def f: 1+f; f'
Audit dan Pengujian
- jaq core diaudit oleh Radically Open Security sebagai bagian dari dua grant NLnet
- Audit keamanan pertama dan kedua menemukan issue dengan tingkat keparahan sedang atau rendah
- Semua issue dari audit keamanan telah ditangani, dan beberapa target fuzzing untuk jaq ditambahkan ke
jaq-core/fuzz - Parser JSON jaq, hifijson, juga sudah memiliki target fuzzing
- jaq memiliki suite pengujian yang terdiri dari lebih dari 500 pengujian
Kasus Pengguna
- Seorang pengguna menilai
jaqsangat membantu dibanding mengimplementasikan dukunganjqsendiri, dan berkat ekstensibilitas melalui traitValT, ia dapat dengan mudah menambahkan dukungan jq untuk tipe miliknya sendiri - Pengguna lain menyatakan bahwa program Rust yang memakai jaq dapat menjalankan semua query terhadap seluruh file tiga kali, sementara crate PyPI
jquntuk Python dan loop Python baru menjalankan satu query terhadap seluruh file - Dalam kasus interpreter
wsjq, jaq dinilai jauh lebih cepat daripada implementasi jq lain, dan penekanannya pada akurasi dianggap mengesankan- Pada benchmark
wsjqtersebut, jaq 5–10 kali lebih cepat daripada jq dan 15–196 kali lebih cepat daripada gojq
- Pada benchmark
- Pengguna yang memproses data certificate transparency log dengan
certstream-servermengalami masalah pada pemrosesan pipelinejq, lalu setelah beralih ke jaq, dapat mengejar laju data bahkan di VM berspesifikasi rendah berkat waktu startup yang lebih cepat
Pendanaan
- Proyek jaq didukung melalui dana NGI0 Entrust dan NGI0 Commons yang didirikan oleh NLnet
- Dukungan finansial disediakan oleh program Next Generation Internet dari European Commission
- Pendanaan tambahan disediakan oleh Swiss State Secretariat for Education, Research and Innovation
1 komentar
Komentar Hacker News
Mengingat pengembangan jq sempat berhenti selama 5 tahun lalu baru belakangan hidup lagi, tidak aneh kalau laporan bug—baik bug lama yang sudah dikenal maupun bug baru—menumpuk selama itu
Sekarang sepertinya mereka akan mulai mendapatkan kembali kecepatannya dan perlahan membereskan daftar masalah yang belum terselesaikan yang sudah lama menumpuk
Saya suka pendekatan README yang juga memperkenalkan proyek-proyek serupa atau yang terinspirasi olehnya, bukan hanya alternatif pengganti
Dari README proyek ini saya jadi tahu tentang https://github.com/yamafaktory/jql, dan saya berterima kasih karena ini alat yang sudah lama saya cari
Bukan bermaksud meremehkan JAQ, tapi sintaks bergaya JQ terlalu sulit dipahami, jadi jql lebih cocok untuk saya
Ia meratakan JSON menjadi baris-baris berformat key-value sehingga cocok untuk pekerjaan stream sederhana seperti
grep: https://github.com/tomnomnom/gronTapi saya sebenarnya mengharapkan pengalaman yang benar-benar mirip SQL. Saya tidak paham kenapa tidak sekalian meniru SQL saja agar bisa melakukan kueri seperti
"SELECT * FROM $json WHERE x>1"Rasanya semua orang ingin membuat bahasa kueri simbolik mereka sendiri yang sulit dipahami, seolah sedang code golf. Saya berharap kita bisa meninggalkan sintaks Unix lama yang sangat ringkas tetapi tidak intuitif, dan bergerak lebih dekat ke gaya PowerShell
|={"b""d"=2, "c"}tampaknya bermakna sepertiselect(."b"."d" == 2 or ."c" != null)di jq, dan walaupun versi jq lebih panjang, rasanya lebih jelasDalam praktiknya mungkin perlu
.[] | select(...), tetapi jql mungkin juga punya asumsi serupa, dan saya tidak yakin contohnya lengkap, jadi itu tidak banyak memengaruhi kesimpulannyaSepertinya mungkin juga untuk diterapkan ke dirinya sendiri atau menggunakan semacam “macro”
Saya suka ide jq, tetapi karena tidak sering memakainya, setiap kali ingin melakukan sesuatu saya harus mencari sintaksnya di manual
Sayangnya, 99% hal yang saya lakukan dengan jq hanyalah
| jq .Secara terpisah saya mulai membuat bahasa konfigurasi, lalu ternyata cukup bagus juga untuk kueri JSON: https://docs.ruuda.nl/rcl/rcl_query/
Contoh yang tidak bisa saya selesaikan dengan jq tetapi bisa dengan RCL ada di sini: https://fosstodon.org/@ruuda/111120049523534027
Jika Anda memberikan tugas yang dibutuhkan bersama sampel JSON sumber yang sudah diperkecil, ia akan membuatkan skrip jq yang benar
Untuk kebutuhan yang kompleks, sering kali lebih mudah dan lebih andal mengarahkan Copilot sedikit demi sedikit lewat iterasi daripada menjelaskan semuanya dengan tepat sekaligus. Selama proses iterasi itu, kadang muncul juga ide yang lebih baik daripada gagasan awal
Mungkin ChatGPT atau alat lain juga bekerja dengan cara serupa
https://github.com/01mf02/jaq/blob/main/Cargo.lock
Dependensinya cukup banyak
Kalau dependensinya banyak, seiring waktu tampaknya risiko ketidakcocokan mendasar antar dependensi juga makin besar, dan pemeliharaannya sepertinya akan menjadi pekerjaan besar
Misalnya, apakah dua tahun lagi masih akan bisa dikompilasi dengan baik
jq adalah alat yang sangat kuat, tetapi belakangan ini DuckDB juga banyak digunakan
Jika data sampai batas tertentu berbentuk tabel, SQL adalah bahasa yang jauh lebih alami
Agak mirip dengan LINQ di C#, tetapi saya lebih menyukainya karena SQL lebih terstandarisasi
Akan sangat bagus jika di dalam bahasa pemrograman kita bisa melakukan kueri terhadap koleksi primitif dengan SQL, dan lebih baik lagi jika koleksi itu bisa disimpan secara transparan ke Sqlite
Setiap kali melihat kode yang setelah mengambil data dari database lalu hanya diproses sederhana dengan loop atau stream API, rasanya selalu sayang. Untuk kegunaan seperti ini, SQL jauh lebih tingkat tinggi dan ringkas dibanding Java/Kotlin/Python/JavaScript
Saya menyimpan seluruh output JSON asli ke dalam tabel sqlite, lalu membuat kolom virtual di sana dan menjalankan hasil
selectdalam loop shellNested loop jadi terurai, dan karena saya bisa memeriksa serta menjalankan ulang record yang tepat di DB, kemungkinan untuk debugging jadi jauh lebih baik
Saya sadar bahwa yang saya buat adalah DAG, dan saya selalu melanjutkan dari record terakhir yang berhasil diproses. Saya penasaran apakah ada alat mirip
Makeuntuk mengekspresikan iniMake tidak punya target SQL, dan pemroses DAG penuh seperti Airflow terlalu berat untuk sekadar merangkai potongan shell
Meski begitu, cara mengekspresikan kueri rekursif secara ringkas di SQL masih sulit didapat
https://github.com/dinedal/textql
Dari sudut pandang akurasi, saya penasaran apakah angka uint64 bisa ditampilkan tanpa terpotong
Ini bagian yang paling mengganggu dari jq saat ini
Namun, spesifikasi terbaru RFC 8259 mengoreksi hal ini dengan menyatakan bahwa ia hanya menetapkan bentuk teks angka dan tidak menentukan semantiknya
Dalam praktiknya, kebanyakan implementasi memperlakukan JSON sebagai subset JavaScript, sehingga muncul asumsi bahwa angkanya adalah floating-point 64-bit
Tertulis bahwa ia memakai literal angka desimal untuk mempertahankan presisi, dan operasi perbandingan menghormati presisi, tetapi operasi aritmetika bisa tetap terpotong
Saat ini pemotongannya ke decimal64 agak membingungkan, tetapi di rilis berikutnya rencananya akan diperbaiki agar memotong ke binary64(double) sesuai usulan spesifikasi JSON: https://github.com/jqlang/jq/pull/2949
Sejak beralih ke jless, saya tidak pernah menoleh ke belakang
Antarmuka penggunanya jauh melampaui yang lain
jq bukan sekadar viewer, melainkan pemroses bahasa kueri JSON
Lucu memang bahwa ada pustaka line art terminal di suatu tempat dalam ekosistem Rust, tetapi ketika saya mencoba menjalankan jaq, ia malah membanjiri iTerm dengan escape code hingga ukuran megabyte dan akhirnya iTerm mencoba mencetaknya ke printer
Terlalu pintar untuk kebaikannya sendiri
Dalam konteks seperti
echo *json | rush -- jaq -rf ./this-program.jq {} | datamash ..., menurut saya tidak tepat jika mencoba menambahkan efek artistik ke TTYBagaimanapun juga, penyebab errornya adalah
jaqtidak memilikistrftimeKesan pertama saya adalah ia punya pesan error yang bagus, tetapi tidak punya
halt_error/0Setelah saya mengomentari
halt_error, hasilnya lebih lambat daripada jq dan gojqPada input yang sama,
jqmemerlukan sekitar 0,023 detik,gojqsekitar 0,070 detik, danjaqsekitar 0,103 detikaoc22-13.jqyang dipakai ada di https://pastebin.com/raw/YiUjEu2n daninput.txtada di https://pastebin.com/raw/X0FSyTNfSaya mulai memakai yq sebagai pengganti jq, dan penasaran apakah ada perbedaan penting
Secara pribadi saya lebih memilih https://github.com/mikefarah/yq daripada https://github.com/kislyuk/yq
Saya paham bahwa memproses YAML jauh lebih sulit daripada JSON, tetapi yq mengubah sintaksnya dari versi 3 ke 4 agar lebih mirip jq, namun entah kenapa tetap tidak sepenuhnya sama
Selain itu, yq tidak punya if-then-else, sehingga terkesan seperti desain yang kurang baik atau ada yang terlewat: https://github.com/mikefarah/yq/issues/95
Saat perlu memproses YAML, yq bekerja dengan baik dan juga cukup bagus dalam menangani komentar, tetapi untuk pemrosesan JSON murni, jq adalah alat yang lebih baik