एक पेड़ में एक फ्लैट टेबल को पार्स करने का सबसे कुशल / सुरुचिपूर्ण तरीका क्या है?


517

मान लें कि आपके पास एक फ्लैट टेबल है जो एक ऑर्डर किए गए ट्री पदानुक्रम को संग्रहीत करता है:

Id   Name         ParentId   Order
 1   'Node 1'            0      10
 2   'Node 1.1'          1      10
 3   'Node 2'            0      20
 4   'Node 1.1.1'        2      10
 5   'Node 2.1'          3      10
 6   'Node 1.2'          1      20

यहाँ एक चित्र है, जहाँ हमारे पास है [id] Name। रूट नोड 0 काल्पनिक है।

                       [०] जड़
                          / \ _ 
              [१] नोड १ [३] नोड २
              / \ _
    [२] नोड १.१ [६] नोड १.२ [५] नोड २.१
          /          
 [४] नोड १.१.१

HTML, (या टेक्स्ट, उस मामले के लिए) को सही ढंग से ऑर्डर किए गए, सही ढंग से इंडेंट किए गए पेड़ के रूप में आउटपुट करने के लिए आप किस न्यूनतम दृष्टिकोण का उपयोग करेंगे?

आगे मान लें कि आपके पास केवल मूल डेटा संरचनाएं (सरणियाँ और हैशैप) हैं, माता-पिता / बच्चों के संदर्भों के साथ कोई फैंसी ऑब्जेक्ट नहीं, कोई ओआरएम नहीं, कोई रूपरेखा नहीं, बस आपके दो हाथ। तालिका को परिणाम सेट के रूप में दर्शाया गया है, जिसे यादृच्छिक रूप से एक्सेस किया जा सकता है।

छद्म कोड या सादा अंग्रेजी ठीक है, यह विशुद्ध रूप से एक वैचारिक प्रश्न है।

बोनस प्रश्न: क्या RDBMS में इस तरह से पेड़ की संरचना को संग्रहीत करने का एक बेहतर तरीका है?


संस्करण और शर्तें

एक टिप्पणीकार ( मार्क बेसे ) के प्रश्न का उत्तर देने के लिए: एक रूट नोड आवश्यक नहीं है, क्योंकि यह कभी भी प्रदर्शित होने वाला नहीं है। ParentId = 0 "ये शीर्ष स्तर के" व्यक्त करने के लिए सम्मेलन है। ऑर्डर कॉलम परिभाषित करता है कि एक ही माता-पिता के साथ नोड्स कैसे सॉर्ट किए जा रहे हैं।

"परिणाम सेट" की मैंने बात की हैशमेप्स की एक सरणी के रूप में चित्रित किया जा सकता है (उस शब्दावली में रहने के लिए)। मेरे उदाहरण के लिए पहले से ही वहाँ होना था। कुछ जवाब अतिरिक्त मील जाते हैं और पहले इसका निर्माण करते हैं, लेकिन यह ठीक है।

पेड़ मनमाने ढंग से गहरा हो सकता है। प्रत्येक नोड में एन बच्चे हो सकते हैं। हालांकि मेरे मन में "लाखों प्रविष्टियाँ" का पेड़ नहीं था।

कुछ पर भरोसा करने के लिए नोड नामकरण ('नोड 1.1.1') की मेरी पसंद को गलत मत समझिए। नोड्स को समान रूप से 'फ्रैंक' या 'बॉब' कहा जा सकता है, कोई भी नामकरण संरचना निहित नहीं है, यह केवल इसे पठनीय बनाने के लिए थी।

मैंने अपना स्वयं का समाधान पोस्ट किया है ताकि आप लोग इसे टुकड़ों में खींच सकें।


2
"माता-पिता / बच्चों के संदर्भ वाली कोई फैंसी वस्तु नहीं" - क्यों नहीं? .AddChild (), .getParent () विधि के साथ एक मूल नोड ऑब्जेक्ट बनाना आपको नोड रिश्ते को बहुत अच्छी तरह से मॉडल करने की अनुमति देता है।
मैट बी

2
क्या यह एक नियमित (n बच्चे हैं जहाँ n> 2 हो सकता है) पेड़ या बाइनरी ट्री (नोड में 0, 1 या 2 बच्चे हो सकते हैं)?
१६:०६ पर BKimmel

चूंकि आप एक हैशमैप के साथ एक उचित नोड डेटा संरचना को लागू कर सकते हैं, यहां कोई वास्तविक प्रतिबंध नहीं है, बस अधिक काम है।
स्वेन्ते

... और ठीक यही तुमने किया।
स्वेन्ते

जवाबों:


451

अब जब MySQL 8.0 पुनरावर्ती प्रश्नों का समर्थन करता है , तो हम कह सकते हैं कि सभी लोकप्रिय SQL डेटाबेस मानक सिंटैक्स में पुनरावर्ती प्रश्नों का समर्थन करते हैं

WITH RECURSIVE MyTree AS (
    SELECT * FROM MyTable WHERE ParentId IS NULL
    UNION ALL
    SELECT m.* FROM MyTABLE AS m JOIN MyTree AS t ON m.ParentId = t.Id
)
SELECT * FROM MyTree;

मैंने 2017 में अपनी प्रस्तुति Recursive Query Throwdown में MySQL 8.0 में पुनरावर्ती प्रश्नों का परीक्षण किया ।

नीचे 2008 से मेरा मूल उत्तर है:


रिलेशनल डेटाबेस में ट्री-स्ट्रक्चर्ड डेटा को स्टोर करने के कई तरीके हैं। आप अपने उदाहरण में जो दिखाते हैं वह दो विधियों का उपयोग करता है:

  • निकटता सूची ("पैरेंट" कॉलम) और
  • पथ गणना (आपके नाम कॉलम में बिंदीदार संख्याएँ)।

एक अन्य समाधान को नेस्टेड सेट कहा जाता है , और इसे उसी तालिका में भी संग्रहीत किया जा सकता है। इन डिजाइनों के बारे में और अधिक जानकारी के लिए जो सेल्को द्वारा " ट्रीज़ एंड हायरार्कीज़ इन एसक्यूएल फॉर स्मार्टिज़ " पढ़ें ।

मैं आमतौर पर ट्री-स्ट्रक्चर्ड डेटा को स्टोर करने के लिए क्लोजर टेबल (उर्फ "एडजेंसी रिलेशन") नामक डिज़ाइन पसंद करता हूं । इसके लिए एक और तालिका की आवश्यकता होती है, लेकिन फिर पेड़ों की क्वेरी करना बहुत आसान है।

मैं अपनी प्रस्तुति में क्लोजर टेबल को कवर करता हूं मॉडल में पदानुक्रमित डेटा के लिए SQL और PHP के साथ और मेरी पुस्तक SQL Antipatterns में: डेटाबेस प्रोग्रामिंग के नुकसान से बचना

CREATE TABLE ClosureTable (
  ancestor_id   INT NOT NULL REFERENCES FlatTable(id),
  descendant_id INT NOT NULL REFERENCES FlatTable(id),
  PRIMARY KEY (ancestor_id, descendant_id)
);

क्लोजर टेबल में सभी रास्तों को स्टोर करें, जहाँ एक नोड से दूसरे में सीधा वंश होता है। प्रत्येक नोड के लिए खुद को संदर्भित करने के लिए एक पंक्ति शामिल करें। उदाहरण के लिए, आपके द्वारा अपने प्रश्न में दिखाए गए डेटा सेट का उपयोग करना:

INSERT INTO ClosureTable (ancestor_id, descendant_id) VALUES
  (1,1), (1,2), (1,4), (1,6),
  (2,2), (2,4),
  (3,3), (3,5),
  (4,4),
  (5,5),
  (6,6);

अब आप इस तरह से नोड 1 पर एक पेड़ प्राप्त कर सकते हैं:

SELECT f.* 
FROM FlatTable f 
  JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1;

आउटपुट (MySQL क्लाइंट में) निम्न की तरह दिखता है:

+----+
| id |
+----+
|  1 | 
|  2 | 
|  4 | 
|  6 | 
+----+

दूसरे शब्दों में, नोड 3 और 5 को बाहर रखा गया है, क्योंकि वे एक अलग पदानुक्रम का हिस्सा हैं, नोड 1 से नहीं उतरते।


पुन: तत्काल बच्चों (या तत्काल माता-पिता) के बारे में ई-सतियों से टिप्पणी करें। आप विशेष रूप से तत्काल बच्चे या माता-पिता (या किसी अन्य दूरी) के लिए क्वेरी करना आसान बनाने path_lengthके ClosureTableलिए " " कॉलम जोड़ सकते हैं ।

INSERT INTO ClosureTable (ancestor_id, descendant_id, path_length) VALUES
  (1,1,0), (1,2,1), (1,4,2), (1,6,1),
  (2,2,0), (2,4,1),
  (3,3,0), (3,5,1),
  (4,4,0),
  (5,5,0),
  (6,6,0);

फिर आप दिए गए नोड के तत्काल बच्चों को क्वेरी करने के लिए अपनी खोज में एक शब्द जोड़ सकते हैं। ये वंशज हैं जिनकी path_lengthसंख्या 1 है।

SELECT f.* 
FROM FlatTable f 
  JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
  AND path_length = 1;

+----+
| id |
+----+
|  2 | 
|  6 | 
+----+

@ अशरफ से टिप्पणी: "कैसे पूरे पेड़ को छाँटने के बारे में [नाम से]?"

यहां नोड 1 के वंशज हैं सभी नोड्स को वापस करने के लिए एक उदाहरण क्वेरी है, उन्हें फ्लैटटेबल में शामिल करें जिसमें अन्य नोड विशेषताएँ शामिल हैं जैसे कि name, और नाम के आधार पर छाँटें।

SELECT f.name
FROM FlatTable f 
JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
ORDER BY f.name;

@ टिप्पणी से पुन: टिप्पणी करें:

SELECT f.name, GROUP_CONCAT(b.ancestor_id order by b.path_length desc) AS breadcrumbs
FROM FlatTable f 
JOIN ClosureTable a ON (f.id = a.descendant_id) 
JOIN ClosureTable b ON (b.descendant_id = a.descendant_id) 
WHERE a.ancestor_id = 1 
GROUP BY a.descendant_id 
ORDER BY f.name

+------------+-------------+
| name       | breadcrumbs |
+------------+-------------+
| Node 1     | 1           |
| Node 1.1   | 1,2         |
| Node 1.1.1 | 1,2,4       |
| Node 1.2   | 1,6         |
+------------+-------------+

एक उपयोगकर्ता ने आज एक संपादन का सुझाव दिया। एसओ मध्यस्थों ने संपादन को मंजूरी दे दी, लेकिन मैं इसे उलट रहा हूं।

संपादन ने सुझाव दिया कि ऊपर दिए गए अंतिम प्रश्न में ORDER BY होना चाहिए ORDER BY b.path_length, f.name, संभवतः यह सुनिश्चित करने के लिए कि आदेश पदानुक्रम से मेल खाता है। लेकिन यह काम नहीं करता है, क्योंकि यह "नोड 1.2" के बाद "नोड 1.1.1" का आदेश देगा।

यदि आप पदानुक्रम को एक समझदार तरीके से मिलान करने के लिए आदेश चाहते हैं, तो यह संभव है, लेकिन केवल पथ की लंबाई के अनुसार आदेश देकर नहीं। उदाहरण के लिए, MySQL क्लोजर टेबल पदानुक्रमित डेटाबेस के लिए मेरा जवाब देखें - सही क्रम में जानकारी कैसे खींचनी है


6
यह बहुत सुरुचिपूर्ण है, धन्यवाद। बोनस बिंदु से सम्मानित किया गया। ;-) मैं एक छोटी सी कमी देखता हूँ - क्योंकि यह स्पष्ट रूप से और अंतर्निहित रूप से बच्चे के संबंध को संग्रहीत करता है , आपको पेड़ की संरचना में एक छोटी सी पारी के लिए बहुत सावधान UPDATEing करने की आवश्यकता है।
तोमलक

16
सही है, किसी डेटाबेस में ट्री-स्ट्रक्चर्स को स्टोर करने के हर तरीके को कुछ काम करने की ज़रूरत होती है, या तो ट्री को बनाते या अपडेट करते समय, या जब पेड़ों और सब्ज़ियों की क्वेरी करते हैं। वह डिज़ाइन चुनें जिसके आधार पर आप सरल होना चाहें: लिखना या पढ़ना।
बिल कार्विन

2
@ बफ़र, असंगतता पैदा करने का मौका है क्योंकि आप पदानुक्रम के लिए सभी पंक्तियों को बनाते हैं। निकटता सूची ( parent_id) केवल एक पंक्ति हर माता-पिता के बच्चे का रिश्ता व्यक्त करने के लिए है, लेकिन बंद तालिका कई है।
बिल करविन

1
@BillKarwin एक और बात, क्या किसी भी नोड के लिए कई रास्तों के ग्राफ के लिए क्लोजिंग टेबल उपयुक्त हैं (जैसे एक श्रेणी पदानुक्रम जहां कोई भी पत्ती या गैर-पत्ती नोड एक से अधिक माता-पिता से संबंधित हो सकता है)
उपयोगकर्ता

2
@ रेज़ा, ताकि यदि आप एक नया बच्चा नोड जोड़ते हैं, तो आप (1) के सभी वंशजों के लिए क्वेरी कर सकते हैं और वे नए बच्चे के पूर्वज हैं।
बिल कार्विन 22

58

यदि आप नेस्टेड सेट (कभी-कभी संशोधित प्री-ऑर्डर ट्री ट्रावर्सल के रूप में संदर्भित) का उपयोग करते हैं, तो आप आवेषण के मूल्य पर, एक ही क्वेरी के साथ ट्री ऑर्डर में पूरी ट्री संरचना या उसके भीतर कोई भी उपप्रकार निकाल सकते हैं, जैसा कि आपको ज़रूरत है स्तंभों का प्रबंधन करें जो आपको पेड़ की संरचना के माध्यम से एक इन-ऑर्डर पथ का वर्णन करते हैं।

के लिए Django-mptt , मैं इस तरह एक संरचना का प्रयोग किया:

आईडी पेरेंट_ड ट्री_ड लेफ्ट लिफ्ट रथ
- --------- ------- ----- --- ----
 १ नल १ ० १ १४
 2 1 1 1 2 7
 3 2 1 2 3 4
 4 2 1 2 5 6
 5 1 1 1 8 13
 6 5 1 2 9 10
 7 5 1 2 11 12

जो एक पेड़ का वर्णन करता है जो इस तरह दिखता है ( idप्रत्येक आइटम का प्रतिनिधित्व करने के साथ ):

 1
 + - २
 | + - ३
 | + - 4
 |
 + - 5
     + - 6
     + - 7

या, एक नेस्टेड सेट आरेख के रूप में जो इसे और अधिक स्पष्ट करता है कि कैसे lftऔर rghtमान काम करते हैं:

 __________________________________________________________________________
| जड़ १ |
| ________________________________ ________________________________ |
| | बच्चा 1.1 | | बच्चा 1.2 | |
| | ___________ ___________ | | ___________ ___________ | |
| | | सी 1.1.1 | | C 1.1.2 | | | | C 1.2.1 | | C 1.2.2 | | |
1 2 3___________4 5___________6 7 8 9___________10 11__________12 13 14
| | ________________________________ | | ________________________________ | |
| __________________________________________________________________________ |

आप देख सकते हैं, किसी दिए गए नोड के लिए पूरे सबट्री प्राप्त करने के लिए, पेड़ के क्रम में, आप बस जो है सभी पंक्तियों का चयन करने के लिए है lftऔर rghtइसके बीच मूल्यों lftऔर rghtमूल्यों। किसी दिए गए नोड के लिए पूर्वजों के पेड़ को प्राप्त करना भी सरल है।

levelस्तंभ भी चीज से ज्यादा सुविधा के लिए denormalisation का एक सा है और tree_idस्तंभ को रिस्टार्ट करने के लिए अनुमति देता है lftऔर rghtके रूप में, प्रत्येक शीर्ष स्तर नोड, जो आवेषण, चलता रहता है और विलोपन से प्रभावित स्तंभों की संख्या कम कर देता है के लिए नंबर lftऔर rghtकॉलम होना जरूरी तदनुसार समायोजित किया जाता है जब ये ऑपरेशन अंतराल बनाने या बंद करने के लिए होते हैं। मैंने उस समय कुछ विकास नोट किए जब मैं प्रत्येक ऑपरेशन के लिए आवश्यक प्रश्नों के चारों ओर अपना सिर लपेटने की कोशिश कर रहा था।

वास्तव में एक पेड़ को प्रदर्शित करने के लिए इस डेटा के साथ काम करने के संदर्भ में, मैंने एक tree_item_iteratorउपयोगिता फ़ंक्शन बनाया , जो प्रत्येक नोड के लिए, आपको पर्याप्त जानकारी प्रदान करनी चाहिए कि आप किस प्रकार का डिस्प्ले चाहते हैं।

MPTT के बारे में अधिक जानकारी:


9
मैं हम जैसे संक्षिप्त रूपों का उपयोग कर बंद कर देंगे इच्छा lftऔर rghtस्तंभ नाम के लिए, मेरा मतलब है हम टाइप करने के लिए नहीं था कि कितने वर्ण? एक?!
orustammanapov

21

यह एक बहुत पुराना सवाल है, लेकिन जैसा कि मुझे लगता है कि यह एक विकल्प पेश करने के लायक है, और मेरी राय में बहुत ही सुरुचिपूर्ण, समाधान है।

एक पेड़ की संरचना को पढ़ने के लिए आप पुनरावर्ती कॉमन टेबल एक्सप्रेशंस (सीटीई) का उपयोग कर सकते हैं । यह एक ही समय में पूरे पेड़ की संरचना लाने की संभावना देता है, नोड के स्तर, उसके मूल नोड और माता-पिता नोड के बच्चों के भीतर आदेश के बारे में जानकारी है।

मुझे दिखाते हैं कि यह PostgreSQL 9.1 में कैसे काम करेगा।

  1. एक संरचना बनाएँ

    CREATE TABLE tree (
        id int  NOT NULL,
        name varchar(32)  NOT NULL,
        parent_id int  NULL,
        node_order int  NOT NULL,
        CONSTRAINT tree_pk PRIMARY KEY (id),
        CONSTRAINT tree_tree_fk FOREIGN KEY (parent_id) 
          REFERENCES tree (id) NOT DEFERRABLE
    );
    
    
    insert into tree values
      (0, 'ROOT', NULL, 0),
      (1, 'Node 1', 0, 10),
      (2, 'Node 1.1', 1, 10),
      (3, 'Node 2', 0, 20),
      (4, 'Node 1.1.1', 2, 10),
      (5, 'Node 2.1', 3, 10),
      (6, 'Node 1.2', 1, 20);
  2. एक प्रश्न लिखें

    WITH RECURSIVE 
    tree_search (id, name, level, parent_id, node_order) AS (
      SELECT 
        id, 
        name,
        0,
        parent_id, 
        1 
      FROM tree
      WHERE parent_id is NULL
    
      UNION ALL 
      SELECT 
        t.id, 
        t.name,
        ts.level + 1, 
        ts.id, 
        t.node_order 
      FROM tree t, tree_search ts 
      WHERE t.parent_id = ts.id 
    ) 
    SELECT * FROM tree_search 
    WHERE level > 0 
    ORDER BY level, parent_id, node_order;

    यहाँ परिणाम हैं:

     id |    name    | level | parent_id | node_order 
    ----+------------+-------+-----------+------------
      1 | Node 1     |     1 |         0 |         10
      3 | Node 2     |     1 |         0 |         20
      2 | Node 1.1   |     2 |         1 |         10
      6 | Node 1.2   |     2 |         1 |         20
      5 | Node 2.1   |     2 |         3 |         10
      4 | Node 1.1.1 |     3 |         2 |         10
    (6 rows)

    ट्री नोड्स को गहराई के स्तर से आदेश दिया जाता है। अंतिम आउटपुट में हम उन्हें बाद की पंक्तियों में प्रस्तुत करेंगे।

    प्रत्येक स्तर के लिए, उन्हें पेरेंट के भीतर parent_id और node_order द्वारा ऑर्डर किया जाता है। यह हमें बताता है कि उन्हें आउटपुट में कैसे प्रस्तुत किया जाए - नोड को इस क्रम में लिंक करें।

    ऐसी संरचना होने से HTML में वास्तव में अच्छी प्रस्तुति देना मुश्किल नहीं होगा।

    पुनरावर्ती CTEs PostgreSQL, IBM DB2, MS SQL सर्वर और Oracle में उपलब्ध हैं

    यदि आप पुनरावर्ती SQL प्रश्नों पर अधिक पढ़ना चाहते हैं, तो आप या तो अपने पसंदीदा DBMS के प्रलेखन की जांच कर सकते हैं या इस विषय पर मेरे दो लेख पढ़ सकते हैं:


18

Oracle 9i के रूप में, आप CONNECT BY का उपयोग कर सकते हैं।

SELECT LPAD(' ', (LEVEL - 1) * 4) || "Name" AS "Name"
FROM (SELECT * FROM TMP_NODE ORDER BY "Order")
CONNECT BY PRIOR "Id" = "ParentId"
START WITH "Id" IN (SELECT "Id" FROM TMP_NODE WHERE "ParentId" = 0)

SQL सर्वर 2005 के रूप में, आप पुनरावर्ती सामान्य तालिका अभिव्यक्ति (CTE) का उपयोग कर सकते हैं।

WITH [NodeList] (
  [Id]
  , [ParentId]
  , [Level]
  , [Order]
) AS (
  SELECT [Node].[Id]
    , [Node].[ParentId]
    , 0 AS [Level]
    , CONVERT([varchar](MAX), [Node].[Order]) AS [Order]
  FROM [Node]
  WHERE [Node].[ParentId] = 0
  UNION ALL
  SELECT [Node].[Id]
    , [Node].[ParentId]
    , [NodeList].[Level] + 1 AS [Level]
    , [NodeList].[Order] + '|'
      + CONVERT([varchar](MAX), [Node].[Order]) AS [Order]
  FROM [Node]
    INNER JOIN [NodeList] ON [NodeList].[Id] = [Node].[ParentId]
) SELECT REPLICATE(' ', [NodeList].[Level] * 4) + [Node].[Name] AS [Name]
FROM [Node]
  INNER JOIN [NodeList] ON [NodeList].[Id] = [Node].[Id]
ORDER BY [NodeList].[Order]

दोनों निम्नलिखित परिणामों का उत्पादन करेंगे।

नाम
'नोड 1'
'नोड 1.1'
'नोड 1.1.1'
'नोड 1.2'
'नोड 2'
'नोड 2.1'

cte का उपयोग sqlserver और oracle दोनों में किया जा सकता है @ Eric Weilnau
निसार

9

बिल का जवाब बहुत ही गॉश है - अच्छा, यह जवाब इसमें कुछ बातें जोड़ता है जिससे मुझे SO समर्थित थ्रेडेड उत्तर की इच्छा होती है।

वैसे भी मैं पेड़ की संरचना और ऑर्डर की संपत्ति का समर्थन करना चाहता था। मैंने प्रत्येक नोड में एक एकल संपत्ति को शामिल किया, जिसे कहा जाता है leftSiblingकि Orderमूल प्रश्न में वही काम करना है (बाएं से दाएं क्रम को बनाए रखना)।

mysql> desc nodes;
+ ------------- + -------------- + ------ + ----- + ------- - + ---------------- +
| मैदान | प्रकार | नल | कुंजी | डिफ़ॉल्ट | अतिरिक्त |
+ ------------- + -------------- + ------ + ----- + ------- - + ---------------- +
| आईडी | int (11) | नहीं | PRI | नल | auto_increment |
| नाम | varchar (255) | हाँ | | नल | |
| बायीं करवट | int (11) | नहीं | | 0 | |
+ ------------- + -------------- + ------ + ----- + ------- - + ---------------- +
सेट में 3 पंक्तियाँ (0.00 सेकंड)

mysql> desc adjacencies;
+ ------------ + --------- + ------ + ----- + --------- + --- ------------- +
| मैदान | प्रकार | नल | कुंजी | डिफ़ॉल्ट | अतिरिक्त |
+ ------------ + --------- + ------ + ----- + --------- + --- ------------- +
| relationId | int (11) | नहीं | PRI | नल | auto_increment |
| माता पिता | int (11) | नहीं | | नल | |
| बच्चा | int (11) | नहीं | | नल | |
| pathLen | int (11) | नहीं | | नल | |
+ ------------ + --------- + ------ + ----- + --------- + --- ------------- +
सेट में 4 पंक्तियाँ (0.00 सेकंड)

मेरे ब्लॉग पर अधिक विवरण और SQL कोड

धन्यवाद विधेयक आपका उत्तर आरंभ करने में सहायक था!


7

अच्छा विकल्प दिया, मैं वस्तुओं का उपयोग कर रहा हूँ। मैं प्रत्येक रिकॉर्ड के लिए एक ऑब्जेक्ट बनाता हूँ जहाँ प्रत्येक ऑब्जेक्ट का एक childrenसंग्रह होता है और उन सभी को एक एशो एरे (/ हैशटेबल) में संग्रहीत करता है जहाँ आईडी कुंजी है। और एक बार संग्रह के माध्यम से ब्लिट्ज, बच्चों को प्रासंगिक बच्चों के क्षेत्रों में जोड़ रहा है। सरल।

लेकिन क्योंकि आप कुछ अच्छे OOP के उपयोग को प्रतिबंधित करके कोई मज़ा नहीं ले रहे हैं, मैं शायद इसके आधार पर पुनरावृति करूँगा:

function PrintLine(int pID, int level)
    foreach record where ParentID == pID
        print level*tabs + record-data
        PrintLine(record.ID, level + 1)

PrintLine(0, 0)

संपादित करें: यह अन्य प्रविष्टियों के एक जोड़े के समान है, लेकिन मुझे लगता है कि यह थोड़ा साफ है। एक चीज़ जो मैं जोड़ूंगा: यह अत्यंत SQL-गहन है। यह बुरा हैयदि आपके पास विकल्प है, तो OOP मार्ग पर जाएं।


यही मेरा मतलब है "नहीं चौखटे" के साथ - आप LINQ का उपयोग कर रहे हैं, क्या आप नहीं हैं? आपके पहले पैराग्राफ के बारे में: परिणाम सेट पहले से ही है, पहले सभी जानकारी को एक नई ऑब्जेक्ट संरचना में कॉपी क्यों करें? (मैं उस तथ्य पर पर्याप्त स्पष्ट नहीं था, क्षमा करें)
टॉमालक

तोमलक - कोई कोड छद्म कोड नहीं है। बेशक आपको उचित चयन और पुनरावृत्तियों में चीजों को तोड़ना होगा ... और एक वास्तविक वाक्यविन्यास! क्यों OOP? क्योंकि आप बिल्कुल संरचना को प्रतिबिंबित कर सकते हैं। यह चीजों को अच्छा रखता है और यह केवल अधिक कुशल (केवल एक का चयन करने के लिए) होता है
ओली

मेरे मन में कोई दोहराया चयन नहीं था। OOP के बारे में: मार्क बेसे ने अपने जवाब में कहा: "आप किसी अन्य डेटा संरचना को हैशमैप के साथ अनुकरण कर सकते हैं, इसलिए यह एक भयानक सीमा नहीं है।" आपका समाधान सही है, लेकिन मुझे लगता है कि OOP के बिना भी कुछ कमरे में सुधार है।
तोमलक

5

यह जल्दी से लिखा गया था, और न तो बहुत सुंदर है और न ही कुशल (साथ ही यह ऑटोबॉक्सीस अलॉट करता है, बीच में परिवर्तित होता है intऔर Integerकष्टप्रद होता है!), लेकिन यह काम करता है।

यह संभवत: नियमों को तोड़ता है क्योंकि मैं अपनी वस्तुओं का निर्माण कर रहा हूं, लेकिन हे मैं इसे वास्तविक कार्य से मोड़ के रूप में कर रहा हूं :)

इससे यह भी माना जाता है कि परिणाम / तालिका पूरी तरह से संरचना में पढ़ी जाती है इससे पहले कि आप नोड्स का निर्माण शुरू करें, जो सैकड़ों पंक्तियों में होने पर सबसे अच्छा समाधान नहीं होगा।

public class Node {

    private Node parent = null;

    private List<Node> children;

    private String name;

    private int id = -1;

    public Node(Node parent, int id, String name) {
        this.parent = parent;
        this.children = new ArrayList<Node>();
        this.name = name;
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void addChild(Node child) {
        children.add(child);
    }

    public List<Node> getChildren() {
        return children;
    }

    public boolean isRoot() {
        return (this.parent == null);
    }

    @Override
    public String toString() {
        return "id=" + id + ", name=" + name + ", parent=" + parent;
    }
}

public class NodeBuilder {

    public static Node build(List<Map<String, String>> input) {

        // maps id of a node to it's Node object
        Map<Integer, Node> nodeMap = new HashMap<Integer, Node>();

        // maps id of a node to the id of it's parent
        Map<Integer, Integer> childParentMap = new HashMap<Integer, Integer>();

        // create special 'root' Node with id=0
        Node root = new Node(null, 0, "root");
        nodeMap.put(root.getId(), root);

        // iterate thru the input
        for (Map<String, String> map : input) {

            // expect each Map to have keys for "id", "name", "parent" ... a
            // real implementation would read from a SQL object or resultset
            int id = Integer.parseInt(map.get("id"));
            String name = map.get("name");
            int parent = Integer.parseInt(map.get("parent"));

            Node node = new Node(null, id, name);
            nodeMap.put(id, node);

            childParentMap.put(id, parent);
        }

        // now that each Node is created, setup the child-parent relationships
        for (Map.Entry<Integer, Integer> entry : childParentMap.entrySet()) {
            int nodeId = entry.getKey();
            int parentId = entry.getValue();

            Node child = nodeMap.get(nodeId);
            Node parent = nodeMap.get(parentId);
            parent.addChild(child);
        }

        return root;
    }
}

public class NodePrinter {

    static void printRootNode(Node root) {
        printNodes(root, 0);
    }

    static void printNodes(Node node, int indentLevel) {

        printNode(node, indentLevel);
        // recurse
        for (Node child : node.getChildren()) {
            printNodes(child, indentLevel + 1);
        }
    }

    static void printNode(Node node, int indentLevel) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < indentLevel; i++) {
            sb.append("\t");
        }
        sb.append(node);

        System.out.println(sb.toString());
    }

    public static void main(String[] args) {

        // setup dummy data
        List<Map<String, String>> resultSet = new ArrayList<Map<String, String>>();
        resultSet.add(newMap("1", "Node 1", "0"));
        resultSet.add(newMap("2", "Node 1.1", "1"));
        resultSet.add(newMap("3", "Node 2", "0"));
        resultSet.add(newMap("4", "Node 1.1.1", "2"));
        resultSet.add(newMap("5", "Node 2.1", "3"));
        resultSet.add(newMap("6", "Node 1.2", "1"));

        Node root = NodeBuilder.build(resultSet);
        printRootNode(root);

    }

    //convenience method for creating our dummy data
    private static Map<String, String> newMap(String id, String name, String parentId) {
        Map<String, String> row = new HashMap<String, String>();
        row.put("id", id);
        row.put("name", name);
        row.put("parent", parentId);
        return row;
    }
}

जब हमेशा बहुत सारे सोर्स कोड प्रस्तुत किए जाते हैं तो मुझे कार्यान्वयन-विशिष्ट भाग से एल्गोरिदम-विशिष्ट भाग को फ़िल्टर करना मुश्किल होता है। इसलिए मैंने एक ऐसा समाधान पूछा जो पहली जगह में भाषा-विशिष्ट नहीं था। लेकिन यह काम करता है, इसलिए आपके समय के लिए धन्यवाद!
तोमलक

मैं देख रहा हूं कि अब आपका क्या मतलब है, अगर यह स्पष्ट नहीं है कि मुख्य एल्गोरिथ्म NodeBuilder.build () में है - मैं शायद इसे संक्षेप में प्रस्तुत करने का बेहतर काम कर सकता था।
मैट बी 20

5

वास्तव में अच्छे समाधान हैं जो एसक्यूएल सूचकांकों के आंतरिक बीट्री प्रतिनिधित्व का फायदा उठाते हैं। यह 1998 के आसपास किए गए कुछ महान शोधों पर आधारित है।

यहाँ एक उदाहरण तालिका (mysql में) है।

CREATE TABLE `node` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `tw` int(10) unsigned NOT NULL,
  `pa` int(10) unsigned DEFAULT NULL,
  `sz` int(10) unsigned DEFAULT NULL,
  `nc` int(11) GENERATED ALWAYS AS (tw+sz) STORED,
  PRIMARY KEY (`id`),
  KEY `node_tw_index` (`tw`),
  KEY `node_pa_index` (`pa`),
  KEY `node_nc_index` (`nc`),
  CONSTRAINT `node_pa_fk` FOREIGN KEY (`pa`) REFERENCES `node` (`tw`) ON DELETE CASCADE
)

पेड़ के प्रतिनिधित्व के लिए आवश्यक एकमात्र खेत हैं:

  • ट्विस्ट: द लेफ्ट टू राइट डीएफएस प्री-ऑर्डर इंडेक्स, जहां रूट = 1।
  • पा: संदर्भ (जुड़वाँ) का उपयोग मूल नोड के लिए, रूट में अशक्त है।
  • sz: नोड की शाखा का आकार सहित।
  • nc: सिंटैक्टिक शुगर के रूप में प्रयोग किया जाता है। यह tw + nc है और नोड के "अगले बच्चे" के ट्विस्ट का प्रतिनिधित्व करता है।

यहाँ एक उदाहरण 24 नोड जनसंख्या है, जो ट्विन द्वारा क्रमबद्ध है:

+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|   1 | Root    |  1 | NULL |   24 |   25 |
|   2 | A       |  2 |    1 |   14 |   16 |
|   3 | AA      |  3 |    2 |    1 |    4 |
|   4 | AB      |  4 |    2 |    7 |   11 |
|   5 | ABA     |  5 |    4 |    1 |    6 |
|   6 | ABB     |  6 |    4 |    3 |    9 |
|   7 | ABBA    |  7 |    6 |    1 |    8 |
|   8 | ABBB    |  8 |    6 |    1 |    9 |
|   9 | ABC     |  9 |    4 |    2 |   11 |
|  10 | ABCD    | 10 |    9 |    1 |   11 |
|  11 | AC      | 11 |    2 |    4 |   15 |
|  12 | ACA     | 12 |   11 |    2 |   14 |
|  13 | ACAA    | 13 |   12 |    1 |   14 |
|  14 | ACB     | 14 |   11 |    1 |   15 |
|  15 | AD      | 15 |    2 |    1 |   16 |
|  16 | B       | 16 |    1 |    1 |   17 |
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
|  18 | D       | 23 |    1 |    1 |   24 |
|  19 | E       | 24 |    1 |    1 |   25 |
+-----+---------+----+------+------+------+

प्रत्येक पेड़ का परिणाम गैर-पुनरावर्ती रूप से किया जा सकता है। उदाहरण के लिए, tw = '22 'पर नोड के पूर्वजों की सूची प्राप्त करना

पूर्वजों

select anc.* from node me,node anc 
where me.tw=22 and anc.nc >= me.tw and anc.tw <= me.tw 
order by anc.tw;
+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|   1 | Root    |  1 | NULL |   24 |   25 |
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
+-----+---------+----+------+------+------+

भाई-बहन और बच्चे तुच्छ होते हैं - बस पा फील्ड का इस्तेमाल करते हैं।

वंशज

उदाहरण के लिए नोड्स का सेट (शाखा) जो = 17 पर निहित है।

select des.* from node me,node des 
where me.tw=17 and des.tw < me.nc and des.tw >= me.tw 
order by des.tw;
+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
+-----+---------+----+------+------+------+

अतिरिक्त नोट्स

यह कार्यप्रणाली तब बहुत उपयोगी होती है जब आवेषण या अपडेट की तुलना में कहीं अधिक संख्या में रीड होते हैं।

क्योंकि पेड़ में एक नोड के सम्मिलन, आंदोलन या अद्यतन के लिए पेड़ को समायोजित करने की आवश्यकता होती है, कार्रवाई के साथ शुरू करने से पहले तालिका को लॉक करना आवश्यक है।

सम्मिलन / विलोपन की लागत अधिक है क्योंकि सम्मिलन बिंदु के बाद और सभी पूर्वजों के लिए ट्विन इंडेक्स और sz (शाखा आकार) मान सभी नोड्स पर अपडेट किए जाने की आवश्यकता होगी।

ब्रांच मूविंग में ब्रांच के ट्विन मान को रेंज से बाहर ले जाना शामिल होता है, इसलिए ब्रांच को मूव करते समय विदेशी कुंजी बाधाओं को अक्षम करना भी आवश्यक है। शाखा को स्थानांतरित करने के लिए आवश्यक चार प्रश्न हैं:

  • शाखा को सीमा से बाहर ले जाएं।
  • वह अंतर छोड़ दें जिसे उसने छोड़ा था। (शेष पेड़ अब सामान्यीकृत है)।
  • वह अंतर खोलें जहां वह जाएगा।
  • शाखा को नई स्थिति में ले जाएं।

ट्री क्वेरी समायोजित करें

पेड़ में अंतराल को खोलना / बंद करना, बनाने / अद्यतन / हटाने के तरीकों द्वारा उपयोग किया जाने वाला एक महत्वपूर्ण उप-कार्य है, इसलिए मैं इसे यहाँ शामिल करता हूँ।

हमें दो मापदंडों की आवश्यकता है - एक झंडे का प्रतिनिधित्व करना, चाहे हम डाउनसाइज़िंग या अपसाइज़िंग कर रहे हों और नोड्स ट्विन इंडेक्स। इसलिए, उदाहरण के लिए ट्वि = 18 (जिसकी शाखा का आकार 5 है)। चलिए मान लेते हैं कि हम नीचे (tw को हटा रहे हैं) - इसका मतलब है कि हम निम्नलिखित उदाहरण के अपडेट में '+' के बजाय '-' का उपयोग कर रहे हैं।

हम पहले sz मूल्य को अद्यतन करने के लिए (थोड़ा परिवर्तित) पूर्वज फ़ंक्शन का उपयोग करते हैं।

update node me, node anc set anc.sz = anc.sz - me.sz from 
node me, node anc where me.tw=18 
and ((anc.nc >= me.tw and anc.tw < me.pa) or (anc.tw=me.pa));

फिर हमें उन लोगों के लिए ट्विस्ट को समायोजित करने की आवश्यकता है, जिनके ट्विस्ट को निकाले जाने वाली शाखा से अधिक है।

update node me, node anc set anc.tw = anc.tw - me.sz from 
node me, node anc where me.tw=18 and anc.tw >= me.tw;

फिर हमें उन अभिभावकों को समायोजित करने की आवश्यकता है जिनके पा के ट्विस्ट को हटाए जाने वाली शाखा से अधिक है।

update node me, node anc set anc.pa = anc.pa - me.sz from 
node me, node anc where me.tw=18 and anc.pa >= me.tw;

3

यह मानते हुए कि आप जानते हैं कि मूल तत्व शून्य हैं, यहां पाठ के आउटपुट के लिए छद्मकोश है:

function PrintLevel (int curr, int level)
    //print the indents
    for (i=1; i<=level; i++)
        print a tab
    print curr \n;
    for each child in the table with a parent of curr
        PrintLevel (child, level+1)


for each elementID where the parentid is zero
    PrintLevel(elementID, 0)

3

आप हैशमैप के साथ किसी अन्य डेटा संरचना का अनुकरण कर सकते हैं, इसलिए यह एक भयानक सीमा नहीं है। ऊपर से नीचे की ओर स्कैन करते हुए, आप डेटाबेस की प्रत्येक पंक्ति के लिए प्रत्येक कॉलम के लिए एक प्रविष्टि के साथ एक हैशमैप बनाते हैं। इनमें से प्रत्येक हैशमैप को एक "मास्टर" हैशमैप में जोड़ें, जो आईडी पर रखा गया है। यदि किसी नोड में एक "अभिभावक" है जिसे आपने अभी तक नहीं देखा है, तो मास्टर हैशमैप में इसके लिए एक प्लेसहोल्डर प्रविष्टि बनाएं, और वास्तविक नोड देखने पर इसे भरें।

इसे प्रिंट करने के लिए, एक सरल गहराई-पहले डेटा के माध्यम से गुजरें, रास्ते में इंडेंट स्तर का ध्यान रखें। आप प्रत्येक पंक्ति के लिए "बच्चों" की प्रविष्टि रखकर, और डेटा को स्कैन करते समय इसे पॉप्युलेट करके इसे आसान बना सकते हैं।

डेटाबेस में एक पेड़ को स्टोर करने के लिए "बेहतर" तरीका है या नहीं, इस पर निर्भर करता है कि आप डेटा का उपयोग कैसे करने जा रहे हैं। मैंने ऐसी प्रणालियाँ देखी हैं जिनमें एक अधिकतम ज्ञात गहराई थी जो पदानुक्रम में प्रत्येक स्तर के लिए एक अलग तालिका का उपयोग करती थी। यह बहुत मायने रखता है अगर पेड़ के स्तर सभी के बाद काफी समान नहीं हैं (शीर्ष स्तर की श्रेणियां पत्तियों की तुलना में अलग हैं)।


1

अगर नेस्टेड हैश मैप या एरेज़ बनाए जा सकते हैं, तो मैं बस शुरुआत से टेबल के नीचे जा सकता हूं और प्रत्येक आइटम को नेस्टेड सरणी में जोड़ सकता हूं। मुझे रूट नोड में प्रत्येक पंक्ति का पता लगाना चाहिए ताकि पता लगाया जा सके कि नेस्टेड सरणी में किस स्तर को सम्मिलित करना है। मैं संस्मरण को नियोजित कर सकता हूं ताकि मुझे बार-बार एक ही माता-पिता को देखने की आवश्यकता न हो।

संपादित करें: मैं पूरी सारणी को पहले एक सरणी में पढ़ूंगा, इसलिए यह DB को बार-बार क्वेरी नहीं करेगा। यदि आपकी मेज बहुत बड़ी है, तो बेशक यह व्यावहारिक नहीं होगा।

संरचना निर्मित होने के बाद, मुझे इसके माध्यम से पहले गहराई का पता लगाना चाहिए और HTML का प्रिंट आउट लेना चाहिए।

एक टेबल का उपयोग करके इस जानकारी को संग्रहीत करने का कोई बेहतर मौलिक तरीका नहीं है (मैं हालांकि गलत हो सकता है;), और एक बेहतर समाधान देखना पसंद करूंगा)। हालाँकि, यदि आप गतिशील रूप से निर्मित db तालिकाओं को नियोजित करने के लिए एक योजना बनाते हैं, तो आपने सादगी के बलिदान, और SQL नरक के जोखिम पर एक पूरी नई दुनिया खोली;)।


1
मैं केवल DB लेआउट को नहीं बदलूंगा क्योंकि उप-नोड्स के एक नए स्तर की आवश्यकता है। :-)
टॉमालक

1

यदि तत्व ट्री ऑर्डर में हैं, जैसा कि आपके उदाहरण में दिखाया गया है, तो आप निम्न पायथन उदाहरण की तरह कुछ का उपयोग कर सकते हैं:

delimiter = '.'
stack = []
for item in items:
  while stack and not item.startswith(stack[-1]+delimiter):
    print "</div>"
    stack.pop()
  print "<div>"
  print item
  stack.append(item)

यह जो करता है वह पेड़ में वर्तमान स्थिति का प्रतिनिधित्व करने वाले ढेर को बनाए रखता है। तालिका में प्रत्येक तत्व के लिए, यह स्टैक तत्वों (मेल खाते को बंद करना) को तब तक पॉप करता है जब तक कि यह वर्तमान आइटम के माता-पिता को नहीं मिल जाता। फिर यह उस नोड की शुरुआत को आउटपुट करता है और स्टैक पर धकेलता है।

यदि आप नेस्टेड तत्वों के बजाय इंडेंटिंग का उपयोग करके पेड़ का उत्पादन करना चाहते हैं, तो आप बस डीव को प्रिंट करने के लिए प्रिंट स्टेटमेंट्स को छोड़ सकते हैं, और प्रत्येक आइटम से पहले स्टैक के कुछ कई आकार के बराबर कई रिक्त स्थान प्रिंट कर सकते हैं। उदाहरण के लिए, पायथन में:

print "  " * len(stack)

आप नेस्टेड सूचियों या शब्दकोशों के सेट के निर्माण के लिए भी आसानी से इस विधि का उपयोग कर सकते हैं।

संपादित करें: मैं आपके स्पष्टीकरण से देखता हूं कि नाम नोड पथ होने का इरादा नहीं थे। यह एक वैकल्पिक दृष्टिकोण बताता है:

idx = {}
idx[0] = []
for node in results:
  child_list = []
  idx[node.Id] = child_list
  idx[node.ParentId].append((node, child_list))

यह टुपल्स (!) के सरणियों के एक पेड़ का निर्माण करता है। idx [0] पेड़ की जड़ (ओं) का प्रतिनिधित्व करता है। एक सरणी में प्रत्येक तत्व नोड से मिलकर 2-ट्यूपल है और इसके सभी बच्चों की सूची है। एक बार निर्माण करने के बाद, आप idx [0] पर रोक सकते हैं और idx को छोड़ सकते हैं, जब तक कि आप उनकी आईडी से नोड्स एक्सेस नहीं करना चाहते।


1

बिल के एसक्यूएल समाधान को बढ़ाने के लिए आप मूल रूप से एक फ्लैट सरणी का उपयोग कर सकते हैं। इसके अलावा अगर आपके तार सभी समान हैं और आपके बच्चों की अधिकतम संख्या ज्ञात है (बाइनरी ट्री में कहें) तो आप इसे एक स्ट्रिंग (वर्ण सरणी) का उपयोग करके कर सकते हैं। यदि आपके पास बच्चों की मनमानी संख्या है तो यह चीजों को थोड़ा जटिल करता है ... मुझे यह देखने के लिए अपने पुराने नोटों की जांच करनी होगी कि क्या किया जा सकता है।

फिर, थोड़ी स्मृति का त्याग करते हुए, खासकर यदि आपका पेड़ विरल और / या अनियंत्रित है, तो आप थोड़ा सा सूचकांक गणित के साथ, अपने पेड़ को स्टोर करके यादृच्छिक रूप से सभी तारों का उपयोग कर सकते हैं, इस तरह से सरणी में चौड़ाई पहले (बाइनरी के लिए) पेड़):

String[] nodeArray = [L0root, L1child1, L1child2, L2Child1, L2Child2, L2Child3, L2Child4] ...

यो अपनी स्ट्रिंग की लंबाई जानते हैं, आप इसे जानते हैं

मैं अभी काम कर रहा हूं इसलिए इस पर ज्यादा समय नहीं दे सकता हूं लेकिन ब्याज के साथ ऐसा करने के लिए मैं थोड़ा सा कोड ला सकता हूं।

हम इसका उपयोग डीएनए कोडों से बने द्विआधारी पेड़ों में खोज करने के लिए करते हैं, एक प्रक्रिया पेड़ का निर्माण करती है, फिर हमने इसे पाठ पैटर्न खोजने के लिए चपटा किया और जब मिला, हालांकि सूचकांक गणित (ऊपर से उलट) हमें नोड वापस मिलता है ... बहुत तेजी से और कुशल, कठिन हमारे पेड़ में शायद ही कभी खाली नोड्स थे, लेकिन हम एक पल में डेटा के गीगाबाइट का पता लगा सकते थे।


0

पदानुक्रमित संरचनाओं के लिए neo4j जैसे nosql टूल का उपयोग करने के बारे में सोचें। उदाहरण के लिए लिंक्डिन की तरह एक नेटवर्क अनुप्रयोग couchbase (एक और nosql समाधान) का उपयोग करता है

लेकिन केवल डेटा-मार्ट स्तर के प्रश्नों के लिए nosql का उपयोग करें और लेनदेन को संग्रहीत / बनाए रखने के लिए नहीं


एसक्यूएल और "गैर-टेबल" संरचनाओं की जटिलताओं और पूर्णता को पढ़ने के बाद, यह मेरा पहला विचार भी था, नोसक्ल। बेशक, निर्यात आदि के लिए बहुत सारे मुद्दे हैं, प्लस, ओपी ने केवल तालिकाओं का उल्लेख किया है। ओह अच्छा। मैं एक डीबी विशेषज्ञ नहीं हूं, जैसा कि स्पष्ट है।
जोसेफ़.बी।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.