- भले ही UI को hierarchical दिखना हो, पहले यह जांचना चाहिए कि क्या डेटा में सचमुच parent-child relationship होना जरूरी है, या सिर्फ ऐसा दिखना ही काफी है
- अगर असली tree की जरूरत नहीं है, तो parent ID के बजाय पूरी सूची के absolute sort order और
indentवैल्यू से स्क्रीन पर संरचना दिखाई जा सकती है - Hiss game editor
banana.eatजैसे नामों को sort करने के बाद dot (.) के बाद वाले हिस्से को indented दिखाकर namespace जैसा दिखने वाला UI बनाता है - यह तरीका उस word processor-शैली editing के ज्यादा करीब है जिसमें user items को ऊपर-नीचे ले जाता है और indent/outdent करता है, इसलिए tree data structure का बोझ कम हो जाता है
- लेकिन अगर items के बीच संबंधों को वास्तव में query या maintain करना है, तो indentation या string symbol hacks के बजाय सचमुच का tree model चाहिए
पेड़ नहीं, लेकिन पेड़ जैसा दिखने वाला list
- जब किसी application में
Foo,Barजैसी dynamic list को tree view में दिखाने की कोशिश की जाती है, तो आम तौर पर हर item को उसके parent item से जोड़ने वाली संरचना की कल्पना की जाती है - relational database में, उदाहरण के लिए,
parentcolumn में parent ID store की जा सकती हैFooकाparentnullहैFoo 1काparentFooहैFoo 1.aकाparentFoo 1है
- ऐसे tree data को SQL में लाने के लिए recursive CTE जैसी तकनीक की जरूरत पड़ सकती है
- लेकिन कई lists में वास्तविक relationship से ज्यादा महत्वपूर्ण यह हो सकता है कि चीजें इंसानों को देखने में साफ-सुथरी तरह व्यवस्थित लगें
indentation value को data के रूप में store करने का तरीका
- अगर असली parent-child relationship की जरूरत नहीं है, तो list को सिर्फ इन fields से store किया जा सकता है
idsortindentname
sortकिसी child group के भीतर का क्रम नहीं, बल्कि पूरी list का absolute order दिखाता हैindentitem के आगे डाली जाने वाली space की मात्रा को सीधे दिखाता है, इसलिए screen rendering सरल हो जाती है- editing UI भी tree manipulation की तुलना में सरल हो सकता है
- user items को ऊपर-नीचे move कर सकता है
- item को indent या outdent कर सकता है
- जरूरत हो तो सही indentation enforce करने के लिए कुछ सरल rules जोड़े जा सकते हैं
- नतीजतन, सीधे computer science textbook वाले data structure को manipulate करने के बजाय अनुभव word processor में list edit करने जैसा हो जाता है
Hiss का dot (.) आधारित नकली namespace
- text adventure game editor Hiss
banana,banana.eat,banana.peelजैसे नामों को UI में hierarchical तरीके से दिखाता है - इसका मतलब यह नहीं कि HissScript में वास्तविक namespace feature implement किया गया है
- implementation काफ़ी सरल है
- object names को alphabetical order में sort किया जाता है
- अगर name में dot (
.) हो, तो पहले वाला हिस्सा काट दिया जाता है - बचे हुए हिस्से को indented करके दिखाया जाता है
- example code का मुख्य logic भी इसी flow का पालन करता है
things.keysको sort किया जाता है- हर name में dot होने पर indentation जोड़कर dot से पहले वाला हिस्सा हटाकर output किया जाता है
- dot न होने पर name को जैसा है वैसा output किया जाता है
- इसके बाद कुछ और lines जोड़ी जाती हैं जो यह check करती हैं कि दिए गए prefix वाला “parent” item मौजूद है या नहीं
- arbitrary depth की nesting भी जोड़ी जा सकती है, लेकिन उसे तब तक टाला गया है जब तक उसकी सच में जरूरत न हो
- यह namespace जैसा दिखने वाला UI game को व्यवस्थित करने वाले व्यक्ति के लिए महत्वपूर्ण है, लेकिन game editor और player के लिए इसका कोई खास अर्थ नहीं है
- dot वाला name भी बस एक name है
- namespace जैसा दिखने वाला हिस्सा सिर्फ name को unique बनाए रखने का काम करता है
flat list के रूप में tree-जैसे cases को संभालना
- Dave Long ने “low-tech real tree” के रूप में path और information को flat list में store करने का तरीका सुझाया
- यह
banana.eatवाले example जैसी ही insight है findoutput जैसी path list की कल्पना की जा सकती है./foo/zonk./foo/bonk./bar/boop/bop./bar/boop/bleep
- अगर depth-first traversal चाहिए, तो paths को lexicographic order में sort करना काफी है
- अगर breadth-first traversal चाहिए, तो path separator के आधार पर paths को उलटकर, depth match करने के लिए खाली items जोड़कर sort किया जा सकता है
- यह example सिर्फ concept दिखाने के लिए है; व्यवहार में separator पर split करके array के रूप में process करना ज्यादा स्वाभाविक होगा
- flat lists को कुल मिलाकर संभालना आसान होता है, और जहाँ संभव हो, items को plain old lists में रखने वाला approach पसंद किया जाता है
फ़र्श पर scrapbook वाली उपमा
- व्यक्तिगत scrapbook बनाते समय फोटो, notes, postcards, tickets वगैरह को फ़र्श पर फैलाकर groups बनाए जा सकते हैं
- इंसान को group relationship साफ़ दिखाई दे सकती है, लेकिन फ़र्श खुद उस relationship को enforce करने वाला कोई physical mechanism नहीं देता
- इस उपमा का सार यह है कि दिखाई गई relationship और वास्तविक structural relationship अलग हो सकती हैं
- UI list में भी यही बात लागू होती है: जो arrangement इंसान को hierarchical दिखती है, ज़रूरी नहीं कि वह internal data model में असली hierarchy ही हो
जब सचमुच tree की जरूरत हो
- indentation या string symbols पर आधारित तरीका स्थिति के अनुसार काफी बदलना पड़ सकता है, और सामान्य programming context में इसे hack माना जा सकता है
- अगर वास्तव में items के बीच relationship जाननी हो, तो parent ID, parent-child join table आदि जैसे data model के अनुरूप असली tree structure का उपयोग करना चाहिए
- अगर स्थिति ऐसी हो जैसे बड़े research project को classify करना, जहाँ physical file cabinet और folder-level organization चाहिए, तो “फ़र्श वाला तरीका” उपयुक्त नहीं है
- अगर किसी project में बाद में वास्तव में items के बीच संबंध जानने की जरूरत पड़ेगी, तो indentation या string के भीतर symbols की संख्या से structure की नकल करना project की पूरी उम्र और maintenance period में दर्दनाक रास्ता साबित हो सकता है
1 टिप्पणियां
Hacker News की रायें
पहला तरीका, यानी वह जो “जाहिर है, यही एक तरीका है” जैसा लगता है, adjacency list कहलाता है
दूसरा “काफ़ी सरल तरीका” मैंने पहले नहीं देखा था, और इसके कुछ स्पष्ट नुकसान हैं, लेकिन कुछ मामलों में यह काफ़ी लग सकता है
तीसरे “namespace वाले” तरीके को materialized path कहा जाता है, और यह tree को दर्शाने का एक और तरीका है; इसके अलावा nested sets भी होते हैं: https://www.ibase.ru/files/articles/programming/dbmstrees/sq...
जब लोग relational database को गंभीरता से लेते थे, तब यह सब अच्छी तरह जाना-पहचाना था, और उदाहरण के लिए http://www.dbazine.com/oracle/or-articles/tropashko4/ जैसे लेख भी थे
अब यह भूला हुआ ज्ञान लगता है
जब आप खुद किसी समस्या के अलग-अलग पहलुओं को समझ रहे होते हैं, तब उस अवधारणा का पहले से मौजूद नाम ढूँढना सच में बहुत मुश्किल लगता है
नतीजा यह होता है कि tree दिखाने का सारा logic code में संभालना पड़ता है, जबकि modern relational databases और कुछ CTEs से कई use cases को बहुत elegant तरीके से लगभग मुफ़्त में संभाला जा सकता है
https://www.oreilly.com/library/view/joe-celkos-trees/978155...
Postgres में ltree data type और search operators हैं जो इस तरह native रूप से काम करते हैं: https://www.postgresql.org/docs/current/ltree.html
उदाहरण के लिए,
CREATE TABLE test (path ltree);,INSERT INTO test VALUES ('Top');,INSERT INTO test VALUES ('Top.Science');,INSERT INTO test VALUES ('Top.Science.Astronomy');की तरह डालकरSELECT path FROM test WHERE path <@ 'Top.Science';सेTop.ScienceऔरTop.Science.Astronomyखोजे जा सकते हैंऊपर के उदाहरण में अगर
Top.Sciencerecord हटा भी दें, तोTop.Science.Astronomyrecord नहीं कटेगाltree value के labels materialized path के ज़रिए एक logical tree का संकेत देते हैं, लेकिन वे यह बाध्य नहीं करते कि संकेतित सभी parent nodes के लिए records मौजूद हों
application के अनुसार यह ठीक वही व्यवहार हो सकता है जो आप चाहते हैं, या बिल्कुल उसका उलटा। अगर दूसरा मामला है, तो integrity बनाए रखने के लिए अलग व्यवस्था करनी होगी
/इस्तेमाल किया जा सकता है?[1] https://learn.microsoft.com/en-us/sql/relational-databases/h...
बस चिंता यह है कि शायद JSON indexes, ltree indexes जितने अच्छे से काम न करें
यहाँ समस्या यह है कि इस संरचना का मूल्य आम तौर पर display tree में नहीं, बल्कि डेटा की hierarchy में होता है
संभावना है कि आपको डेटा को traverse करना, संबंध दिखाना, या उसे reorder करना जैसे काम करने पड़ें
database के data structure में visual information भरना जोखिम भरा और short-sighted लगता है
क्या जवाब यह है कि “नहीं, ऐसा हो ही नहीं सकता”?
YAGNI एक मशहूर design heuristic है, इसके पीछे वजह है। “मान लो कि हमेशा ज़रूरत पड़ेगी” सही नहीं है
बस optimized data type के dedicated column में रखने के बजाय उसे data string के आगे जोड़ दिया गया है
यह संख्या न भी हो, और ID column भी न हो, फिर भी यह किसी दूसरे expected value की ओर इशारा करने वाला identifier ही है; format बदल जाने से वह parent ID होना बंद नहीं हो जाता
बेशक यह सुनिश्चित करना होगा कि parent के बिना child जैसी गलत indentation save न हो
इसलिए सबसे आसान तरीका पहले order/depth के रूप में store करना है, और जब ज़रूरी features लागू करने हों तब parent/child model में migrate करना है
लेकिन “indentation” को render होने वाली spaces की संख्या के रूप में नहीं, बल्कि tree में depth के रूप में अधिक abstract तरीके से परिभाषित करना बेहतर है। इससे गलत data ढूँढना आसान होता है, बाद की migration भी आसान होती है, और nested
/, tabs, 8 spaces, 4 spaces, 1 space जैसी user-specific rendering flexibility भी मिलती हैstruct item_t { char key[255]; char display_value[255]; }जैसी data structure हो, और key मेंa/b/cकी तरह एक consistent path separator हो, तो parent और child ढूँढना बहुत आसान हो जाता हैसबसे खराब स्थिति में array को linear scan करना होगा, और अगर sort किया गया है, तो parent तक पहुँचने के लिए सिर्फ पिछले items देखने होंगे
मैंने एक ऐसी company शुरू की थी जहाँ tree-shaped data बहुत था। tree structure को indented list में बदलना O(n) समय में संभव है
यह उस समय interview questions में से एक था, और कई SQL databases में ऐसे तरीके होते हैं जिनसे recursive query के बिना भी tree के हिस्से को तेज़ी से लाकर render करने लायक रूप में store किया जा सकता है
एक बार आप इन concepts को समझ लें, तो डेटा को सही तरह tree के रूप में store करने के फायदे इस तरह की indentation से कहीं ज़्यादा होते हैं
“SQL query के ज़रिए relational database से tree-structured data लाने का एक तरीका recursive CTE(Common Table Expressions) का उपयोग करना है, और यह उसके नाम जितना ही मज़ेदार है”
CTE डरावना नहीं है, recursive CTE समेत भी, और इसकी आदत पड़ जाए तो यह सच में मज़ेदार लग सकता है
hierarchy depth d वाले node path को assemble करने पर query result मिलने का समय कम से कम d गुना धीमा हो गया
फायदा यह था कि tree edit operations सस्ते थे, लेकिन वे read की तुलना में बहुत कम होते थे
“लोगों को वास्तव में tree चाहिए या ज़रूरत होती है, ऐसा कम होता है; ज़्यादा बार उन्हें सिर्फ tree जैसा दिखने वाला कुछ चाहिए होता है” — इस बिंदु पर HN और Reddit का फर्क दिखता है
HN में child comments, parent comment के
nextSiblingहोते हैं, और parent के indentation value में 1 जोड़कर उसे tree जैसा दिखाया जाता हैReddit में, कम से कम old.reddit.com पर, child comments वास्तव में parent comment के अंदर nested होते हैं। नई site के बारे में नहीं पता
डेटा पर होने वाले सारे operations, पहले tree structure infer करके फिर उसे वापस implicit tree format में translate करने वाली जटिल अव्यवस्था बन जाएँगे
लेख का मुख्य विचार सरल है। समस्या के अनुसार सही structure का उपयोग करना चाहिए
लेकिन मुझे इसकी narrative गलत लगती है। database से tree लाने के लिए CTE अनिवार्य नहीं है; आप flat list ला सकते हैं और local स्तर पर tree बना सकते हैं। बाद की manipulation के लिए भी वैसे भी ऐसा करना पड़ सकता है
इसी तर्क से, list store करने के लिए relational database इस्तेमाल करने वालों से यह भी कहा जा सकता है कि text file में store करो। network latency की लागत क्यों उठानी?
दूसरी ओर, प्रस्तावित structure बड़े tree में branch को move करने और depth बदलने के लिए पर्याप्त अच्छा नहीं है, क्योंकि इसकी लागत linear है
शुरुआत से ही इरादा साफ़ करना चाहिए था। तीन examples समझाने के बाद निष्कर्ष में “अगर tree चाहिए तो tree इस्तेमाल करो” कहकर उन्हें निष्प्रभावी नहीं करना चाहिए था। हालाँकि अगर यह बात लेख की शुरुआत में होती, तो यह काफी कम clickbait लगता
कुछ साल पहले OpenGL के बारे में मुझे इसी तरह की समझ मिली थी। मुझे hierarchical 3D objects की दुनिया draw करने की ज़रूरत नहीं थी, बल्कि sorted triangle list draw करनी थी
उस विचार ने दिमाग में एक switch on कर दिया, और कई optimizations बहुत आसान हो गईं
जिन games में complex entity hierarchies होती हैं, उनमें भी render queue में डालते समय transparency sorting जैसी वजहों से अक्सर उन्हें flat structure में fold करना पड़ता है
“चीज़ों की flat list” ECS/DOD की बुनियाद भी है
database में इस तरह के काम को संभालने पर पूरी की पूरी किताबें हैं
https://www.oreilly.com/library/view/joe-celkos-trees/978155...
fake tree बनाने का एक और तरीका JSON blob store करना है
अगर डेटा के संबंध सिर्फ अंदरूनी हों, तो unique और ordered sorting numbers बनाए रखने की तुलना में यह आसान हो सकता है