> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
यह दस्तावेज़ अपाचे कैसेंड्रा पर आरडीएफ-शैली नॉलेज ग्राफ के लिए एक स्टोरेज मॉडल का वर्णन करता है। यह मॉडल एक **एंटिटी-सेंट्रिक** दृष्टिकोण का उपयोग करता है, जिसमें प्रत्येक एंटिटी उन सभी क्वाड के बारे में जानती है जिनमें वह भाग लेता है और वह जो भूमिका निभाता है। यह पारंपरिक मल्टी-टेबल एस.पी.ओ. क्रमपरिवर्तन दृष्टिकोण को केवल दो तालिकाओं से बदल देता है।
## पृष्ठभूमि और प्रेरणा
### पारंपरिक दृष्टिकोण
कैसेंड्रा पर एक मानक आरडीएफ क्वाड स्टोर को क्वेरी पैटर्न को कवर करने के लिए कई डीनॉर्मलाइज़्ड तालिकाओं की आवश्यकता होती है - आमतौर पर 6 या अधिक टेबल जो विषय, विधेय, वस्तु और डेटासेट (एसपीओडी) के विभिन्न क्रमपरिवर्तनों का प्रतिनिधित्व करते हैं। प्रत्येक क्वाड को प्रत्येक तालिका में लिखा जाता है, जिसके परिणामस्वरूप महत्वपूर्ण राइट एम्प्लीफिकेशन, परिचालन ओवरहेड और स्कीमा जटिलता होती है।
इसके अतिरिक्त, लेबल रिज़ॉल्यूशन (एंटिटीज के लिए मानव-पठनीय नामों को प्राप्त करना) के लिए अलग राउंड-ट्रिप क्वेरी की आवश्यकता होती है, जो एआई और ग्राफआरएजी उपयोग के मामलों में विशेष रूप से महंगी होती है, जहां एलएलएम संदर्भ के लिए लेबल आवश्यक हैं।
### एंटिटी-सेंट्रिक अंतर्दृष्टि
प्रत्येक क्वाड `(D, S, P, O)` में अधिकतम 4 एंटिटीज शामिल होती हैं। प्रत्येक एंटिटी की क्वाड में भागीदारी के लिए एक पंक्ति लिखकर, हम यह गारंटी देते हैं कि **किसी भी क्वेरी में कम से कम एक ज्ञात तत्व होगा, जो एक विभाजन कुंजी पर हिट करेगा।** यह एकल डेटा तालिका के साथ सभी 16 क्वेरी पैटर्न को कवर करता है।
मुख्य लाभ:
**2 टेबल** 7+ तालिकाओं के बजाय
**प्रति क्वाड 4 राइट** 6+ राइट के बजाय
**लेबल रिज़ॉल्यूशन मुफ्त में** - एक एंटिटी के लेबल उसके संबंधों के साथ स्थित होते हैं, जो स्वाभाविक रूप से एप्लिकेशन कैश को गर्म करते हैं
**सभी 16 क्वेरी पैटर्न** सिंगल-पार्टिशन रीड द्वारा परोसे जाते हैं
**सरल संचालन** - ट्यून करने, कंपैक्ट करने और रिपेयर करने के लिए एक डेटा टेबल
## स्कीमा
### टेबल 1: quads_by_entity
प्राथमिक डेटा तालिका। प्रत्येक एंटिटी में एक विभाजन होता है जिसमें वह सभी क्वाड शामिल होते हैं जिनमें वह भाग लेता है। क्वेरी पैटर्न (एंटिटी द्वारा लुकअप) को दर्शाने के लिए नामित।
**विभाजन कुंजी (पार्टिशन की):** `(collection, entity)` — संग्रह के लिए निर्धारित, प्रत्येक इकाई के लिए एक विभाजन।
**क्लस्टरिंग कॉलम क्रम का तर्क:**
1.**भूमिका (role):** अधिकांश क्वेरी "यह इकाई विषय/वस्तु है" से शुरू होती हैं।
2.**p:** अगला सबसे आम फ़िल्टर, "मुझे सभी `knows` संबंध दिखाएं"।
3.**otype:** URI-मान वाले बनाम शाब्दिक-मान वाले संबंधों के आधार पर फ़िल्टर करने में सक्षम बनाता है।
4.**s, o, d:** विशिष्टता के लिए शेष कॉलम।
5.**dtype, lang:** समान मान वाले लेकिन अलग-अलग प्रकार के मेटाडेटा वाले शाब्दिकों को अलग करने के लिए (उदाहरण के लिए, `"thing"` बनाम `"thing"@en` बनाम `"thing"^^xsd:string`)।
### तालिका 2: quads_by_collection
संग्रह-स्तरीय क्वेरी और हटाने का समर्थन करता है। यह एक संग्रह से संबंधित सभी क्वाड का एक विवरण प्रदान करता है। इसे उस क्वेरी पैटर्न को दर्शाने के लिए नामित किया गया है (संग्रह द्वारा खोज)।
PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang)
);
```
सबसे पहले डेटासेट के आधार पर समूहीकृत किया जाता है, जिससे संग्रह या डेटासेट स्तर पर हटाने की सुविधा मिलती है। `otype`, `dtype`, और `lang` कॉलम को समूहीकरण कुंजी में शामिल किया गया है ताकि समान मान वाले लिटरल को अलग किया जा सके, लेकिन अलग-अलग प्रकार के मेटाडेटा के साथ - RDF में, `"thing"`, `"thing"@en`, और `"thing"^^xsd:string` अर्थपूर्ण रूप से भिन्न मान हैं।
## लेखन पथ
प्रत्येक आने वाले क्वाड `(D, S, P, O)` के लिए, जो संग्रह `C` के भीतर है, `quads_by_entity` में **4 पंक्तियाँ** और `quads_by_collection` में **1 पंक्ति** लिखें।
### उदाहरण
संग्रह `tenant1` में क्वाड दिया गया है:
```
Dataset: https://example.org/graph1
Subject: https://example.org/Alice
Predicate: https://example.org/knows
Object: https://example.org/Bob
```
`quads_by_entity` में 4 पंक्तियाँ लिखें:
| संग्रह | इकाई | भूमिका | p | otype | s | o | d |
|---|---|---|---|---|---|---|---|
| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
`otype` का मान `'L'` है, `dtype` का मान `'xsd:string'` है, और `lang` का मान `'en'` है। शाब्दिक मान `"Alice Smith"` को `o` में संग्रहीत किया जाता है। `quads_by_entity` में केवल 3 पंक्तियों की आवश्यकता होती है - शाब्दिक को इकाई के रूप में लिखने के लिए कोई पंक्ति नहीं लिखी जाती है, क्योंकि शाब्दिक स्वतंत्र रूप से क्वेरी करने योग्य इकाइयाँ नहीं हैं।
## क्वेरी पैटर्न
### सभी 16 डीएसपीओ पैटर्न
नीचे दी गई तालिका में, "परिपूर्ण उपसर्ग" का अर्थ है कि क्वेरी क्लस्टरिंग कॉलम के एक निरंतर उपसर्ग का उपयोग करती है। "विभाजन स्कैन + फ़िल्टर" का अर्थ है कि कैसेंड्रा एक विभाजन के एक स्लाइस को पढ़ता है और मेमोरी में फ़िल्टर करता है - यह कुशल है, लेकिन यह एक शुद्ध उपसर्ग मिलान नहीं है।
| 16 | ?, ?, ?, ? | — | पूर्ण स्कैन | केवल अन्वेषण |
**मुख्य परिणाम**: 15 गैर-तुच्छ पैटर्नों में से 7 परिपूर्ण क्लस्टरिंग उपसर्ग हिट हैं। शेष 8 एकल-विभाजन रीड हैं जिनमें इन-पार्टिशन फ़िल्टरिंग होती है। प्रत्येक क्वेरी जिसमें कम से कम एक ज्ञात तत्व होता है, वह एक विभाजन कुंजी को हिट करती है।
पैटर्न 16 (?, ?, ?, ?) व्यवहार में नहीं होता है क्योंकि संग्रह हमेशा निर्दिष्ट होता है, जिससे यह पैटर्न 12 में कम हो जाता है।
### सामान्य क्वेरी उदाहरण
**किसी इकाई के बारे में सब कुछ:**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice';
```
**किसी इकाई के लिए सभी बाहरी संबंध:**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
AND role = 'S';
```
**किसी इकाई के लिए विशिष्ट विधेय:**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
AND role = 'S' AND p = 'https://example.org/knows';
```
**किसी इकाई के लिए लेबल (विशिष्ट भाषा):**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label'
AND otype = 'L';
```
फिर, यदि आवश्यक हो, तो `lang = 'en'` एप्लिकेशन-साइड पर फ़िल्टर करें।
**केवल URI-मान वाले संबंध (इकाई-से-इकाई लिंक):**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U';
```
**रिवर्स लुकअप - यह इकाई किससे जुड़ी है:**
```sql
SELECT * FROM quads_by_entity
WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob'
AND role = 'O';
```
## लेबल रिज़ॉल्यूशन और कैश वार्मिंग
एंटिटी-सेंट्रिक मॉडल के सबसे महत्वपूर्ण लाभों में से एक यह है कि **लेबल रिज़ॉल्यूशन एक मुफ्त साइड इफ़ेक्ट बन जाता है।**
पारंपरिक मल्टी-टेबल मॉडल में, लेबल प्राप्त करने के लिए अलग-अलग राउंड-ट्रिप क्वेरी की आवश्यकता होती है: ट्रिपल प्राप्त करें, परिणामों में एंटिटी यूआरआई की पहचान करें, फिर प्रत्येक के लिए `rdfs:label` प्राप्त करें। यह N+1 पैटर्न महंगा है।
एंटिटी-सेंट्रिक मॉडल में, किसी एंटिटी को क्वेरी करने पर, यह उसके सभी क्वाड लौटाता है - जिसमें उसके लेबल, प्रकार और अन्य गुण शामिल हैं। जब एप्लिकेशन क्वेरी परिणामों को कैश करता है, तो लेबल किसी भी चीज़ के लिए अनुरोध करने से पहले ही प्री-वार्म हो जाते हैं।
दो उपयोग परिदृश्य इस बात की पुष्टि करते हैं कि यह व्यवहार में अच्छी तरह से काम करता है:
**मानव-सामना करने वाली क्वेरी:** स्वाभाविक रूप से छोटे परिणाम सेट, लेबल आवश्यक। एंटिटी रीड कैश को प्री-वार्म करते हैं।
**एआई/बल्क क्वेरी:** बड़े परिणाम सेट जिनमें सख्त सीमाएं होती हैं। लेबल या तो अनावश्यक होते हैं या केवल उन एंटिटीज के एक क्यूरेटेड सबसेट के लिए आवश्यक होते हैं जो पहले से ही कैश में हैं।
30,000 एंटिटीज जैसे विशाल परिणाम सेट के लिए लेबल को हल करने की सैद्धांतिक चिंता को इस व्यावहारिक अवलोकन द्वारा कम किया जाता है कि कोई भी मानव या एआई उपभोक्ता उन सभी लेबलों को उपयोगी रूप से संसाधित नहीं करता है। एप्लिकेशन-स्तरीय क्वेरी सीमाएं यह सुनिश्चित करती हैं कि कैश दबाव प्रबंधनीय रहे।
## वाइड पार्टिशन्स और रीफिकेशन
रीफिकेशन (आरडीएफ-स्टार शैली के स्टेटमेंट स्टेटमेंट के बारे में) हब एंटिटीज बनाते हैं - उदाहरण के लिए, एक स्रोत दस्तावेज़ जो निकाले गए हजारों तथ्यों का समर्थन करता है। इससे वाइड पार्टिशन्स बन सकते हैं।
कम करने वाले कारक:
**एप्लिकेशन-स्तरीय क्वेरी सीमाएं:** सभी GraphRAG और मानव-सामना करने वाली क्वेरी सख्त सीमाओं को लागू करती हैं, इसलिए हॉट रीड पाथ पर वाइड पार्टिशन्स को कभी भी पूरी तरह से स्कैन नहीं किया जाता है।
**कैसेंड्रा आंशिक रीड को कुशलता से संभालता है:** एक क्लस्टरिंग कॉलम स्कैन जिसमें शुरुआती स्टॉप हो, वह बड़े पार्टिशन्स पर भी तेज़ होता है।
**कलेक्शन डिलीशन** (केवल वह ऑपरेशन जो पूरे पार्टिशन्स को पार कर सकता है) एक स्वीकृत पृष्ठभूमि प्रक्रिया है।
## कलेक्शन डिलीशन
एपीआई कॉल द्वारा ट्रिगर किया गया, पृष्ठभूमि में चलता है (अंततः सुसंगत)।
1. लक्ष्य कलेक्शन के लिए `quads_by_collection` पढ़ें ताकि सभी क्वाड प्राप्त हो सकें।
2. क्वाड से अद्वितीय एंटिटीज निकालें (s, p, o, d मान)।
3. प्रत्येक अद्वितीय एंटिटी के लिए, `quads_by_entity` से पार्टीशन को हटाएं।
4.`quads_by_collection` से पंक्तियों को हटाएं।
`quads_by_collection` टेबल वह इंडेक्स प्रदान करता है जिसकी आवश्यकता सभी एंटिटी पार्टिशन्स को खोजने के लिए होती है बिना पूरे टेबल स्कैन के। पार्टीशन-स्तरीय डिलीट कुशल हैं क्योंकि `(collection, entity)` पार्टीशन कुंजी है।
## मल्टी-टेबल मॉडल से माइग्रेशन पाथ
एंटिटी-सेंट्रिक मॉडल मौजूदा मल्टी-टेबल मॉडल के साथ माइग्रेशन के दौरान सह-अस्तित्व में रह सकता है:
1. मौजूदा टेबल के साथ `quads_by_entity` और `quads_by_collection` टेबल तैनात करें।
2. नए और पुराने दोनों टेबल में नए क्वाड को डुअल-राइट करें।
3. मौजूदा डेटा को नए टेबल में बैकफिल करें।
4. एक क्वेरी पैटर्न को एक बार में माइग्रेट करें।
5. सभी रीड माइग्रेट होने के बाद पुराने टेबल को डीकमीशन करें।
## सारांश
| पहलू | पारंपरिक (6-टेबल) | एंटिटी-सेंट्रिक (2-टेबल) |