রিলেশনাল ডাটাবেসে হায়ারারিকাল ডেটা সংরক্ষণ করার বিকল্পগুলি কী কী? [বন্ধ]


1333

ভাল ওভারভিউ

সাধারণভাবে বলতে গেলে, আপনি দ্রুত পঠনের সময় (উদাহরণস্বরূপ, নেস্টেট সেট) বা দ্রুত লেখার সময় (সংলগ্ন তালিকা) এর মধ্যে সিদ্ধান্ত নিচ্ছেন। সাধারণত, আপনি নীচের বিকল্পগুলির সংমিশ্রণটি দিয়ে শেষ করেন যা আপনার প্রয়োজনগুলির সাথে সবচেয়ে উপযুক্ত। নিম্নলিখিতটি কিছু গভীরভাবে পাঠ সরবরাহ করে:

বিকল্প

আমার সম্পর্কে এবং সাধারণ বৈশিষ্ট্য সম্পর্কে আমি সচেতন:

  1. সংলগ্ন তালিকা :
    • কলাম: আইডি, প্যারেন্টআইডি
    • কার্যকর করা সহজ।
    • সস্তা নোড সরানো, সন্নিবেশ করানো এবং মুছে ফেলা।
    • স্তর, পূর্বপুরুষ এবং উত্তরসূরিদের পথ খুঁজে পাওয়া ব্যয়বহুল
    • তাদের সমর্থন করে এমন ডেটাবেজে সাধারণ টেবিল এক্সপ্রেশনগুলির মাধ্যমে এন + 1 এড়িয়ে চলুন
  2. নেস্টেড সেট (ওরফে মডিফায়েড প্রির্ডার ট্রি ট্রিভারসাল )
    • কলাম: বাম, ডান
    • সস্তা পিতৃপুরুষ, বংশধররা
    • O(n/2)অস্থির এনকোডিংয়ের কারণে খুব ব্যয়বহুল চাল, সন্নিবেশগুলি, মোছা
  3. ব্রিজ টেবিল (ওরফে ক্লোজার টেবিল / ডাব্লু ট্রিগার )
    • এর সাথে পৃথক যোগদানের টেবিল ব্যবহার করুন: পূর্বপুরুষ, বংশধর, গভীরতা (alচ্ছিক)
    • সস্তা পিতৃপুরুষ এবং বংশধররা
    • O(log n)সন্নিবেশ, আপডেট, মুছে ফেলার জন্য ব্যয় (সাবট্রি আকার) লিখেছেন
    • সাধারণ এনকোডিং: যোগদানের জন্য আরডিবিএমএস পরিসংখ্যান এবং কোয়েরি পরিকল্পনাকারীর পক্ষে ভাল
    • নোড প্রতি একাধিক সারি প্রয়োজন
  4. বংশ কলাম (ওরফে ম্যাটেরিয়ালাইজড পাথ , পাথের গণনা)
    • কলাম: বংশ (যেমন / পিতামাতা / শিশু / নাতি / ইত্যাদি ...)
    • উপসর্গ ক্যোয়ারির মাধ্যমে সস্তা বংশধর (উদাঃ LEFT(lineage, #) = '/enumerated/path')
    • O(log n)সন্নিবেশ, আপডেট, মুছে ফেলার জন্য ব্যয় (সাবট্রি আকার) লিখেছেন
    • সম্পর্কহীন: অ্যারে ডেটাটাইপ বা সিরিয়ালযুক্ত স্ট্রিং বিন্যাসের উপর নির্ভর করে
  5. নেস্টেড অন্তর
    • নেস্টেড সেটের মতো, তবে আসল / ফ্লোট / দশমিক সহ যাতে এনকোডিংটি অস্থির হয় না (সস্তা চাল / সন্নিবেশ / মোছা)
    • বাস্তব / ভাসা / দশমিক প্রতিনিধিত্ব / যথার্থ সমস্যা আছে
    • ম্যাট্রিক্স এনকোডিং বৈকল্পিক "ফ্রি" এর জন্য পূর্বপুরুষের এনকোডিং (উপাদানযুক্ত পথ) যুক্ত করে, তবে রৈখিক বীজগণিতের যুক্ত কৌশল সহ।
  6. ফ্ল্যাট টেবিল
    • একটি সংশোধিত অ্যাডজ্যাসেন্সি তালিকা যা প্রতিটি রেকর্ডে একটি স্তর এবং র‌্যাঙ্ক (যেমন ক্রম) কলাম যুক্ত করে।
    • পুনরাবৃত্তি করা / প্যাগিনেটে সস্তা
    • ব্যয়বহুল পদক্ষেপ এবং মুছুন
    • ভাল ব্যবহার: থ্রেডেড আলোচনা - ফোরাম / ব্লগ মন্তব্য
  7. একাধিক বংশ কলাম
    • কলাম: প্রতিটি বংশ স্তরের জন্য একটি, মূল পর্যন্ত সমস্ত পিতামাতাকে বোঝায়, আইটেমের স্তর থেকে নীচে স্তরগুলিকে NULL এ সেট করা হয়
    • সস্তা পূর্বপুরুষ, বংশধর, স্তর
    • সস্তার সন্নিবেশ, মুছুন, পাতার সরানো
    • অভ্যন্তরীণ নোডগুলির ব্যয়বহুল সন্নিবেশ, মোছা, সরানো
    • শ্রেণিবদ্ধতা কত গভীর হতে পারে তার সীমাবদ্ধতা

ডাটাবেস নির্দিষ্ট নোট

মাইএসকিউএল

আকাশবাণী

  • অ্যাডজেন্সি তালিকাগুলি অতিক্রম করতে সংযুক্ত বাই ব্যবহার করুন

পোস্টগ্রি

SQL সার্ভার


5
স্লাইডসরেটনেট / বিলকারউইন / এসকিএলএন্টিপ্যাটার্নস স্ট্রাইক- ব্যাক পৃষ্ঠা to 77 অনুসারে , এবং ব্যবহারের সহজতার ক্ষেত্রে (এবং আমি পারফরম্যান্সও অনুমান করছি) Closure Tablesare Adjacency ListPath EnumerationNested Sets
গিলি

আমি এখানে খুব সাধারণ সংস্করণটি মিস করছি: একটি সাধারণ বিএলওবি। যদি আপনার শ্রেণিবিন্যাসের কয়েকটি আইটেম থাকে তবে আইডির একটি সিরিয়ালযুক্ত গাছ সেরা বিকল্প হতে পারে।
লোথার

@ লোথার: প্রশ্নটি একটি সম্প্রদায়ের উইকি তাই এতে নির্দ্বিধায় পড়ুন। এই বিষয়ে আমার ধারণাটি হ'ল আমি কেবল সেই ডাটাবেসগুলির সাথে এটি করব যা এক্সপ্যাথের মতো একটি স্থিতিশীল কোয়েরি ভাষার সাথে এক্সএমএল হিসাবে কোনও প্রকারের ব্লব স্ট্রাকচারিং সমর্থন করে। অন্যথায় আমি এসকিউএল নয়, পুনরুদ্ধার, deserialize এবং কোডে munge বাদে কোয়েরি করার একটি ভাল উপায় দেখতে পাচ্ছি না। এবং যদি আপনার সত্যিই এমন সমস্যা হয় যেখানে আপনার অনেকগুলি স্বেচ্ছাসেবী উপাদানগুলির প্রয়োজন হয় তবে আপনি নো 4 জ এর মতো নোড ডাটাবেস ব্যবহার করা থেকে ভাল হতে পারেন, যা আমি ব্যবহার করেছি এবং পছন্দ করেছি, তবে কখনও উত্পাদনের মধ্য দিয়ে নেওয়া হয়নি।
কমলাপিজ


2
"সাধারণ সংক্ষিপ্তসার" এর জন্য এমএসডিএন লিঙ্কটি আর আর্টিকেলটি দেখায় না। এটি এমএসডিএন ম্যাগাজিনের সেপ্টেম্বর ২০০৮ সংস্করণে ছিল, যা আপনি সিএইচএম ফাইল হিসাবে ডাউনলোড করতে পারেন বা ওয়েব সংরক্ষণাগারের মাধ্যমে দেখতে পারেন: web.archive.org/web/20080913041559/http://msdn.microsoft.com:80/ …
kͩeͣmͮpͥ ͩ

উত্তর:


66

আমার প্রিয় উত্তরটি হ'ল এই থ্রেডের প্রথম বাক্যটি যা প্রস্তাব করেছিল। শ্রেণিবদ্ধতা বজায় রাখতে একটি অ্যাডজেসেন্সি তালিকা ব্যবহার করুন এবং শ্রেণিবদ্ধতা অনুসন্ধান করতে নেস্টেড সেট ব্যবহার করুন use

এখনও অবধি সমস্যাটি হ'ল যে অ্যাডজেসেসি তালিকা থেকে নেস্টেড সেটে কভারেজ পদ্ধতিটি ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে চলে আসবে R অ্যাডজেসেন্সি তালিকা এবং নেস্টেড সেটগুলির দুর্দান্ত কার্যকারিতা দ্বারা রক্ষণাবেক্ষণের সরলতার নির্বান পৌঁছাতে। ফলস্বরূপ, বেশিরভাগ লোক একটি বা অন্যটির জন্য স্থিতিশীল হয়ে থাকে বিশেষত যদি বলুন, লুসি 100,000 নোড বা তারও বেশি। পুশ স্ট্যাক পদ্ধতিটি ব্যবহার করে এমএলএম'আররা একটি ছোট মিলিয়ন নোড শ্রেণিবদ্ধ হিসাবে বিবেচনা করবে তার রূপান্তর করতে পুরো দিন সময় নিতে পারে।

আমি ভেবেছিলাম যে সেলকোকে একটি অ্যাডজেসেন্সি তালিকাটি নেস্টেট সেটে গতিতে রূপান্তর করতে একটি পদ্ধতি নিয়ে এসেছিল যা কেবল অসম্ভব বলে মনে হচ্ছে। আমার আই 5 ল্যাপটপে পুশ স্ট্যাক পদ্ধতির কর্মক্ষমতা এখানে।

Duration for     1,000 Nodes = 00:00:00:870 
Duration for    10,000 Nodes = 00:01:01:783 (70 times slower instead of just 10)
Duration for   100,000 Nodes = 00:49:59:730 (3,446 times slower instead of just 100) 
Duration for 1,000,000 Nodes = 'Didn't even try this'

এবং এখানে নতুন পদ্ধতির সময়কাল (প্রথম বন্ধনীতে পুশ স্ট্যাক পদ্ধতি সহ)।

Duration for     1,000 Nodes = 00:00:00:053 (compared to 00:00:00:870)
Duration for    10,000 Nodes = 00:00:00:323 (compared to 00:01:01:783)
Duration for   100,000 Nodes = 00:00:03:867 (compared to 00:49:59:730)
Duration for 1,000,000 Nodes = 00:00:54:283 (compared to something like 2 days!!!)

হ্যাঁ, এটা সঠিক। 1 মিলিয়ন নোড এক সেকেন্ডেরও কম এবং 100 সেকেন্ডের মধ্যে 4,000 সেকেন্ডের মধ্যে নূন্য রূপান্তরিত হয়।

আপনি নতুন পদ্ধতি সম্পর্কে পড়তে পারেন এবং নীচের ইউআরএলে কোডের একটি অনুলিপি পেতে পারেন। http://www.sqlservercentral.com/articles/Hierarchy/94040/

আমি একই ধরণের পদ্ধতি ব্যবহার করে একটি "প্রাক-সমষ্টিগত" শ্রেণিবিন্যাসও বিকাশ করেছি। এমএলএম'আর এবং উপকরণ বিল তৈরির লোকেরা এই নিবন্ধটিতে বিশেষভাবে আগ্রহী হবে। http://www.sqlservercentral.com/articles/T-SQL/94570/

যদি আপনি উভয় নিবন্ধটি একবার দেখার জন্য থামেন না, তবে "আলোচনায় যোগ দিন" লিঙ্কটিতে ঝাঁপিয়ে পড়ুন এবং আপনি কী ভাবছেন তা আমাকে জানান।


এমএলমার কী?
ডেভিড মান

এমএলএম = "মাল্টি-লেভেল বিপণন"। এমওয়ে, শাকলি, এসিএন ইত্যাদি ইত্যাদি
জেফ মোডেন

31

এটি আপনার প্রশ্নের একটি খুব আংশিক উত্তর, কিন্তু আমি এখনও দরকারী দরকারী আশা করি।

মাইক্রোসফ্ট এসকিউএল সার্ভার ২০০৮ দুটি বৈশিষ্ট্য প্রয়োগ করে যা শ্রেণিবদ্ধ তথ্য পরিচালনার জন্য অত্যন্ত দরকারী:

  • HierarchyId ডাটা টাইপ।
  • সাধারণ টেবিল এক্সপ্রেশন, কীওয়ার্ড সহ ব্যবহার করে ।

শুরুর জন্য এমএসডিএন-তে কেন্ট টেজেলস দ্বারা "এসকিউএল সার্ভার ২০০৮ সহ আপনার ডেটা হায়ারারচিগুলি মডেল করুন" একবার দেখুন Have আমার নিজের প্রশ্নটিও দেখুন: এসকিউএল সার্ভার ২০০৮ সালে পুনরাবৃত্ত একই টেবিল কোয়েরি


2
আকর্ষণীয়, HierarchyId, যে এক সম্পর্কে জানেন না: msdn.microsoft.com/en-us/library/bb677290.aspx
orangepips

1
প্রকৃতপক্ষে. আমি প্রচুর পুনরাবৃত্তিমূলক শ্রেণিবিন্যাসের ডেটা নিয়ে কাজ করি এবং আমি সাধারণ টেবিলের অভিব্যক্তিটি অত্যন্ত দরকারী বলে মনে করি। একটি ইন্ট্রোটির জন্য এমএসডিএন.মাইক্রোসফটকম /en-us/library/ms186243.aspx দেখুন ।
সিজারগন

28

এই নকশাটি এখনও উল্লেখ করা হয়নি:

একাধিক বংশ কলাম

যদিও এর সীমাবদ্ধতা রয়েছে, আপনি যদি তা সহ্য করতে পারেন তবে এটি খুব সহজ এবং খুব দক্ষ। বৈশিষ্ট্য:

  • কলাম: প্রতিটি বংশ স্তরের জন্য একটি, মূল পর্যন্ত সমস্ত পিতামাতাকে বোঝায়, বর্তমান আইটেমগুলির স্তরের নীচে স্তর 0 (বা NULL) সেট করা হয়েছে
  • শ্রেণিবদ্ধতা কত গভীর হতে পারে তার একটি নির্দিষ্ট সীমা রয়েছে
  • সস্তা পূর্বপুরুষ, বংশধর, স্তর
  • সস্তার সন্নিবেশ, মুছুন, পাতার সরানো
  • অভ্যন্তরীণ নোডগুলির ব্যয়বহুল সন্নিবেশ, মোছা, সরানো

এখানে একটি উদাহরণ অনুসরণ করা হয়েছে - পাখির ট্যাকোনমিক বৃক্ষ যাতে শ্রেণিবদ্ধ হয় শ্রেণি / আদেশ / পরিবার / বংশ / প্রজাতি - প্রজাতি সর্বনিম্ন স্তর, 1 সারি = 1 ট্যাকন (যা পাতার নোডের ক্ষেত্রে প্রজাতির সাথে মিলে যায়):

CREATE TABLE `taxons` (
  `TaxonId` smallint(6) NOT NULL default '0',
  `ClassId` smallint(6) default NULL,
  `OrderId` smallint(6) default NULL,
  `FamilyId` smallint(6) default NULL,
  `GenusId` smallint(6) default NULL,
  `Name` varchar(150) NOT NULL default ''
);

এবং তথ্য উদাহরণ:

+---------+---------+---------+----------+---------+-------------------------------+
| TaxonId | ClassId | OrderId | FamilyId | GenusId | Name                          |
+---------+---------+---------+----------+---------+-------------------------------+
|     254 |       0 |       0 |        0 |       0 | Aves                          |
|     255 |     254 |       0 |        0 |       0 | Gaviiformes                   |
|     256 |     254 |     255 |        0 |       0 | Gaviidae                      |
|     257 |     254 |     255 |      256 |       0 | Gavia                         |
|     258 |     254 |     255 |      256 |     257 | Gavia stellata                |
|     259 |     254 |     255 |      256 |     257 | Gavia arctica                 |
|     260 |     254 |     255 |      256 |     257 | Gavia immer                   |
|     261 |     254 |     255 |      256 |     257 | Gavia adamsii                 |
|     262 |     254 |       0 |        0 |       0 | Podicipediformes              |
|     263 |     254 |     262 |        0 |       0 | Podicipedidae                 |
|     264 |     254 |     262 |      263 |       0 | Tachybaptus                   |

এটি দুর্দান্ত কারণ কারণ আপনি অভ্যন্তরীণ বিভাগগুলি গাছের স্তরে পরিবর্তন না করে যতক্ষণ না আপনি প্রয়োজনীয় সমস্ত কাজগুলি খুব সহজ উপায়ে সম্পন্ন করেন।


22

সংলগ্ন মডেল + নেস্টেড সেট মডেল

আমি এটির জন্য গিয়েছিলাম কারণ আমি সহজেই গাছে নতুন আইটেম sertোকাতে পারতাম (এটিতে একটি নতুন আইটেম সন্নিবেশ করার জন্য আপনার কেবল একটি শাখার আইডি প্রয়োজন) এবং এটি খুব দ্রুত জিজ্ঞাসাও করতে পারি।

+-------------+----------------------+--------+-----+-----+
| category_id | name                 | parent | lft | rgt |
+-------------+----------------------+--------+-----+-----+
|           1 | ELECTRONICS          |   NULL |   1 |  20 |
|           2 | TELEVISIONS          |      1 |   2 |   9 |
|           3 | TUBE                 |      2 |   3 |   4 |
|           4 | LCD                  |      2 |   5 |   6 |
|           5 | PLASMA               |      2 |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |      1 |  10 |  19 |
|           7 | MP3 PLAYERS          |      6 |  11 |  14 |
|           8 | FLASH                |      7 |  12 |  13 |
|           9 | CD PLAYERS           |      6 |  15 |  16 |
|          10 | 2 WAY RADIOS         |      6 |  17 |  18 |
+-------------+----------------------+--------+-----+-----+
  • প্রত্যেকবার আপনার যে কোনও পিতা-মাতার সমস্ত সন্তানের প্রয়োজন হয় কেবল আপনি তার জিজ্ঞাসা করুন parent কলামটি ।
  • আপনার যদি কোনও পিতামাতার সমস্ত বংশধরদের প্রয়োজন হয় তবে আপনি যে আইটেমগুলির lftমধ্যে lftএবং তাদের rgtপিতামাতার মধ্যে রয়েছেন সেগুলির জন্য জিজ্ঞাসা করুন ।
  • আপনি গাছ রুট কোনো নোড আপ সব বাবা প্রয়োজন থাকে, তাহলে আপনি থাকার আইটেম জন্য অনুসন্ধান lftনোড এর চেয়ে কম lftএবং rgtনোড এর চেয়ে বড় rgtএবং সাজানোর দ্বারা parent

সন্নিবেশকারীদের চেয়ে গাছটি অ্যাক্সেস করা এবং দ্রুত জিজ্ঞাসা করা দরকার, এজন্যই আমি এটি বেছে নিয়েছি

একমাত্র সমস্যা হ'ল নতুন আইটেম The োকানোর সময় leftএবং rightকলামগুলি ঠিক করা । ভাল আমি এটির জন্য একটি সঞ্চিত পদ্ধতি তৈরি করেছি এবং প্রতিবারই আমি এটির জন্য একটি নতুন আইটেম প্রবেশ করিয়েছিলাম যা আমার ক্ষেত্রে বিরল তবে এটি সত্যিই দ্রুত। আমি জো সেলকোর বইটি থেকে ধারণাটি পেয়েছি, এবং সঞ্চিত পদ্ধতি এবং কীভাবে আমি এটি নিয়ে এসেছি তা এখানে ডিবিএ এসই https://dba.stackexchange.com/q/89051/41481 এ ব্যাখ্যা করা হয়েছে


3
+1 এটি একটি বৈধ পন্থা। আমার নিজের অভিজ্ঞতা থেকে কী সিদ্ধান্ত নিচ্ছে যে বড় আপডেটের ক্রিয়াকলাপগুলি যখন ঘটে তখন আপনি নোংরা পড়াতে ঠিক আছেন কিনা if যদি তা না হয় তবে এটি একটি বিষয় হয়ে ওঠে বা সরাসরি টেবিল অনুসন্ধান করা থেকে বাধা দেয় এবং সর্বদা একটি API- ডিবি স্প্রোকস / ফাংশন বা কোডের মধ্য দিয়ে যায়।
কমলাপিজ

1
এটি একটি আকর্ষণীয় সমাধান; তবে আমি নিশ্চিত না যে পিতামাতার কলামটি জিজ্ঞাসা করা সত্যিই বড় কোনও সুবিধা দেয় যখন বাচ্চাদের সন্ধান করার চেষ্টা করা হয় - এজন্য আমরা প্রথম স্থানে বাম এবং ডান কলামগুলি রেখেছি।
থমাস

2
@ থমাস, childrenএবং এর মধ্যে পার্থক্য রয়েছে descendantsleftএবং rightবংশধরদের সন্ধান করতে ব্যবহৃত হয়।
আজেফেরতি

14

যদি আপনার ডাটাবেস অ্যারেগুলিকে সমর্থন করে তবে আপনি একটি বংশ কলাম বা প্যারেন্ট আইডসের একটি অ্যারে হিসাবে বস্তুগত পথও প্রয়োগ করতে পারেন।

বিশেষত পোস্টগ্রিসের সাহায্যে আপনি সেট অপারেটরগুলিকে শ্রেণিবদ্ধতা অনুসন্ধান করতে, এবং জিআইএন সূচকগুলির সাথে দুর্দান্ত পারফরম্যান্স পেতে পারেন। এটি একক ক্যোয়ারিতে পিতামাতাদের, শিশুদের এবং গভীরতাটিকে বেশ তুচ্ছ করে তোলে। আপডেটগুলিও বেশ পরিচালনাযোগ্য।

আপনি যদি কৌতূহলী হন তবে মেটেরিয়াল পাথের জন্য অ্যারেগুলি ব্যবহার করার আমার সম্পূর্ণ লিখন আছে ।


9

এটি সত্যিই একটি বর্গক্ষেত্রের খোসা, রাউন্ড হোল প্রশ্ন।

যদি রিলেশনাল ডাটাবেস এবং এসকিউএল কেবলমাত্র হাতুড়ি থাকে বা আপনি ব্যবহার করতে ইচ্ছুক থাকেন তবে এখন পর্যন্ত যে উত্তরগুলি পোস্ট করা হয়েছে তা পর্যাপ্ত are তবে, শ্রেণিবদ্ধ ডেটা পরিচালনা করার জন্য ডিজাইন করা কোনও সরঞ্জাম ব্যবহার করবেন না কেন? গ্রাফ ডাটাবেস জটিল শ্রেণিবদ্ধ তথ্য জন্য আদর্শ।

কোনও গ্রাফ / শ্রেণিবদ্ধ মডেলকে একটি সম্পর্কিত মডেলটিতে মানচিত্রের জন্য কোনও কোড / ক্যোয়ারী সমাধানের জটিলতার সাথে সম্পর্কিত সম্পর্কের মডেলটির অদক্ষতাগুলি যখন কোনও গ্রাফ ডাটাবেস সমাধান একই সমস্যার সমাধান করতে পারে সেই তুলনায় সহজে চেষ্টা করার উপযুক্ত নয়।

একটি সাধারণ শ্রেণিবদ্ধ তথ্য কাঠামো হিসাবে সামগ্রীর বিলের বিষয়টি বিবেচনা করুন।

class Component extends Vertex {
    long assetId;
    long partNumber;
    long material;
    long amount;
};

class PartOf extends Edge {
};

class AdjacentTo extends Edge {
};

দুটি উপ-সমাবেশের মধ্যে সবচেয়ে সংক্ষিপ্ত পথ : সাধারণ গ্রাফ ট্রভারসাল অ্যালগরিদম। গ্রহণযোগ্য পাথ মানদণ্ডের ভিত্তিতে যোগ্য হতে পারে can

সাদৃশ্য : দুটি অ্যাসেমব্লির মধ্যে মিলের ডিগ্রি কত? দুটি উপ-গাছের ছেদ এবং ইউনিয়ন গণনা উভয় উপ-গাছের উপর একটি ট্র্যাভারসাল সম্পাদন করুন। অনুরূপ শতাংশটি ইউনিয়ন দ্বারা বিভক্ত ছেদটি।

ট্রানজিটিভ সমাপ্তি : উপ-গাছটি হাঁটুন এবং আগ্রহের ক্ষেত্রগুলি যোগ করুন, যেমন "উপ-সমাবেশে অ্যালুমিনিয়াম কত?"

হ্যাঁ, আপনি এসকিউএল এবং একটি সম্পর্কিত ডেটাবেস দিয়ে সমস্যার সমাধান করতে পারেন। তবে আপনি যদি কাজের জন্য সঠিক সরঞ্জামটি ব্যবহার করতে ইচ্ছুক হন তবে আরও অনেক ভাল পন্থা রয়েছে।


5
এই উত্তরটি আরও কার্যকর হবে যদি ব্যবহারের কেসগুলি প্রদর্শিত হয় বা আরও ভাল বিপরীত হয় তবে কীভাবে কোনও আরডিবিএমএসে এসকিউএলের পরিবর্তে স্পারকিউএলএর সাথে একটি গ্রাফ ডাটাবেসকে জিজ্ঞাসা করতে হয়।
কমলাপীপস

1
স্পারকিউএলআরডিএফ ডাটাবেসের সাথে সম্পর্কিত যা গ্রাফ ডাটাবেসের বৃহত্তর ডোমেনের একটি সাবক্লাস। আমি ইনফিনিটগ্রাফের সাথে কাজ করি যা কোনও আরডিএফ ডাটাবেস নয় এবং বর্তমানে স্পারকিউএল সমর্থন করে না। ইনফিনিটগ্রাফ বিভিন্ন বিভিন্ন কোয়েরি মেকানিজমকে সমর্থন করে: (1) ভিউ, ফিল্টার, পাথ কোয়ালিফায়ার এবং ফলাফল হ্যান্ডলারগুলি সেট করার জন্য একটি গ্রাফ নেভিগেশন এপিআই, (2) একটি জটিল গ্রাফ পাথের সাথে মিল রেখে ভাষা, এবং (3) গ্রিমলিন।
djhallx

6

আমি আমার শ্রেণিবিন্যাসের জন্য ক্লোজার টেবিল সহ পোস্টগ্রিজ এসকিউএল ব্যবহার করছি। পুরো ডাটাবেসের জন্য আমার কাছে একটি সার্বজনীন সঞ্চিত পদ্ধতি রয়েছে:

CREATE FUNCTION nomen_tree() RETURNS trigger
    LANGUAGE plpgsql
    AS $_$
DECLARE
  old_parent INTEGER;
  new_parent INTEGER;
  id_nom INTEGER;
  txt_name TEXT;
BEGIN
-- TG_ARGV[0] = name of table with entities with PARENT-CHILD relationships (TBL_ORIG)
-- TG_ARGV[1] = name of helper table with ANCESTOR, CHILD, DEPTH information (TBL_TREE)
-- TG_ARGV[2] = name of the field in TBL_ORIG which is used for the PARENT-CHILD relationship (FLD_PARENT)
    IF TG_OP = 'INSERT' THEN
    EXECUTE 'INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT $1.id,$1.id,0 UNION ALL
      SELECT $1.id,ancestor_id,depth+1 FROM ' || TG_ARGV[1] || ' WHERE child_id=$1.' || TG_ARGV[2] USING NEW;
    ELSE                                                           
    -- EXECUTE does not support conditional statements inside
    EXECUTE 'SELECT $1.' || TG_ARGV[2] || ',$2.' || TG_ARGV[2] INTO old_parent,new_parent USING OLD,NEW;
    IF COALESCE(old_parent,0) <> COALESCE(new_parent,0) THEN
      EXECUTE '
      -- prevent cycles in the tree
      UPDATE ' || TG_ARGV[0] || ' SET ' || TG_ARGV[2] || ' = $1.' || TG_ARGV[2]
        || ' WHERE id=$2.' || TG_ARGV[2] || ' AND EXISTS(SELECT 1 FROM '
        || TG_ARGV[1] || ' WHERE child_id=$2.' || TG_ARGV[2] || ' AND ancestor_id=$2.id);
      -- first remove edges between all old parents of node and its descendants
      DELETE FROM ' || TG_ARGV[1] || ' WHERE child_id IN
        (SELECT child_id FROM ' || TG_ARGV[1] || ' WHERE ancestor_id = $1.id)
        AND ancestor_id IN
        (SELECT ancestor_id FROM ' || TG_ARGV[1] || ' WHERE child_id = $1.id AND ancestor_id <> $1.id);
      -- then add edges for all new parents ...
      INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT child_id,ancestor_id,d_c+d_a FROM
        (SELECT child_id,depth AS d_c FROM ' || TG_ARGV[1] || ' WHERE ancestor_id=$2.id) AS child
        CROSS JOIN
        (SELECT ancestor_id,depth+1 AS d_a FROM ' || TG_ARGV[1] || ' WHERE child_id=$2.' 
        || TG_ARGV[2] || ') AS parent;' USING OLD, NEW;
    END IF;
  END IF;
  RETURN NULL;
END;
$_$;

তারপরে প্রতিটি টেবিলের জন্য যেখানে আমার শ্রেণিবদ্ধতা রয়েছে, আমি একটি ট্রিগার তৈরি করি

CREATE TRIGGER nomenclature_tree_tr AFTER INSERT OR UPDATE ON nomenclature FOR EACH ROW EXECUTE PROCEDURE nomen_tree('my_db.nomenclature', 'my_db.nom_helper', 'parent_id');

বিদ্যমান শ্রেণিবিন্যাস থেকে একটি ক্লোজার টেবিল তৈরির জন্য আমি এই সঞ্চিত পদ্ধতিটি ব্যবহার করি:

CREATE FUNCTION rebuild_tree(tbl_base text, tbl_closure text, fld_parent text) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
    EXECUTE 'TRUNCATE ' || tbl_closure || ';
    INSERT INTO ' || tbl_closure || ' (child_id,ancestor_id,depth) 
        WITH RECURSIVE tree AS
      (
        SELECT id AS child_id,id AS ancestor_id,0 AS depth FROM ' || tbl_base || '
        UNION ALL 
        SELECT t.id,ancestor_id,depth+1 FROM ' || tbl_base || ' AS t
        JOIN tree ON child_id = ' || fld_parent || '
      )
      SELECT * FROM tree;';
END;
$$;

বন্ধ টেবিলগুলি 3 টি কলাম - ANCESTOR_ID, DESCENDANT_ID, DEPTH দিয়ে সংজ্ঞায়িত করা হয়েছে। আনসেস্টর এবং ডিসেসেন্ডেন্টের জন্য একই মূল্য এবং ডিপথটির জন্য শূন্যের মান সহ রেকর্ড সংরক্ষণ করা সম্ভব (এবং আমি এমনকি পরামর্শও)। এই শ্রেণিবিন্যাস পুনরুদ্ধারের জন্য প্রশ্নগুলি সহজতর করবে। এবং তারা সত্যই খুব সহজ:

-- get all descendants
SELECT tbl_orig.*,depth FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth <> 0;
-- get only direct descendants
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth = 1;
-- get all ancestors
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON ancestor_id = tbl_orig.id WHERE descendant_id = XXX AND depth <> 0;
-- find the deepest level of children
SELECT MAX(depth) FROM tbl_closure WHERE ancestor_id = XXX;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.