- JSON belgelerinde yol tabanlı gezinme yapan bir Rust CLI aracı ve mevcut
jq, jmespath, jsonpath-rust, jql araçlarından arama hızı daha yüksek
- Sorguları düzenli dil olarak ifade edip DFA'ya derliyor ve JSON ağacını tek geçişte dolaşan yapısıyla O(n) sürede işliyor
- zero-copy parsing destekleyen
serde_json_borrow kullanarak bellek ayırmayı en aza indiriyor ve ripgrep'in performans felsefesinden ilham alarak tasarlanmış
- Benchmark sonuçlarına göre büyük JSON'larda bile uçtan uca performansı en iyi ve arama odaklı basit bir sorgu dili sunuyor
- MIT lisansı ile yayımlanmış; DFA tabanlı sorgu motoru bir Rust kütüphanesi olarak yeniden kullanılabiliyor
jsongrep'e genel bakış
- jsongrep, JSON belgelerinde yol tabanlı değer aramak için kullanılan Rust tabanlı bir CLI aracı ve
jq, jmespath, jsonpath-rust, jql'den daha hızlı olmayı hedefliyor
- JSON belgesini bir ağaç olarak ele alıyor; yol (path) ifadelerini düzenli dil (regular language) olarak tanımlayıp DFA'ya (Deterministic Finite Automaton) derledikten sonra tek geçişte arama yapıyor
- Sorgu dili basit ve arama odaklı tasarlanmış; dönüştürme veya hesaplama özellikleri yok
serde_json_borrow ile zero-copy parsing yaparak bellek ayırmayı en aza indiriyor
- Geliştirilirken
ripgrep'in tasarım felsefesi ve performans yaklaşımı örnek alınmış
jsongrep kullanım örnekleri
jg komutu sorgu ve JSON girdisi alır; yolu sorguyla eşleşen tüm değerleri çıktılar
- Nokta gösterimi (dot path) ile iç içe alanlara erişim
jg 'roommates[0].name' → "Alice"
- Wildcard (
*, [*]) ile tüm anahtarları veya indeksleri eşleştirme
- Alternation (
|) ile birden fazla yol arasından birini seçme
- Özyinelemeli arama (
(* | [*])*) ile herhangi bir derinlikte alan arama
- Optional (
?) ile 0 veya 1 kez eşleşme desteği
-F seçeneğiyle belirli alan adlarını hızlıca arama
- Pipe (
| less, | sort) kullanıldığında yol çıktısını otomatik olarak gizler; --with-path ile zorla gösterilebilir
jsongrep'in temel kavramları
- JSON bir ağaç yapısıdır; nesne anahtarları ve dizi indeksleri kenar (edge) görevi görür
- Sorgu, kökten belirli bir düğüme kadar olan yol kümelerini tanımlar
- Sorgu dili düzenli dil olarak tasarlandığı için DFA'ya dönüştürülebilir
- DFA girdiyi yalnızca bir kez okur ve backtracking olmadan O(n) sürede arama yapar
- Mevcut araçlar (
jq, jmespath vb.) sorguları yorumlayarak özyinelemeli biçimde arama yaparken, jsongrep önceden derlenmiş DFA ile tek geçişte arama yapar
DFA tabanlı sorgu motorunun yapısı
- İş hattı 5 aşamadan oluşur
serde_json_borrow ile JSON'u ağaç olarak parse etme
- Sorguyu AST'ye parse etme
- Glushkov algoritmasıyla NFA oluşturma
- Subset Construction ile DFA'ya dönüştürme
- DFA geçişlerini izleyerek JSON ağacını tek DFS ile dolaşma
-
Sorgu parse etme
- PEG grameri (
pest kütüphanesi kullanılıyor) ile sorguyu Query AST'sine dönüştürür
- Başlıca sözdizimi öğeleri:
Field, Index, Range, FieldWildcard, ArrayWildcard, Optional, KleeneStar, Disjunction, Sequence
- Örnek:
roommates[*].name → Sequence(Field("roommates"), ArrayWildcard, Field("name"))
-
JSON ağaç modeli
- Nesne anahtarları ve dizi indeksleri kenar, değerler ise düğümdür
- Örneğin
roommates[*].name, roommates → [0] → name yolunu dolaşır
-
NFA oluşturma (Glushkov algoritması)
- ε-geçişi olmayan bir NFA oluşturur
- Aşamalar
- Sorgu sembollerine konum numarası verme
- First/Last/Follows kümelerini hesaplama
- Her konum arasındaki geçişleri kurma
- Örnek sorgu
roommates[*].name için NFA, 4 durumdan oluşan basit doğrusal bir yapıdır
-
DFA'ya dönüştürme (Subset Construction)
- NFA durum kümeleri temel alınarak deterministik bir DFA oluşturulur
- Her durum, bir NFA durum kümesine karşılık gelir
- Gereksiz anahtarları verimli biçimde atlamak için
Other sembolü eklenir
- Basit sorgular NFA ile aynı yapıya sahip bir DFA'ya dönüşür
-
DFS tabanlı arama
- Kökten başlayıp her kenar boyunca DFA geçişi yapılır
- Geçiş yoksa ilgili alt ağaç budanır (prune)
- DFA durumu accepting ise yol ve değer kaydedilir
- Her düğüm en fazla bir kez ziyaret edilir; toplam arama O(n) olur
serde_json_borrow sayesinde dizeler kopyalanmadan özgün buffer referans alınır
Benchmark metodolojisi
- Criterion.rs ile istatistik tabanlı benchmark yapıldı
-
Veri kümeleri
simple.json (106B), kubernetes-definitions.json (~992KB), kestra-0.19.0.json (~7.6MB), citylots.json (~190MB)
-
Karşılaştırılan araçlar
jsongrep, jsonpath-rust, jmespath, jaq, jql
-
Benchmark grupları
document_parse: JSON parse hızı
query_compile: sorgu derleme süresi
query_search: yalnızca arama
end_to_end: tüm iş hattı
-
Adalet için dikkate alınanlar
- zero-copy parsing avantajı ayrı ölçüldü
- DFA derleme maliyeti ayrı ölçüldü
- Özelliği olmayan araçlar ilgili testlerden çıkarıldı
- Veri kopyalama maliyeti ayrı ele alındı
Benchmark sonuçları
- Belge parse süresi:
serde_json_borrow en hızlısı
- Sorgu derleme süresi:
jsongrep, DFA oluşturduğu için en yüksek maliyete sahip; jmespath çok daha hızlı
- Arama süresi:
jsongrep, tüm araçlar arasında en hızlısı
- Uçtan uca performans: 190MB veri kümesinde bile
jq, jmespath, jsonpath-rust, jql'den ezici biçimde daha hızlı
- Tüm sonuçlar canlı benchmark sitesinde görülebilir
Lisans ve kullanım
- MIT lisanslı açık kaynak yazılım
- GitHub, Crates.io ve Docs.rs üzerinden kullanılabilir
- DFA tabanlı sorgu motoru kütüphane olarak yeniden kullanılabilir ve Rust projelerine doğrudan entegre edilebilir
Kaynakça
- Glushkov, V. M. (1961), The Abstract Theory of Automata
- Rabin, M. O., & Scott, D. (1959), Finite Automata and Their Decision Problems
3 yorum
Harika görünüyor.
| Dikey çizgi neden gövde metninde farklı görünüyor? İlginçmiş..
Hacker News görüşleri
jq'nun sözdizimi fazla anlaşılmaz olduğu için, her seferinde basit bir JSON değeri bile almak istesem aratmam gerekiyorjqsözdizimini sezgisel buluyorum; shell pipeline gibi nokta, pipe ve köşeli parantez kullanmaya alışığımGenelde tek seferlik filtreler yazdığım için, okumaktan çok yazmaya zaman harcıyorum
Muhtemelen kullanım senaryom basit ya da
jqdüşünme biçimime iyi uyuyorTüm CLI araçlarının JSON girdi/çıktısı verip
jqile birbirine bağlandığı bir dünya hayal ediyorum ama bu sizin için kâbus gibi olurdujqsık kullanmadığım için “öğrenme vadisinde” kalan bir araçHer kullandığımda yeniden öğrenmem gerektiğinden sezgisel gelmiyor
sedde Turing-complete olmasına rağmen çoğu kişi onu en fazla regex değiştirme için kullanıyorjq'yu seviyorum ama geçmişte kendi yazdığım sorguları bile anlayamadığım olducelq, daha tanıdık olan CEL dilini kullanıyorBu araç basitçe JavaScript ile JSON işliyor ve şaşırtıcı biçimde
jq'dan daha hızlı$ cat package.json | dq 'Object.keys(data).slice(0, 5)'gibi kullanılıyorClojure öğrendiğim için artık JSON yerine EDN kullanıyorum
Daha kısa, daha okunabilir ve yapısal olarak işlenmesi daha kolay
Son zamanlarda verileri
borkdude/jetya dababashkaile işliyor,djblue/portalile görselleştiriyorumjq'nun o karmaşık operatörlerinde neden ısrar edildiğini anlayamıyorumPerformansı önemsiyorum ama nanosaniye düzeyindeki karşılaştırmalar bana gösteriş amaçlı performans gibi geliyor
Çoğu durumda şu an kullandığımız araç yeterli
Örneğin ben sadece büyük dosyalarda
grepyerinergkullanıyorum2 ms ile 0.2 ms arasındaki fark önemsiz görünebilir ama TB ölçeğinde akış işleyen biri için önemlidir
Donanım hızlandı ama yazılımın tersine yavaşladığı bir gerçeklikte yaşıyoruz
jq'nun öne çıkması için sezgisel bir sözdizimi ve gerçek kullanım örnekleri daha fazla olmalıOptimizasyondan kaçınmak bana tembellik ve hayal gücü eksikliği gibi geliyor
Ağ gecikmesinden hızlı diye rahatlamak kulağa bahane gibi geliyor
JSON fazla büyükse JSON yerine ikili bir format kullanmak gerekir
CLI'da karmaşık pipeline'lar kurmak gerekiyorsa, bence doğrudan program yazmak daha iyi
Pek çok yeni CLI aracı “daha hızlı” olduğunu öne sürüyor ama gerçekte
jq'nun yavaş olduğunu neredeyse hiç hissetmedimndjsondosyalarıyla çalışıyorumjqile sadece alan adlarını değiştiren basit işler bile fazla yavaş olduğu için işi doğrudan Node veya Rust scriptleriyle yapıyorumjqyavaş hissedilebilirHyperscaler ortamlarında birkaç TB log doğrudan indirilip analiz ediliyor
İzleme çözünürlüğüne göre performans farkı hissedilebilir
Özelliklerin sadece bir kısmı uygulanıyor ve benchmark ile zafer ilan ediliyor
Bu proje de o “alt küme daha hızlıdır” eğiliminin bir parçası gibi görünüyor
Ondan sonra her şey yavaş gelmeye başlıyor
ripgrepgibi hızlı bir aracı bir kez kullandıktan sonra geri dönmek zor oluyorHem
jqhemyqkullandım amayqçok daha yavaş olmasına rağmen bundan hiç şikâyet etmedimjq'dan daha hızlı bir araç varsa güzel ama buna sadece belirli bir kullanıcı kitlesi ihtiyaç duyarYine de optimizasyonu seven biri olarak saygı duyuyorum
yq'dan söz ettiğinizi merak ettim — Go sürümü mü, Python sürümü mü?jqile işliyorumETL aşamasında epey zaman alıyor
Sayfayı ilk açtığımda light mode renkleri bozuktu
Dark mode'a geçip geri dönünce düzeldi
Ben doğruluk nedeniyle Jaq'a geçtim
Performansının da
jq'dan iyi olduğu söyleniyorjaq,jsongrep'e kıyasla daha doğru yöne evrilmiş gibi görünüyorjaq3.0, dağıtımlardakijqpaketinden hızlı olsa da elle derlenmişjqdaha hızlıjq'nun yavaş olduğuna dair ün, dağıtım paketleme sorunlarından kaynaklanıyor gibi görünüyorİşim gereği sık sık newline-delimited JSON (
jsonl) ile uğraşıyorumHer satır tam bir JSON nesnesi; başlıca CLI araçlarının bu formatı destekleyip desteklemediğini merak ediyorum
jq,mlr,htmlq,xsv,yqgibi çeşitli veri işleme CLI araçları kullandım amaNushell'i keşfettikten sonra hepsinin yerini o aldı
Tüm formatları tek bir sözdizimiyle işleyebilmek çok ferahlatıcıydı
Yalnız ekip arkadaşlarıyla çalışırken
jq,yq,mlrkullanmaya devam ediyorumOtomatik tamamlama ayarı ve komutların keşfedilebilirliği konusunda biraz rahatsızlık var ama oh-my-zsh'den çok daha iyi
Zorunlu type annotation, statik binary derleme ve bir TUI kütüphanesi de gelirse küçük uygulamalar yazmak için bile kullanırım
Harika bir araç! Yalnız benchmark görselleştirmesi biraz zayıf kalmış
Tüm araçlar aynı renkte olduğu için
jsongrep'in nerede olduğunu bulmak zorjqda grafikte yoktu, bu da kafa karıştırıcıydıxLargedosyası 190 MiB ile küçük sayılır; ben sık sık 400 MiB ile 1 GiB arası JSON işliyorumDaha büyük herkese açık JSON belgeleri varsa paylaşmanız iyi olur
Benchmark görselleştirmesi kaba hissettiriyor
Renk ya da şekil kullanarak daha fazla boyut ifade edilebilirdi
Sonuçları anlamak için dosya yollarını tek tek okumak zorunda kalmak kullanışsız