3 puan yazan GN⁺ 2023-11-30 | 1 yorum | WhatsApp'ta paylaş
  • jaq, JSON veri işleme aracı jqnun bir klonudur; çoğu durumda jq ile uyumluluğu korurken daha doğru ve öngörülebilir bir uygulama olmayı hedefler
  • Komut satırı programı jaq, jq için bir drop-in replacement olarak kullanılabilir ve Rust kütüphanesi jaq-core, Rust programları içinde jq programlarını derleyip çalıştırabilir
  • jqda bulunmayan YAML, CBOR, TOML ve XML desteği sunar; jaq-core çok iş parçacıklı ortamlarda güvenle kullanılabilir ve JSON ötesinde rastgele veri tiplerini destekler
  • Performans değerlendirmesinde jaq-3.0, 31 benchmarkın 20'sinde en hızlıydı; jq-1.8.1 5'inde, gojq-0.12.18 ise 6'sında en hızlıydı
  • Güvenlik açısından panic önleme, bellek güvenliği ve girdi verisiyle jq filtrelerinin I/O sınırlandırmasını garanti etmeye çalışır; ancak zaman, bellek ve stack gibi kaynak tükenmesi durumlarını ele almaz

jaq neler sunuyor

  • jaq, JSON veri işleme aracı jq için bir klondur; telaffuzu /ʒaːk/ olup Jacques ile aynıdır
  • jqda olmayan veri formatı desteği sunar
    • YAML

    • CBOR

    • TOML

      • XML
      • Ayrı bir manual bulunur ve playground üzerinden denenebilir
      • jaq iki biçimde sunulur
      • Komut satırı programı jaq: jq için drop-in replacement olarak kullanılabilir
      • Kütüphane jaq-core: Rust programları içinde jq programlarını derleyip çalıştırabilir

Tasarım hedefleri

  • Doğruluk

    • jaq, çoğu durumda jq ile uyumluluğu korurken daha doğru ve öngörülebilir bir jq uygulaması olmayı hedefler
  • Performans

    • jaq, başlangıçta jq 1.6nın uzun açılış süresi rahatsız edici olduğu için geliştirildi; bu ortamda açılış süresi yaklaşık 50ms idi
    • Bu açılış süresi özellikle çok sayıda küçük dosya işlenirken belirgin hale gelir
    • jq 1.7 ile açılış süresi büyük ölçüde iyileşti, ancak jaq birçok benchmarkta hâlâ jqdan daha hızlıdır
  • Sadelik

    • jaq, hata olasılığını azaltmak ve katkı sunmayı kolaylaştırmak için basit ve küçük bir uygulamayı hedefler

Kurulum ve derleme

  • Linux, Mac ve Windows için ikili dosyalar releases page üzerinden indirilebilir
  • macOS veya Linux'ta homebrew ile kurulabilir
    • brew install jaq
    • brew install --HEAD jaq
  • Kaynaktan derlemek için Rust toolchain gerekir
  • Depoyu klonladıysanız cargo build --release veya cargo install --locked --path jaq ile derleme ya da kurulum yapılabilir
  • jaq, Rust'ın desteklediği tüm sistemlerde çalışmalıdır; aksi halde issue açılması istenir

Performans değerlendirmesi

  • Performans değerlendirmesi, jaq, jq ve gojq arasında yapılan çeşitli benchmarklardan oluşur
  • empty benchmarkı, null girdiyle empty filtresini n kez çalıştırarak açılış süresini ölçer
  • bf-fib benchmarkı, jq ile yazılmış bir Brainfuck yorumlayıcısında Fibonacci sayıları üreten bir Brainfuck betiğini çalıştırır
  • Benchmark verileri, Linux çalıştıran AMD Ryzen 5 5500U sisteminde üretildi
    • Kullanılan komut: bench.sh target/release/jaq jq-1.8.1 gojq-0.12.17 | tee bench.json
    • Tabloda jaq-3.0, jq-1.8.1, gojq-0.12.18 sonuçları milisaniye cinsinden gösterilir
    • N/A, hata veya 10 saniyeyi aşma anlamına gelir
  • Sonuç özeti
    • jaq-3.0, 20 benchmarkta en hızlıydı
    • jq-1.8.1, 5 benchmarkta en hızlıydı
    • gojq-0.12.18, 6 benchmarkta en hızlıydı
  • gojq, tree-flatten testinde çok daha hızlıdır; çünkü flatten filtresini tanım olarak değil, native olarak uygular

Güvenlik modeli ve sınırlar

  • jaq şunları garanti etmeye çalışır
    • Kaynak tükenmesi vakaları dışında panic oluşmaması
    • Belleğe zarar vermeyen bellek güvenliği
    • jq filtresi çalıştırılmadan önce dosya okunması dışında, girdi verisi ve jq filtresinin I/O işlemi başlatamaması
  • Bu garantilerin bozulduğu durumlar bug kabul edilir ve raporlanmalıdır
  • jaq, hiçbir tür kaynak tükenmesi durumuna karşı önlem almaz
    • Çalışma süresi sınırsız uzayabilir
    • Bellek sınırsız kullanılabilir
    • Stack alanı sınırsız kullanılabilir
  • Örnek olarak, girdi verisi okunurken veya jq filtresi çalıştırılırken stack overflow oluşabilir
    • jaq -nr 'repeat("[")' | jaq
    • jaq -n 'def f: 1+f; f'

Denetim ve testler

  • jaq core, iki ayrı NLnet hibesi kapsamında Radically Open Security tarafından denetlendi
  • İlk ve ikinci güvenlik denetimlerinde orta veya düşük önem derecesine sahip sorunlar bulundu
  • Güvenlik denetimindeki tüm sorunlar giderildi ve jaq-core/fuzz içine jaq için birden fazla fuzzing hedefi eklendi
  • jaq'ın JSON ayrıştırıcısı hifijson da zaten fuzzing hedeflerine sahipti
  • jaq için 500'den fazla testten oluşan bir test paketi bulunur

Kullanıcı örnekleri

  • Bir kullanıcı, jaqın jq desteğini doğrudan uygulamaktan çok daha faydalı olduğunu ve ValT trait üzerinden sağlanan genişletilebilirlik sayesinde kendi tiplerine jq desteğini kolayca ekleyebildiğini söyledi
  • Başka bir kullanıcı, jaq kullanan Rust programının, Python'daki jq PyPI crate'i ve tüm dosya üzerinde tek sorgu çalıştıran Python döngüsü bir kez işi bitirene kadar, tüm dosya üzerinde tüm sorguları üç kez çalıştırabildiğini belirtti
  • wsjq yorumlayıcısı örneğinde, jaq'ın diğer jq uygulamalarından belirgin biçimde daha hızlı olduğu ve doğruluğa verdiği önemin etkileyici bulunduğu ifade edildi
    • İlgili wsjq benchmarkında jaq, jq'dan 5–10 kat, gojq'dan ise 15–196 kat daha hızlıydı
  • certificate transparency log verilerini certstream-server ile işleyen bir kullanıcı, jq pipe işlemede sorun yaşadığını; jaq'a geçtikten sonra daha hızlı açılış süresi sayesinde düşük özellikli bir VM'de bile akışı yakalayabildiğini söyledi

Fon desteği

1 yorum

 
GN⁺ 2023-11-30
Hacker News yorumları
  • jq geliştirmenin 5 yıl durmuş olup ancak yakın zamanda yeniden canlandığı düşünülürse, bilinen hatalar da yeni hatalar da dahil, bu süre boyunca raporların birikmiş olması şaşırtıcı değil
    Artık yeniden hız kazanıp uzun süredir biriken açık işleri yavaş yavaş temizleyecek gibi görünüyor

  • Benzer veya ilham alınmış projeleri, alternatif olmayan projelerle birlikte README'de tanıtma yaklaşımı hoşuma gidiyor
    Bu projenin README'sinde https://github.com/yamafaktory/jql'yi öğrendim; uzun zamandır aradığım araç olduğu için memnunum
    JAQ'yu kötülemek istemem ama JQ tarzı söz dizimi anlaması fazla zor olduğundan jql bana daha uygun geliyor

    • Bu açıdan gron da iyi
      JSON'u anahtar-değer biçimindeki satırlara düzleştirerek grep gibi basit akış işlemleriyle iyi uyumlu hale getiriyor: https://github.com/tomnomnom/gron
    • Güzel bir keşif, denemeyi düşünüyorum
      Ancak gerçekten SQL benzeri bir deneyim bekliyordum. Neden doğrudan SQL'i kopyalayıp "SELECT * FROM $json WHERE x>1" gibi sorgulama imkânı vermediklerini anlamıyorum
      Herkes kod golfü yapar gibi kendi anlaşılması zor sembolik sorgu dilini yaratmak istiyor sanki. Aşırı kısa ama bariz olmayan eski Unix tarzı söz diziminden uzaklaşıp PowerShell yaklaşımına daha yakın olmasını isterdim
    • https://github.com/tidwall/jj de bakmaya değer
    • Bu rahatsızlığa bir ölçüde katılıyorum ama en azından jql çözüm gibi görünmüyor
      |={"b""d"=2, "c"} ifadesi jq'daki select(."b"."d" == 2 or ."c" != null) gibi bir anlama geliyor gibi; jq tarafı daha uzun olsa da daha açık hissettiriyor
      Gerçekte .[] | select(...) gerekir muhtemelen, ama jql'de de benzer bir varsayım olabilir; örneğin eksiksiz olup olmadığından emin olmadığım için sonuç açısından çok fark etmiyor
    • jql'in homoikoniklik (homoiconicity) özelliği epey Lisp'e benziyor
      Kendisine uygulamak ya da “makrolar” kullanmak da mümkün görünüyor
  • jq'nun fikrini seviyorum ama sık kullanmadığım için istediğimi yapmak üzere her seferinde söz dizimini kılavuzdan aramam gerekiyor
    Ne yazık ki jq ile yaptığım işlerin %99'u | jq .

    • Aynı sorunu yaşamıştım
      Ayrı olarak bir yapılandırma dili oluşturmaya başlamıştım; meğer JSON sorguları için de epey iyiymiş: https://docs.ruuda.nl/rcl/rcl_query/
      jq ile çözemediğim ama RCL ile çözebildiğim bir örnek burada: https://fosstodon.org/@ruuda/111120049523534027
    • Aynı sorun yüzünden jq'nun gücünden tam yararlanamıyordum; bu gibi durumlarda Copilot gerçekten yardımcı oluyor
      Gerekli işi ve küçültülmüş bir örnek kaynak JSON'u birlikte verdiğinizde doğru jq betiğini üretiyor
      Karmaşık gereksinimleri tek seferde doğru açıklamaktansa Copilot ile adım adım yineleyerek çözüme yönlendirmek daha kolay ve güvenilir. Yineleme sırasında başlangıçtakinden daha iyi fikirler de akla gelebiliyor
      ChatGPT veya başka araçlar da benzer şekilde çalışır gibi
    • Son zamanlarda gerekli jq söz dizimini ChatGPT ile hızlıca elde ettim: https://chat.openai.com/share/40b68d73-d2dd-412d-867f-9f375e...
  • https://github.com/01mf02/jaq/blob/main/Cargo.lock
    Bağımlılık sayısı epey fazla

    • gojq ile karşılaştırınca gerçekten çok: https://github.com/itchyny/gojq/blob/main/go.mod
    • Rust ekosisteminde böyle durumların genelde nasıl ilerlediğini merak ediyorum
      Bağımlılık çok olunca zamanla birbirleriyle temelden uyumsuz hale gelme riski artıyor gibi görünüyor ve bakım büyük bir iş olacak gibi
      Örneğin 2 yıl sonra da derlenir mi diye düşünüyorum
  • jq çok güçlü bir araç, ama son zamanlarda DuckDB de yaygın kullanılıyor
    Veri bir ölçüde tablo biçimindeyse SQL çok daha doğal bir dil

    • Daha önce Retool’u denemiştim; “Query JSON with SQL” vardı ve oldukça kullanışlıydı: https://docs.retool.com/queries/guides/sql/query-json
      C#’taki LINQ’ya biraz benziyor ama SQL daha standartlaşmış olduğu için daha çok hoşuma gidiyor
      Dil içinde ham koleksiyonları SQL ile sorgulayabilmek harika olurdu; daha da ötesi koleksiyonları şeffaf biçimde Sqlite’a kaydedebilmek daha da iyi olurdu
      Bir veritabanından vb. veri aldıktan sonra döngü ya da stream API ile basit işlem yapan kodları görünce hep eksik hissediyorum. Bu tür kullanımda SQL, Java/Kotlin/Python/JavaScript’ten çok daha üst düzey ve kısa
    • Benzer hissediyorum
      Ham JSON çıktısının tamamını bir sqlite tablosuna kaydediyor, orada sanal sütunlar oluşturuyor, ardından select sonucunu bir shell döngüsünden geçiriyorum
      İç içe döngüler açılıyor; doğru kaydı DB’de kontrol edip yeniden çalıştırabildiğim için hata ayıklanabilirlik çok daha iyi hale geliyor
      Aslında yaptığım şeyin bir DAG olduğunu fark ettim ve her zaman başarıyla işlenen son kayıttan yeniden başlıyorum. Bunu ifade edecek Make benzeri bir araç var mı merak ediyorum
      Make’in SQL hedefi yok; Airflow gibi tam teşekküllü DAG işleyicileri ise shell parçalarını birleştirmek için fazla ağır
    • Doğru. Katı bir şeması olan ilişkisel veri için SQL çok daha iyi
      Yine de SQL’de özyinelemeli sorguları kısa ve öz ifade etmenin bir yolu hâlâ zor bulunuyor
    • Bu kullanım için şahsen textql’yi daha çok seviyorum. Zihinsel modeli daha basit
      https://github.com/dinedal/textql
  • Doğruluk açısından uint64 sayıların kesilmeden gösterilip gösterilemediğini merak ediyorum
    Şu anda jq’da beni en çok rahatsız eden kısım bu

    • Ne yazık ki JSON sayılarına 64 bit kayan nokta olarak bakarsanız, standarda uyulacaksa öyle ele alınmaları gerekir ve tamsayı hassasiyeti 53 bit olur
      Ancak en yeni şartname olan RFC 8259’un yalnızca sayıların metin biçimini belirttiği, anlambilimi belirlemediği yönünde bir düzeltme var
      Pratikte çoğu uygulama JSON’u JavaScript’in bir alt kümesi gibi ele aldığı için bu, sayıların 64 bit kayan nokta olduğu varsayımına yol açıyor
    • Bildiğim kadarıyla jq 1.7’de iyileştirildi: https://github.com/jqlang/jq/releases/tag/jq-1.7
      Ondalık sayı literalleri kullanarak hassasiyeti koruduğu, karşılaştırma işlemlerinin hassasiyete saygı duyduğu ama aritmetik işlemlerin kesilebileceği belirtiliyor
    • jq 1.7 büyük tamsayıları koruyor, ancak üzerlerinde herhangi bir işlem yapılırsa kesiliyorlar
      Şu anda decimal64’e kestiği için biraz kafa karıştırıcı; sonraki sürümde JSON şartnamesinin önerisine uygun olarak binary64(double) biçimine kesecek şekilde düzeltilecek: https://github.com/jqlang/jq/pull/2949
  • jless’e geçtikten sonra geriye bakmadım
    Kullanıcı arayüzü diğerlerinden çok daha ileride

    • Aynı türden değiller
      jq basit bir görüntüleyici değil, bir JSON sorgu dili işleyicisi
  • Rust’ın bir yerlerinde terminal çizgi sanatı kütüphanesi olması sevimli, ama jaq’ı çalıştırınca iTerm’e megabaytlarca escape code döktü ve sonunda iTerm bunu yazıcıya göndermeye çalıştı
    Fazla akıllı davranmış
    echo *json | rush -- jaq -rf ./this-program.jq {} | datamash ... gibi bir bağlamda TTY’ye sanatsal efektler koymaya çalışmanın uygun olmadığını düşünüyorum
    Hatanın nedeni her hâlükârda jaq’ta strftime olmamasıydı

  • İlk izlenimim, güzel hata mesajları olduğu ama halt_error/0 olmadığı yönünde
    halt_error’ı yorum satırına aldıktan sonra jq ve gojq’dan daha yavaştı
    Aynı girdide jq yaklaşık 0,023 saniye, gojq yaklaşık 0,070 saniye, jaq ise yaklaşık 0,103 saniye sürdü
    Kullanılan aoc22-13.jq https://pastebin.com/raw/YiUjEu2n, input.txt ise https://pastebin.com/raw/X0FSyTNf

  • jq yerine yq kullanmaya başladım; önemli bir fark var mı merak ediyorum

    • Hangi yq olduğuna bağlı
      Şahsen https://github.com/mikefarah/yq’yu https://github.com/kislyuk/yq’ya tercih ediyorum
    • jq, yq’dan çok daha sağlam bir araç gibi hissettiriyor
      YAML işlemenin JSON’dan çok daha zor olduğunu anlıyorum, ama yq sürüm 3’ten 4’e geçerken sözdizimini jq’ya daha yakın hale getirmiş olsa da bir şekilde tamamen aynı değil
      Ayrıca yq’da if-then-else yok; bu da kötü tasarlanmış ya da atlanmış gibi görünüyor: https://github.com/mikefarah/yq/issues/95
      YAML işlemek gerektiğinde yq iyi çalışıyor ve yorumları da oldukça iyi ele alıyor, ancak saf JSON işleme için jq daha iyi bir araç