3 पॉइंट द्वारा GN⁺ 2023-11-30 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • jaq JSON डेटा प्रोसेसिंग टूल jq का एक क्लोन है, जो ज़्यादातर मामलों में jq के साथ संगतता बनाए रखते हुए अधिक सटीक और पूर्वानुमेय इम्प्लीमेंटेशन का लक्ष्य रखता है
  • कमांड-लाइन प्रोग्राम jaq को jq के drop-in replacement के रूप में इस्तेमाल किया जा सकता है, और Rust लाइब्रेरी jaq-core Rust प्रोग्राम के भीतर jq प्रोग्राम को compile और run कर सकती है
  • यह YAML, CBOR, TOML, XML सपोर्ट देता है, जो jq में नहीं है; साथ ही jaq-core मल्टीथ्रेडेड वातावरण में सुरक्षित रूप से इस्तेमाल किया जा सकता है और JSON से आगे arbitrary data types को सपोर्ट करता है
  • परफ़ॉर्मेंस मूल्यांकन में jaq-3.0 31 में से 20 benchmark में सबसे तेज़ था, jq-1.8.1 5 में, और gojq-0.12.18 6 में सबसे तेज़ था
  • सुरक्षा के लिहाज़ से यह 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 मूल रूप से इसलिए बनाया गया था क्योंकि jq 1.6 का लंबा startup time असुविधाजनक था, और उस वातावरण में startup time लगभग 50ms था
    • बहुत बड़ी संख्या में छोटी फ़ाइलों को प्रोसेस करते समय यह startup time खास तौर पर उभरकर सामने आता है
    • jq 1.7 में startup time काफ़ी बेहतर हुआ, लेकिन कई benchmark में jaq अब भी jq से तेज़ है
  • सरलता

    • jaq बग की संभावना कम करने और योगदान आसान बनाने के लिए सरल और छोटा इम्प्लीमेंटेशन अपनाता है

इंस्टॉलेशन और बिल्ड

  • Linux, Mac, Windows के लिए binaries releases page से डाउनलोड की जा सकती हैं
  • macOS या Linux पर इसे homebrew से install किया जा सकता है
    • brew install jaq
    • brew install --HEAD jaq
  • source से build करने के लिए Rust toolchain चाहिए
  • यदि repository clone की है, तो cargo build --release या cargo install --locked --path jaq से build या install किया जा सकता है
  • jaq को Rust द्वारा समर्थित सभी systems पर चलना चाहिए; यदि ऐसा नहीं है, तो issue दर्ज करने के लिए कहा गया है

परफ़ॉर्मेंस मूल्यांकन

  • परफ़ॉर्मेंस मूल्यांकन कई benchmark से बना है, जिनमें jaq, jq और gojq की तुलना की गई है
  • empty benchmark null input के साथ empty filter को n बार चलाकर startup time मापता है
  • bf-fib benchmark 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.0 20 benchmark में सबसे तेज़ था
    • jq-1.8.1 5 benchmark में सबसे तेज़ था
    • gojq-0.12.18 6 benchmark में सबसे तेज़ था
  • gojq tree-flatten में काफ़ी तेज़ है, क्योंकि यह flatten filter को 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("[")' | jaq
    • jaq -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 सपोर्ट इम्प्लीमेंट करने की तुलना में बहुत मदद की, और ValT trait के ज़रिए extensibility के कारण अपने खुद के type में jq सपोर्ट आसानी से जोड़ा जा सका
  • एक अन्य उपयोगकर्ता ने कहा कि jaq इस्तेमाल करने वाला Rust प्रोग्राम पूरे फ़ाइल पर एक query चलाने में Python के jq PyPI crate और Python loop द्वारा लगने वाले समय के दौरान, पूरे फ़ाइल पर सभी query तीन बार चला सकता था
  • wsjq interpreter के मामले में, jaq अन्य jq implementations की तुलना में काफ़ी तेज़ था और सटीकता पर इसका ज़ोर प्रभावशाली लगा
    • उस wsjq benchmark में jaq, jq से 5~10 गुना और gojq से 15~196 गुना तेज़ था
  • certificate transparency log data को certstream-server से प्रोसेस करने वाले एक उपयोगकर्ता ने कहा कि jq पाइप प्रोसेसिंग में समस्या थी, लेकिन jaq पर स्विच करने के बाद तेज़ startup time की वजह से यह कम-क्षमता वाले VM पर भी साथ चल पाया

फंडिंग

1 टिप्पणियां

 
GN⁺ 2023-11-30
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 मेरे लिए ज्यादा ठीक बैठता है

    • इस नजरिए से gron भी अच्छा है
      यह 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 वाले तरीके के करीब जाना चाहिए
    • https://github.com/tidwall/jj भी देखने लायक है
    • ऐसी असुविधा से कुछ हद तक सहमत हूं, लेकिन कम से कम jql समाधान जैसा नहीं दिखता
      |={"b""d"=2, "c"} का मतलब jq के select(."b"."d" == 2 or ."c" != null) जैसा लगता है, और jq वाला ज्यादा लंबा होने पर भी ज्यादा स्पष्ट महसूस होता है
      असल में शायद .[] | select(...) की जरूरत होगी, लेकिन jql में भी ऐसी ही कोई assumption हो सकती है, और example पूरा है या नहीं यह पक्का नहीं, इसलिए निष्कर्ष पर ज्यादा असर नहीं पड़ता
    • jql की homoiconicity काफी Lisp जैसी दिखती है
      लगता है इसे खुद पर 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
    • इसी समस्या की वजह से jq की ताकत का पूरा इस्तेमाल नहीं कर पाता था, लेकिन ऐसे cases में Copilot सच में मददगार है
      जरूरी task और छोटा किया हुआ original JSON sample साथ में दें, तो यह सही jq script बना देता है
      complex requirements को एक बार में बिल्कुल सही बताने के बजाय Copilot के साथ धीरे-धीरे iterate करके solution तक ले जाना ज्यादा आसान और भरोसेमंद है। iteration के दौरान शुरुआत से बेहतर ideas भी आ जाते हैं
      ChatGPT या दूसरे tools भी शायद इसी तरह काम करेंगे
    • हाल ही में ChatGPT से जरूरी jq syntax जल्दी मिल गया: https://chat.openai.com/share/40b68d73-d2dd-412d-867f-9f375e...
  • https://github.com/01mf02/jaq/blob/main/Cargo.lock
    dependencies काफी ज्यादा हैं

    • gojq से तुलना करें तो वाकई बहुत ज्यादा: https://github.com/itchyny/gojq/blob/main/go.mod
    • Rust ecosystem में ऐसे मामलों में आम तौर पर आगे क्या होता है, यह जानने की उत्सुकता है
      dependencies ज्यादा हों तो समय के साथ उनके आपस में मूल रूप से incompatible होने का risk बड़ा लगता है, और maintenance बड़ा काम बन सकता है
      उदाहरण के लिए, सोचता हूं कि 2 साल बाद भी compile ठीक से होगा या नहीं
  • jq बहुत शक्तिशाली tool है, लेकिन आजकल DuckDB भी काफी इस्तेमाल हो रहा है
    अगर data कुछ हद तक table के रूप में है, तो SQL कहीं ज़्यादा natural भाषा है

    • पहले Retool आज़माया था, जिसमें “Query JSON with SQL” था और यह काफी सुविधाजनक लगा: https://docs.retool.com/queries/guides/sql/query-json
      यह 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 जोड़ने के लिए बहुत भारी हैं
    • सही। strict schema वाले relational data के लिए SQL कहीं ज़्यादा अच्छा है
      फिर भी SQL में recursive queries को concise ढंग से express करना अब भी आसान नहीं है
    • इस use case के लिए मुझे निजी तौर पर textql ज़्यादा अच्छा लगता है। mental model ज़्यादा simple है
      https://github.com/dinedal/textql
  • correctness के नज़रिए से, जानना चाहता हूँ कि क्या uint64 numbers को truncate किए बिना दिखाया जा सकता है
    अभी jq में यही बात सबसे ज़्यादा खटकती है

    • दुर्भाग्य से अगर JSON numbers को 64-bit floating point माना जाए, तो standard के हिसाब से उन्हें वैसे ही handle करना होगा और integer precision 53 bits हो जाती है
      हालांकि newer spec RFC 8259 ने इसे ठीक करते हुए कहा है कि वह सिर्फ number के textual form को specify करता है, semantics तय नहीं करता
      व्यवहार में, ज़्यादातर implementations JSON को JavaScript के subset की तरह treat करती हैं, इसलिए यह assumption बन जाता है कि numbers 64-bit floating point हैं
    • मेरी जानकारी में jq 1.7 में यह बेहतर हुआ है: https://github.com/jqlang/jq/releases/tag/jq-1.7
      लिखा है कि decimal number literals का इस्तेमाल करके precision preserve की जाती है, और comparison operations precision का सम्मान करते हैं, लेकिन arithmetic operations truncate हो सकते हैं
    • jq 1.7 बड़े integers preserve करता है, लेकिन उन पर कोई भी operation किया जाए तो truncation हो जाती है
      अभी यह decimal64 में truncate करता है, जो थोड़ा confusing है; अगले release में JSON spec की recommendation के अनुसार इसे binary64(double) में truncate करने के लिए fix किया जाएगा: https://github.com/jqlang/jq/pull/2949
  • jless पर switch करने के बाद पीछे मुड़कर नहीं देखा
    इसका user interface बाकी चीज़ों से काफी आगे है

    • यह उसी category की चीज़ नहीं है
      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.jq https://pastebin.com/raw/YiUjEu2n है, और input.txt https://pastebin.com/raw/X0FSyTNf है

  • jq की जगह yq इस्तेमाल करना शुरू किया है, सोच रहा हूँ कि कोई important difference है क्या

    • यह इस पर निर्भर करता है कि कौन-सा yq है
      निजी तौर पर मैं https://github.com/mikefarah/yq को https://github.com/kislyuk/yq से ज़्यादा पसंद करता हूँ
    • jq, yq की तुलना में कहीं ज़्यादा robust tool लगता है
      समझता हूँ कि 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 है