सटीकता, गति और सरलता पर केंद्रित jq क्लोन, Jaq
(github.com/01mf02)- jaq JSON डेटा प्रोसेसिंग टूल
jqका एक क्लोन है, जो ज़्यादातर मामलों मेंjqके साथ संगतता बनाए रखते हुए अधिक सटीक और पूर्वानुमेय इम्प्लीमेंटेशन का लक्ष्य रखता है - कमांड-लाइन प्रोग्राम
jaqकोjqके drop-in replacement के रूप में इस्तेमाल किया जा सकता है, और Rust लाइब्रेरीjaq-coreRust प्रोग्राम के भीतर jq प्रोग्राम को compile और run कर सकती है - यह YAML, CBOR, TOML, XML सपोर्ट देता है, जो
jqमें नहीं है; साथ हीjaq-coreमल्टीथ्रेडेड वातावरण में सुरक्षित रूप से इस्तेमाल किया जा सकता है और JSON से आगे arbitrary data types को सपोर्ट करता है - परफ़ॉर्मेंस मूल्यांकन में
jaq-3.031 में से 20 benchmark में सबसे तेज़ था,jq-1.8.15 में, औरgojq-0.12.186 में सबसे तेज़ था - सुरक्षा के लिहाज़ से यह panic रोकने, memory safety, और input data व jq filter की I/O सीमाओं को सुनिश्चित करने की कोशिश करता है, लेकिन समय, मेमोरी और स्टैक जैसी resource exhaustion स्थितियों से नहीं निपटता
jaq क्या प्रदान करता है
- jaq JSON डेटा प्रोसेसिंग टूल
jqका एक क्लोन है, और इसका उच्चारण/ʒaːk/है, जो Jacques जैसा है - इसमें ऐसे data format सपोर्ट हैं जो
jqमें नहीं हैं-
YAML
-
CBOR
-
TOML
- XML
- इसके लिए अलग manual है, और इसे playground में आज़माया जा सकता है
- jaq दो रूपों में उपलब्ध है
- कमांड-लाइन प्रोग्राम
jaq:jqके drop-in replacement के रूप में उपयोग योग्य - लाइब्रेरी
jaq-core: Rust प्रोग्राम के भीतर jq प्रोग्राम को compile और run किया जा सकता है
-
डिज़ाइन लक्ष्य
-
सटीकता
- jaq का लक्ष्य ज़्यादातर मामलों में
jqके साथ संगत रहते हुए अधिक सटीक और पूर्वानुमेय jq इम्प्लीमेंटेशन देना है
- jaq का लक्ष्य ज़्यादातर मामलों में
-
परफ़ॉर्मेंस
- jaq मूल रूप से इसलिए बनाया गया था क्योंकि
jq 1.6का लंबा startup time असुविधाजनक था, और उस वातावरण में startup time लगभग 50ms था - बहुत बड़ी संख्या में छोटी फ़ाइलों को प्रोसेस करते समय यह startup time खास तौर पर उभरकर सामने आता है
jq 1.7में startup time काफ़ी बेहतर हुआ, लेकिन कई benchmark में jaq अब भीjqसे तेज़ है
- jaq मूल रूप से इसलिए बनाया गया था क्योंकि
-
सरलता
- jaq बग की संभावना कम करने और योगदान आसान बनाने के लिए सरल और छोटा इम्प्लीमेंटेशन अपनाता है
इंस्टॉलेशन और बिल्ड
- Linux, Mac, Windows के लिए binaries releases page से डाउनलोड की जा सकती हैं
- macOS या Linux पर इसे homebrew से install किया जा सकता है
brew install jaqbrew install --HEAD jaq
- source से build करने के लिए Rust toolchain चाहिए
cargo install --locked jaqcargo install --locked --git https://github.com/01mf02/jaq
- यदि repository clone की है, तो
cargo build --releaseयाcargo install --locked --path jaqसे build या install किया जा सकता है - jaq को Rust द्वारा समर्थित सभी systems पर चलना चाहिए; यदि ऐसा नहीं है, तो issue दर्ज करने के लिए कहा गया है
परफ़ॉर्मेंस मूल्यांकन
- परफ़ॉर्मेंस मूल्यांकन कई benchmark से बना है, जिनमें jaq, jq और gojq की तुलना की गई है
emptybenchmark null input के साथemptyfilter कोnबार चलाकर startup time मापता हैbf-fibbenchmark jq में लिखे Brainfuck interpreter से Fibonacci संख्या बनाने वाली Brainfuck script चलाता है- benchmark data Linux सिस्टम के AMD Ryzen 5 5500U पर तैयार किया गया था
- उपयोग किया गया कमांड:
bench.sh target/release/jaq jq-1.8.1 gojq-0.12.17 | tee bench.json - तालिका में
jaq-3.0,jq-1.8.1,gojq-0.12.18के परिणाम milliseconds में दिखाए गए हैं N/Aका मतलब error या 10 सेकंड से अधिक समय है
- उपयोग किया गया कमांड:
- परिणाम सारांश
jaq-3.020 benchmark में सबसे तेज़ थाjq-1.8.15 benchmark में सबसे तेज़ थाgojq-0.12.186 benchmark में सबसे तेज़ था
gojqtree-flattenमें काफ़ी तेज़ है, क्योंकि यहflattenfilter को definition की बजाय native रूप में implement करता है
सुरक्षा मॉडल और सीमाएँ
- jaq निम्नलिखित की गारंटी देने की कोशिश करता है
- resource exhaustion के मामलों को छोड़कर panic नहीं होता
- मेमोरी को क्षतिग्रस्त न करने वाली memory safety
- jq filter चलाने से पहले फ़ाइल पढ़ने को छोड़कर, input data और jq filter I/O ऑपरेशन शुरू नहीं कर सकते
- यदि ये गारंटी टूटती हैं, तो उसे bug माना जाता है और रिपोर्ट किया जाना चाहिए
- jaq किसी भी प्रकार की resource exhaustion से नहीं निपटता
- execution time असीमित रूप से लंबा हो सकता है
- memory का असीमित उपयोग हो सकता है
- stack space का असीमित उपयोग हो सकता है
- उदाहरण के तौर पर input data पढ़ते समय या jq filter चलाते समय stack overflow हो सकता है
jaq -nr 'repeat("[")' | jaqjaq -n 'def f: 1+f; f'
ऑडिट और टेस्टिंग
- jaq core का NLnet grant के दो हिस्सों के अंतर्गत Radically Open Security द्वारा ऑडिट किया गया
- पहले और दूसरे सुरक्षा ऑडिट में मध्यम या निम्न गंभीरता वाले मुद्दे पाए गए
- सुरक्षा ऑडिट के सभी मुद्दों का समाधान कर दिया गया, और
jaq-core/fuzzमें jaq के लिए कई fuzzing target जोड़े गए - jaq का JSON parser hifijson भी पहले से fuzzing target रखता था
- jaq में 500 से अधिक tests वाला एक test suite है
उपयोगकर्ता मामले
- एक उपयोगकर्ता के अनुसार,
jaqने सीधेjqसपोर्ट इम्प्लीमेंट करने की तुलना में बहुत मदद की, औरValTtrait के ज़रिए extensibility के कारण अपने खुद के type में jq सपोर्ट आसानी से जोड़ा जा सका - एक अन्य उपयोगकर्ता ने कहा कि jaq इस्तेमाल करने वाला Rust प्रोग्राम पूरे फ़ाइल पर एक query चलाने में Python के
jqPyPI crate और Python loop द्वारा लगने वाले समय के दौरान, पूरे फ़ाइल पर सभी query तीन बार चला सकता था wsjqinterpreter के मामले में, jaq अन्य jq implementations की तुलना में काफ़ी तेज़ था और सटीकता पर इसका ज़ोर प्रभावशाली लगा- उस
wsjqbenchmark में jaq, jq से 5~10 गुना और gojq से 15~196 गुना तेज़ था
- उस
- certificate transparency log data को
certstream-serverसे प्रोसेस करने वाले एक उपयोगकर्ता ने कहा किjqपाइप प्रोसेसिंग में समस्या थी, लेकिन jaq पर स्विच करने के बाद तेज़ startup time की वजह से यह कम-क्षमता वाले VM पर भी साथ चल पाया
फंडिंग
- jaq प्रोजेक्ट को NLnet द्वारा स्थापित NGI0 Entrust और NGI0 Commons फंड के माध्यम से समर्थन मिला है
- वित्तीय सहायता European Commission के Next Generation Internet प्रोग्राम से दी गई है
- अतिरिक्त फंडिंग Swiss State Secretariat for Education, Research and Innovation से मिली है
1 टिप्पणियां
Hacker News की राय
यह देखते हुए कि jq का development 5 साल तक रुका रहा और हाल ही में फिर से जिंदा हुआ है, यह अजीब नहीं कि इस दौरान पुराने या नए bugs की reports जमा होती रहीं
अब लगता है कि इसकी रफ्तार वापस आएगी और लंबे समय से जमा unresolved list को धीरे-धीरे साफ किया जाएगा
README में मिलते-जुलते या प्रेरित projects, जो alternatives नहीं हैं, उन्हें साथ में紹介 करने का तरीका अच्छा है
इस project के README से https://github.com/yamafaktory/jql के बारे में पता चला, और यह वही tool था जिसे मैं लंबे समय से ढूंढ रहा था, इसलिए आभारी हूं
JAQ को नीचा दिखाने का इरादा नहीं है, लेकिन JQ-style syntax समझना बहुत मुश्किल है, इसलिए jql मेरे लिए ज्यादा ठीक बैठता है
यह JSON को key-value format वाली lines में flatten कर देता है, जिससे
grepजैसे simple stream operations के साथ यह अच्छी तरह fit होता है: https://github.com/tomnomnom/gronहालांकि असल में SQL जैसा अनुभव expect किया था। समझ नहीं आता कि सीधे SQL की नकल करके
"SELECT * FROM $json WHERE x>1"की तरह query क्यों नहीं करने देतेलगता है सब लोग code golf की तरह अपनी-अपनी कठिन symbolic query language बनाना चाहते हैं। बहुत छोटे लेकिन self-evident न लगने वाले पुराने Unix-style syntax से हटकर PowerShell वाले तरीके के करीब जाना चाहिए
|={"b""d"=2, "c"}का मतलब jq केselect(."b"."d" == 2 or ."c" != null)जैसा लगता है, और jq वाला ज्यादा लंबा होने पर भी ज्यादा स्पष्ट महसूस होता हैअसल में शायद
.[] | select(...)की जरूरत होगी, लेकिन jql में भी ऐसी ही कोई assumption हो सकती है, और example पूरा है या नहीं यह पक्का नहीं, इसलिए निष्कर्ष पर ज्यादा असर नहीं पड़तालगता है इसे खुद पर apply करना या “macros” इस्तेमाल करना भी संभव होगा
jq का idea अच्छा लगता है, लेकिन अक्सर इस्तेमाल नहीं करता, इसलिए जो चाहिए वह करने के लिए हर बार syntax manual में ढूंढना पड़ता है
दुर्भाग्य से jq से किए जाने वाले कामों में 99%
| jq .ही होता हैअलग से एक configuration language बनानी शुरू की, लेकिन पता चला कि वह JSON query के लिए भी काफी अच्छी है: https://docs.ruuda.nl/rcl/rcl_query/
एक example जिसे jq से हल नहीं कर पाया लेकिन RCL से कर सका, यहां है: https://fosstodon.org/@ruuda/111120049523534027
जरूरी task और छोटा किया हुआ original JSON sample साथ में दें, तो यह सही jq script बना देता है
complex requirements को एक बार में बिल्कुल सही बताने के बजाय Copilot के साथ धीरे-धीरे iterate करके solution तक ले जाना ज्यादा आसान और भरोसेमंद है। iteration के दौरान शुरुआत से बेहतर ideas भी आ जाते हैं
ChatGPT या दूसरे tools भी शायद इसी तरह काम करेंगे
https://github.com/01mf02/jaq/blob/main/Cargo.lock
dependencies काफी ज्यादा हैं
dependencies ज्यादा हों तो समय के साथ उनके आपस में मूल रूप से incompatible होने का risk बड़ा लगता है, और maintenance बड़ा काम बन सकता है
उदाहरण के लिए, सोचता हूं कि 2 साल बाद भी compile ठीक से होगा या नहीं
jq बहुत शक्तिशाली tool है, लेकिन आजकल DuckDB भी काफी इस्तेमाल हो रहा है
अगर data कुछ हद तक table के रूप में है, तो SQL कहीं ज़्यादा natural भाषा है
यह C# के LINQ से थोड़ा मिलता-जुलता है, लेकिन SQL ज़्यादा standardized है, इसलिए मुझे ज़्यादा पसंद है
अगर भाषा के अंदर raw collections को SQL से query कर पाना संभव हो, तो शानदार होगा; और अगर collections को transparently Sqlite में store किया जा सके, तो और भी बेहतर होगा
database वगैरह से data लाने के बाद loops या stream API से simple processing करने वाला code देखकर हमेशा कमी महसूस होती है। ऐसे use case में SQL, Java/Kotlin/Python/JavaScript से कहीं ज़्यादा high-level और concise है
original JSON output को पूरा sqlite table में store करता हूँ, फिर उसमें virtual columns बनाता हूँ, और फिर
selectके results को shell loop में चलाता हूँnested loops खुल जाते हैं, और exact records को DB में verify करके फिर से run किया जा सकता है, इसलिए debugging की संभावना काफी बेहतर हो जाती है
समझ आया कि मैं जो बना रहा हूँ वह DAG है, और हमेशा आखिरी successfully processed record से फिर शुरू कर रहा हूँ। सोच रहा हूँ कि इसे express करने के लिए
Makeजैसा कोई tool है क्याMake में SQL target नहीं है, और Airflow जैसे full-fledged DAG processors shell snippets जोड़ने के लिए बहुत भारी हैं
फिर भी SQL में recursive queries को concise ढंग से express करना अब भी आसान नहीं है
https://github.com/dinedal/textql
correctness के नज़रिए से, जानना चाहता हूँ कि क्या uint64 numbers को truncate किए बिना दिखाया जा सकता है
अभी jq में यही बात सबसे ज़्यादा खटकती है
हालांकि newer spec RFC 8259 ने इसे ठीक करते हुए कहा है कि वह सिर्फ number के textual form को specify करता है, semantics तय नहीं करता
व्यवहार में, ज़्यादातर implementations JSON को JavaScript के subset की तरह treat करती हैं, इसलिए यह assumption बन जाता है कि numbers 64-bit floating point हैं
लिखा है कि decimal number literals का इस्तेमाल करके precision preserve की जाती है, और comparison operations precision का सम्मान करते हैं, लेकिन arithmetic operations truncate हो सकते हैं
अभी यह decimal64 में truncate करता है, जो थोड़ा confusing है; अगले release में JSON spec की recommendation के अनुसार इसे binary64(double) में truncate करने के लिए fix किया जाएगा: https://github.com/jqlang/jq/pull/2949
jless पर switch करने के बाद पीछे मुड़कर नहीं देखा
इसका user interface बाकी चीज़ों से काफी आगे है
jq सिर्फ viewer नहीं, बल्कि JSON query language processor है
Rust में कहीं terminal line art library होना प्यारा है, लेकिन jaq चलाकर देखा तो उसने iTerm में escape codes megabytes में उंडेल दिए और आखिरकार iTerm ने उसे printer पर output करने की कोशिश की
यह कुछ ज़्यादा ही चालाक बनने जैसा था
echo *json | rush -- jaq -rf ./this-program.jq {} | datamash ...जैसे context में TTY में artistic effects डालने की कोशिश मुझे ठीक नहीं लगतीerror की वजह आखिरकार यह थी कि
jaqमेंstrftimeनहीं हैपहला impression यह है कि error messages अच्छे हैं, लेकिन
halt_error/0नहीं हैhalt_errorको comment out करने के बाद यह jq और gojq से धीमा थाउसी input पर
jqको करीब 0.023 सेकंड,gojqको करीब 0.070 सेकंड, औरjaqको करीब 0.103 सेकंड लगेइस्तेमाल किया गया
aoc22-13.jqhttps://pastebin.com/raw/YiUjEu2n है, औरinput.txthttps://pastebin.com/raw/X0FSyTNf हैjq की जगह yq इस्तेमाल करना शुरू किया है, सोच रहा हूँ कि कोई important difference है क्या
निजी तौर पर मैं https://github.com/mikefarah/yq को https://github.com/kislyuk/yq से ज़्यादा पसंद करता हूँ
समझता हूँ कि YAML processing, JSON से कहीं ज़्यादा कठिन है, लेकिन yq ने version 3 से 4 में जाते हुए syntax को jq के ज़्यादा करीब बदला, फिर भी किसी तरह पूरी तरह same नहीं है
साथ ही yq में if-then-else नहीं है, जिससे लगता है कि design अच्छा नहीं है या कुछ छूट गया है: https://github.com/mikefarah/yq/issues/95
जब YAML process करना हो, तो yq अच्छा काम करता है और comments भी काफी अच्छी तरह handle करता है, लेकिन pure JSON processing के लिए jq बेहतर tool है