> **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.
यह विनिर्देश स्केलेबिलिटी और उपयोगकर्ता अनुभव से संबंधित मुद्दों को संबोधित करता है जो तब उत्पन्न होते हैं जब TrustGraph में बड़े दस्तावेज़ लोड किए जाते हैं। वर्तमान आर्किटेक्चर दस्तावेज़ अपलोड को एक एकल, अविभाज्य ऑपरेशन के रूप में मानता है, जिससे पाइपलाइन के कई बिंदुओं पर मेमोरी का दबाव पड़ता है और उपयोगकर्ताओं को कोई प्रतिक्रिया या रिकवरी विकल्प नहीं मिलते हैं।
यह कार्यान्वयन निम्नलिखित उपयोग मामलों को लक्षित करता है:
1.**बड़े पीडीएफ प्रसंस्करण**: सैकड़ों मेगाबाइट के पीडीएफ फ़ाइलों को अपलोड करें और संसाधित करें
बिना मेमोरी समाप्त किए।
2.**फिर से शुरू करने योग्य अपलोड**: बाधित अपलोड को वहीं से जारी करने की अनुमति दें जहां से
वे रुके थे, न कि पुनः आरंभ करने के बजाय।
3.**प्रगति प्रतिक्रिया**: उपयोगकर्ताओं को अपलोड और प्रसंस्करण की वास्तविक समय की जानकारी प्रदान करें।
4.**मेमोरी-कुशल प्रसंस्करण**: दस्तावेज़ों को स्ट्रीमिंग तरीके से संसाधित करें
बिना पूरी फ़ाइलों को मेमोरी में रखे।
## लक्ष्य
**क्रमिक अपलोड**: REST और WebSocket के माध्यम से खंडित दस्तावेज़ अपलोड का समर्थन।
**फिर से शुरू करने योग्य स्थानांतरण**: बाधित अपलोड से उबरने की क्षमता।
**प्रगति दृश्यता**: क्लाइंट को अपलोड/प्रोसेसिंग प्रगति प्रतिक्रिया प्रदान करें।
**मेमोरी दक्षता**: पाइपलाइन में पूरे दस्तावेज़ को बफर करने से बचें।
**पिछड़ा संगतता**: मौजूदा छोटे दस्तावेज़ वर्कफ़्लो बिना किसी बदलाव के जारी रहते हैं।
**स्ट्रीमिंग प्रोसेसिंग**: PDF डिकोडिंग और टेक्स्ट चंकिंग स्ट्रीम पर काम करते हैं।
## पृष्ठभूमि
### वर्तमान आर्किटेक्चर
दस्तावेज़ सबमिशन निम्नलिखित पथ से गुजरता है:
1.**क्लाइंट** REST (`POST /api/v1/librarian`) या WebSocket के माध्यम से दस्तावेज़ सबमिट करता है।
2.**API गेटवे** बेस64-एन्कोडेड दस्तावेज़ सामग्री के साथ पूर्ण अनुरोध प्राप्त करता है।
3.**LibrarianRequestor** अनुरोध को Pulsar संदेश में बदलता है।
4.**Librarian सर्विस** संदेश प्राप्त करता है, दस्तावेज़ को मेमोरी में डिकोड करता है।
5.**BlobStore** दस्तावेज़ को Garage/S3 पर अपलोड करता है।
6.**Cassandra** ऑब्जेक्ट संदर्भ के साथ मेटाडेटा संग्रहीत करता है।
7. प्रोसेसिंग के लिए: दस्तावेज़ को S3 से पुनर्प्राप्त किया जाता है, डिकोड किया जाता है, खंडित किया जाता है - सभी मेमोरी में।
API स्कीमा: `trustgraph-base/trustgraph/schema/services/library.py`
### वर्तमान सीमाएँ
वर्तमान डिज़ाइन में कई जटिल मेमोरी और उपयोगकर्ता अनुभव संबंधी समस्याएं हैं:
1.**परमाणु अपलोड ऑपरेशन**: संपूर्ण दस्तावेज़ को एक
एकल अनुरोध में प्रेषित किया जाना चाहिए। बड़े दस्तावेज़ों के लिए लंबे समय तक चलने वाले अनुरोधों की आवश्यकता होती है, जिसमें कोई प्रगति संकेत नहीं होता है और यदि कनेक्शन विफल हो जाता है तो कोई पुनः प्रयास तंत्र नहीं होता है।
2.**एपीआई डिज़ाइन**: REST और WebSocket दोनों एपीआई संपूर्ण दस्तावेज़ की अपेक्षा करते हैं
एक ही संदेश में। स्कीमा (`LibrarianRequest`) में एक `content`
फ़ील्ड है जिसमें संपूर्ण बेस64-एन्कोडेड दस्तावेज़ होता है।
3.**लाइब्रेरियन मेमोरी**: लाइब्रेरियन सेवा पूरे दस्तावेज़ को
मेमोरी में डिकोड करती है, फिर इसे S3 पर अपलोड करने से पहले। 500MB के PDF के लिए, इसका मतलब है कि 500MB+ को प्रोसेस मेमोरी में रखना।
500MB+ को प्रोसेस मेमोरी में रखना।
4.**PDF डिकोडर मेमोरी**: जब प्रोसेसिंग शुरू होती है, तो PDF डिकोडर टेक्स्ट निकालने के लिए पूरे PDF को मेमोरी में लोड करता है। PyPDF और समान लाइब्रेरीज़ को आमतौर पर पूरे दस्तावेज़ तक पहुंच की आवश्यकता होती है।
PyPDF और समान लाइब्रेरीज़ को आमतौर पर पूरे दस्तावेज़ तक पहुंच की आवश्यकता होती है।
5.**चंकर मेमोरी**: टेक्स्ट चंकर, निकाले गए पूरे टेक्स्ट को प्राप्त करता है
और इसे मेमोरी में रखता है, जबकि चंक्स बनाता है।
**मेमोरी प्रभाव का उदाहरण** (500MB पीडीएफ):
गेटवे: ~700MB (बेस64 एन्कोडिंग ओवरहेड)
लाइब्रेरियन: ~500MB (डिकोडेड बाइट्स)
पीडीएफ डिकोडर: ~500MB + एक्सट्रैक्शन बफ़र्स
चंकर: निकाला गया टेक्स्ट (चर, संभावित रूप से 100MB+)
एक बड़े दस्तावेज़ के लिए कुल अधिकतम मेमोरी 2GB से अधिक हो सकती है।
## तकनीकी डिज़ाइन
### डिज़ाइन सिद्धांत
1.**एपीआई फ़ेसड**: सभी क्लाइंट इंटरैक्शन लाइब्रेरियन एपीआई के माध्यम से होते हैं। क्लाइंट
के पास अंतर्निहित S3/गैराज स्टोरेज तक प्रत्यक्ष पहुंच या ज्ञान नहीं है।
2.**एस3 मल्टीपार्ट अपलोड**: आंतरिक रूप से मानक एस3 मल्टीपार्ट अपलोड का उपयोग करें।
यह एस3-संगत प्रणालियों (AWS S3, MinIO, Garage,
Ceph, DigitalOcean Spaces, Backblaze B2, आदि) में व्यापक रूप से समर्थित है, जो पोर्टेबिलिटी सुनिश्चित करता है।
3.**परमाणु पूर्णता**: एस3 मल्टीपार्ट अपलोड स्वाभाविक रूप से परमाणु होते हैं - अपलोड किए गए
भाग तब तक अदृश्य रहते हैं जब तक कि `CompleteMultipartUpload` को कॉल नहीं किया जाता। कोई अस्थायी
फ़ाइलें या नाम बदलने की क्रियाएं आवश्यक नहीं हैं।
4.**ट्रैक करने योग्य स्थिति**: अपलोड सत्रों को कैसेंड्रा में ट्रैक किया जाता है, जो
अपूर्ण अपलोडों में दृश्यता प्रदान करता है और पुनः आरंभ करने की क्षमता को सक्षम करता है।
) WITH default_time_to_live = 86400; -- 24 hour TTL
CREATE INDEX upload_session_user ON upload_session (user);
```
**टीटीएल व्यवहार:**
सत्र 24 घंटे के बाद समाप्त हो जाते हैं यदि वे पूरे नहीं होते हैं।
जब कैसेंड्रा टीटीएल समाप्त होता है, तो सत्र रिकॉर्ड हटा दिया जाता है।
अनाथ एस3 भाग को एस3 लाइफसाइकिल नीति द्वारा साफ़ किया जाता है (बकेट पर कॉन्फ़िगर करें)।
### विफलता प्रबंधन और परमाणुता
**चंक अपलोड विफलता:**
क्लाइंट विफल चंक को फिर से प्रयास करता है (समान `upload_id` और `chunk-index`)।
एस3 `UploadPart` समान भाग संख्या के लिए अपरिवर्तनीय है।
सत्र ट्रैक करता है कि कौन से चंक सफल हुए।
**क्लाइंट अपलोड के दौरान डिस्कनेक्ट हो जाता है:**
प्राप्त चंक के साथ सत्र कैसेंड्रा में बना रहता है।
क्लाइंट यह देखने के लिए `get-upload-status` को कॉल कर सकता है कि क्या गायब है।
केवल गायब चंक अपलोड करके फिर से शुरू करें, फिर `complete-upload`।
**पूर्ण-अपलोड विफलता:**
एस3 `CompleteMultipartUpload` परमाणु है - या तो यह पूरी तरह से सफल होता है या विफल रहता है।
विफलता पर, भाग बने रहते हैं और क्लाइंट `complete-upload` को फिर से प्रयास कर सकता है।
कोई आंशिक दस्तावेज़ कभी भी दिखाई नहीं देता है।
**सेशन समाप्ति:**
कैसेंड्रा TTL 24 घंटे बाद सेशन रिकॉर्ड को हटा देता है।
S3 बकेट लाइफसाइकिल पॉलिसी अधूरी मल्टीपार्ट अपलोड को साफ़ करती है।
कोई मैनुअल सफाई की आवश्यकता नहीं है।
### S3 मल्टीपार्ट एटॉमिकिटी
S3 मल्टीपार्ट अपलोड अंतर्निहित एटॉमिकिटी प्रदान करते हैं:
1.**भाग अदृश्य होते हैं**: अपलोड किए गए भागों को ऑब्जेक्ट के रूप में एक्सेस नहीं किया जा सकता है।
वे केवल एक अधूरी मल्टीपार्ट अपलोड के हिस्से के रूप में मौजूद होते हैं।
2.**पूर्णता (Atomic completion)**: `CompleteMultipartUpload` या तो सफल होता है (वस्तु परमाणु रूप से दिखाई देती है) या विफल होता है (कोई वस्तु नहीं बनाई जाती है)। कोई आंशिक स्थिति नहीं।
3.**नाम बदलने की आवश्यकता नहीं**: अंतिम वस्तु कुंजी ⟦CODE_0⟧ समय पर निर्दिष्ट की जाती है। भाग सीधे उस कुंजी पर संयोजित होते हैं।
`CreateMultipartUpload` समय। भाग सीधे उस कुंजी में संयोजित किए जाते हैं।
4.**सर्वर-साइड कोएलेसेंस (Server-side coalesce)**: S3 आंतरिक रूप से भागों को जोड़ता है। लाइब्रेरियन
कभी भी भागों को वापस नहीं पढ़ता है - दस्तावेज़ के आकार की परवाह किए बिना शून्य मेमोरी ओवरहेड।
अपलोड प्रवाह भंडारण में दस्तावेजों को कुशलतापूर्वक लाने के लिए है। प्रसंस्करण प्रवाह दस्तावेजों को पूरी तरह से मेमोरी में लोड किए बिना, उन्हें निकालने और चंक में विभाजित करने के लिए है।
#### डिज़ाइन सिद्धांत: पहचानकर्ता, सामग्री नहीं
वर्तमान में, जब प्रसंस्करण शुरू होता है, तो दस्तावेज़ सामग्री पल्सर संदेशों के माध्यम से प्रवाहित होती है। इससे पूरे दस्तावेज़ मेमोरी में लोड हो जाते हैं। इसके बजाय:
पल्सर संदेश केवल **दस्तावेज़ पहचानकर्ता** ले जाते हैं
प्रोसेसर सीधे लाइब्रेरियन से दस्तावेज़ सामग्री प्राप्त करते हैं
पुनर्प्राप्ति एक **अस्थायी फ़ाइल में स्ट्रीम** के रूप में होती है
दस्तावेज़-विशिष्ट पार्सिंग (PDF, टेक्स्ट, आदि) फ़ाइलों के साथ काम करते हैं, मेमोरी बफ़र्स के साथ नहीं
यह लाइब्रेरियन को दस्तावेज़-संरचना-अज्ञेयवादी रखता है। PDF पार्सिंग, टेक्स्ट
निष्कर्षण और अन्य प्रारूप-विशिष्ट तर्क संबंधित डिकोडर में रहते हैं।
#### प्रसंस्करण प्रवाह
#### प्रसंस्करण प्रवाह
```
Pulsar PDF Decoder Librarian S3
│ │ │ │
│── doc-id ───────────►│ │ │
│ (processing msg) │ │ │
│ │ │ │
│ │── stream-document ──────►│ │
│ │ (doc-id) │── GetObject ────►│
│ │ │ │
│ │◄── chunk ────────────────│◄── stream ───────│
│ │ (write to temp file) │ │
│ │◄── chunk ────────────────│◄── stream ───────│
│ │ (append to temp file) │ │
│ │ ⋮ │ ⋮ │
│ │◄── EOF ──────────────────│ │
│ │ │ │
│ │ ┌──────────────────────────┐ │
│ │ │ temp file on disk │ │
│ │ │ (memory stays bounded) │ │
│ │ └────────────┬─────────────┘ │
│ │ │ │
│ │ PDF library opens file │
│ │ extract page 1 text ──► chunker │
│ │ extract page 2 text ──► chunker │
│ │ ⋮ │
│ │ close file │
│ │ delete temp file │
```
#### लाइब्रेरियन स्ट्रीम एपीआई
एक स्ट्रीमिंग दस्तावेज़ पुनर्प्राप्ति ऑपरेशन जोड़ें:
**`stream-document`**
अनुरोध:
```json
{
"operation": "stream-document",
"document-id": "doc-123"
}
```
प्रतिक्रिया: स्ट्रीम किए गए बाइनरी खंड (एकल प्रतिक्रिया नहीं)।
REST API के लिए, यह `Transfer-Encoding: chunked` के साथ एक स्ट्रीमिंग प्रतिक्रिया लौटाता है।
आंतरिक सेवा-से-सेवा कॉल के लिए (प्रोसेसर से लाइब्रेरियन तक), यह हो सकता है:
सीधे प्रीसाइंड URL के माध्यम से S3 स्ट्रीमिंग (यदि आंतरिक नेटवर्क अनुमति देता है)
सेवा प्रोटोकॉल पर खंडित प्रतिक्रियाएं
एक समर्पित स्ट्रीमिंग एंडपॉइंट
मुख्य आवश्यकता: डेटा खंडों में प्रवाहित होता है, और कभी भी पूरी तरह से लाइब्रेरियन में बफर नहीं होता है।
#### PDF डिकोडर परिवर्तन
**वर्तमान कार्यान्वयन** (मेमोरी-गहन):
```python
def decode_pdf(document_content: bytes) -> str:
reader = PdfReader(BytesIO(document_content)) # full doc in memory
किसी भी समय, संपूर्ण दस्तावेज़ या संपूर्ण निकाले गए पाठ को मेमोरी में संग्रहीत नहीं किया जाता है।
#### अस्थायी फ़ाइल संबंधी विचार
**स्थान:** सिस्टम के अस्थायी फ़ोल्डर का उपयोग करें (`/tmp` या समकक्ष)। कंटेनरयुक्त परिनियोजन के लिए, सुनिश्चित करें कि अस्थायी फ़ोल्डर में पर्याप्त जगह है
और यह तेज़ स्टोरेज पर है (यदि संभव हो तो नेटवर्क-माउंटेड नहीं)।
**सफाई:** सफाई सुनिश्चित करने के लिए संदर्भ प्रबंधकों (`with tempfile...`) का उपयोग करें
यहां तक कि अपवादों पर भी।
**समवर्ती प्रसंस्करण:** प्रत्येक प्रसंस्करण कार्य का अपना अस्थायी फ़ाइल होता है।
समानांतर दस्तावेज़ प्रसंस्करण के बीच कोई टकराव नहीं होता है।
**डिस्क स्पेस**: अस्थायी फ़ाइलें अल्पकालिक होती हैं (प्रोसेसिंग की अवधि)।
500MB के PDF के लिए, प्रोसेसिंग के दौरान 500MB अस्थायी स्थान की आवश्यकता होती है। यदि डिस्क स्पेस सीमित है, तो आकार सीमा अपलोड के समय लागू की जा सकती है।
### एकीकृत प्रोसेसिंग इंटरफ़ेस: चाइल्ड दस्तावेज़
PDF निष्कर्षण और टेक्स्ट दस्तावेज़ प्रोसेसिंग को एक ही
डाउनस्ट्रीम पाइपलाइन (चंकर → एम्बेडिंग → स्टोरेज) में फीड करने की आवश्यकता है। इसे एक सुसंगत "आईडी द्वारा प्राप्त करें" इंटरफ़ेस के साथ प्राप्त करने के लिए, निकाले गए टेक्स्ट ब्लॉकों को "चाइल्ड दस्तावेज़" के रूप में लाइब्रेरियन में वापस संग्रहीत किया जाता है।
एक दस्तावेज़ आईडी प्राप्त करें (पल्सर के माध्यम से)
लाइब्रेरियन से सामग्री स्ट्रीम करें
इसे छोटे भागों में विभाजित करें
यह नहीं जानता या परवाह नहीं करता कि आईडी किस चीज़ को संदर्भित करती है:
एक उपयोगकर्ता द्वारा अपलोड किया गया टेक्स्ट दस्तावेज़
एक पीडीएफ पृष्ठ से निकाला गया टेक्स्ट ब्लॉक
कोई भी भविष्य का दस्तावेज़ प्रकार
#### चाइल्ड दस्तावेज़ मेटाडेटा
दस्तावेज़ स्कीमा को पैरेंट/चाइल्ड संबंधों को ट्रैक करने के लिए विस्तारित करें:
```sql
-- Add columns to document table
ALTER TABLE document ADD parent_id text;
ALTER TABLE document ADD document_type text;
-- Index for finding children of a parent
CREATE INDEX document_parent ON document (parent_id);
```
**दस्तावेज़ के प्रकार:**
| `document_type` | विवरण |
|-----------------|-------------|
| `source` | उपयोगकर्ता द्वारा अपलोड किया गया दस्तावेज़ (पीडीएफ, टेक्स्ट, आदि) |
| `extracted` | स्रोत दस्तावेज़ से प्राप्त (उदाहरण के लिए, पीडीएफ पृष्ठ पाठ) |
**मेटाडेटा फ़ील्ड:**
| फ़ील्ड | स्रोत दस्तावेज़ | निकाली गई चाइल्ड |
|-------|-----------------|-----------------|
| `id` | उपयोगकर्ता द्वारा प्रदान किया गया या उत्पन्न | उत्पन्न (उदाहरण के लिए, `{parent-id}-page-{n}`) |
| `parent_id` | `NULL` | मूल दस्तावेज़ आईडी |
| `document_type` | `source` | `extracted` |
| `kind` | `application/pdf`, आदि | `text/plain` |
| `title` | उपयोगकर्ता द्वारा प्रदान किया गया | उत्पन्न (उदाहरण के लिए, "रिपोर्ट.pdf का पृष्ठ 3") |
| `user` | प्रमाणित उपयोगकर्ता | मूल के समान |
#### चाइल्ड दस्तावेज़ों के लिए लाइब्रेरियन एपीआई
**चाइल्ड दस्तावेज़ बनाना** (आंतरिक, pdf-extractor द्वारा उपयोग किया जाता है):
```json
{
"operation": "add-child-document",
"parent-id": "doc-123",
"document-metadata": {
"id": "doc-123-page-1",
"kind": "text/plain",
"title": "Page 1"
},
"content": "<base64-encoded-text>"
}
```
छोटे, निकाले गए टेक्स्ट के लिए (सामान्य पृष्ठ टेक्स्ट <100KBहै),सिंगल-ऑपरेशनअपलोडस्वीकार्यहै।बहुतबड़ेटेक्स्टएक्सट्रैक्शनकेलिए,चंक्डअपलोडकाउपयोगकियाजासकताहै।
**चाइल्ड दस्तावेज़ों की सूची** (डीबगिंग/एडमिन के लिए):
**चाइल्ड दस्तावेज़ों की सूची** (डीबगिंग/प्रशासन के लिए):
"""Extract PDF pages and store as child documents."""
with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp:
# Stream PDF to temp file
for chunk in librarian_client.stream_document(doc_id):
tmp.write(chunk)
tmp.flush()
# Extract pages
reader = PdfReader(tmp.name)
for page_num, page in enumerate(reader.pages, start=1):
text = page.extract_text()
# Store as child document
child_id = f"{doc_id}-page-{page_num}"
await librarian_client.add_child_document(
parent_id=doc_id,
document_id=child_id,
kind="text/plain",
title=f"Page {page_num}",
content=text.encode('utf-8')
)
# Send to chunker queue
await output_queue.send(child_id)
```
चंकर इन चाइल्ड आईडी को प्राप्त करता है और उन्हें उसी तरह संसाधित करता है जैसे कि वह किसी उपयोगकर्ता द्वारा अपलोड किए गए टेक्स्ट दस्तावेज़ को संसाधित करता है।
चंकर इन चाइल्ड आईडी को प्राप्त करता है और उन्हें उसी तरह संसाधित करता है जैसे कि वह किसी उपयोगकर्ता द्वारा अपलोड किए गए टेक्स्ट दस्तावेज़ को संसाधित करता है।
### क्लाइंट अपडेट
#### पायथन एसडीके
पायथन एसडीके (`trustgraph-base/trustgraph/api/library.py`) को खंडित अपलोड को पारदर्शी रूप से संभालना चाहिए। सार्वजनिक इंटरफ़ेस अपरिवर्तित रहता है:
खंडित अपलोड को पारदर्शी रूप से संभालना चाहिए। सार्वजनिक इंटरफ़ेस अपरिवर्तित रहता है:
```python
# Existing interface - no change for users
library.add_document(
id="doc-123",
title="Large Report",
kind="application/pdf",
content=large_pdf_bytes, # Can be hundreds of MB
tags=["reports"]
)
```
आंतरिक रूप से, SDK दस्तावेज़ के आकार का पता लगाता है और रणनीति बदलता है: