Native CLI i18n: The TrustGraph CLI has built-in translation support that dynamically loads language strings. You can test and use different languages by simply passing the --lang flag (e.g., --lang es for Spanish, --lang ru for Russian) or by configuring your environment's LANG variable. Automated Docs Translations: This PR introduces autonomously translated Markdown documentation into several target languages, including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew, Arabic, Simplified Chinese, and Russian.
35 KiB
| layout | title | parent |
|---|---|---|
| default | Büyük Belge Yükleme Teknik Özellikleri | Turkish (Beta) |
Büyük Belge Yükleme Teknik Özellikleri
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.
Genel Bakış
Bu teknik özellik, TrustGraph'e büyük belgelerin yüklenmesi sırasında ortaya çıkan ölçeklenebilirlik ve kullanıcı deneyimi sorunlarını ele almaktadır. Mevcut mimari, belge yüklemeyi tek bir atomik işlem olarak ele almaktadır, bu da boru hattının çeşitli noktalarında bellek yüklenmesine neden olmakta ve kullanıcılara herhangi bir geri bildirim veya kurtarma seçeneği sunmamaktadır.
Bu uygulama, aşağıdaki kullanım senaryolarına yöneliktir:
-
Büyük PDF İşleme: Belleği tüketmeden yüzlerce megabayt boyutunda PDF dosyalarını yükleyin ve işleyin.
-
Devam Eden Yüklemeler: Kesintiye uğrayan yüklemelerin, baştan başlamak yerine, durdurulduğu yerden devam etmesini sağlayın.
-
İlerleme Geri Bildirimi: Kullanıcılara yükleme ve işleme sürecinin gerçek zamanlı görünürlüğünü sağlayın.
-
Bellek Verimli İşleme: Belgeleri, tüm dosyaları bellekte tutmadan, akış halinde işleyin.
Hedefler
Artımlı Yükleme: REST ve WebSocket üzerinden parçalı belge yüklemeyi destekleyin. Devam Eden Aktarımlar: Kesintiye uğrayan yüklemelerden kurtarmayı sağlayın. İlerleme Görünürlüğü: İstemcilere yükleme/işleme sürecinin ilerleme durumunu geri bildirin. Bellek Verimliliği: Boru hattının tamamında tam belge tamponlamayı ortadan kaldırın. Geriye Dönük Uyumluluk: Mevcut, küçük belge iş akışlarının değişmeden devam etmesini sağlayın. Akış İşleme: PDF kod çözme ve metin parçalama işlemleri, akışlar üzerinde gerçekleştirilir.
Arka Plan
Mevcut Mimari
Belge gönderme işlemi, aşağıdaki yolu izlemektedir:
- İstemci, belgeyi REST (
POST /api/v1/librarian) veya WebSocket üzerinden gönderir. - API Ağ Geçidi, base64 ile kodlanmış belge içeriği içeren eksiksiz isteği alır.
- LibrarianRequestor, isteği Pulsar mesajına dönüştürür.
- Librarian Hizmeti, mesajı alır, belgeyi belleğe kodlar.
- BlobStore, belgeyi Garage/S3'e yükler.
- Cassandra, nesne referansı ile birlikte meta verileri depolar.
- İşleme için: belge S3'ten alınır, kodlanır, parçalara ayrılır - hepsi bellekte.
Önemli dosyalar:
REST/WebSocket girişi: trustgraph-flow/trustgraph/gateway/service.py
Librarian çekirdeği: trustgraph-flow/trustgraph/librarian/librarian.py
Blob depolama: trustgraph-flow/trustgraph/librarian/blob_store.py
Cassandra tabloları: trustgraph-flow/trustgraph/tables/library.py
API şeması: trustgraph-base/trustgraph/schema/services/library.py
Mevcut Sınırlamalar
Mevcut tasarımın, çeşitli birikimli bellek ve kullanıcı deneyimi sorunları bulunmaktadır:
-
Atomik Yükleme İşlemi: Tüm belge, tek bir istekte iletilmelidir. Büyük belgeler, bağlantı başarısız olursa geri alma mekanizması olmadan, ilerleme göstergesi olmayan uzun süreli istekler gerektirir.
-
API Tasarımı: Hem REST hem de WebSocket API'leri, tüm belgeyi tek bir mesajda bekler. Şema (
LibrarianRequest), tüm base64 ile kodlanmış belgeyi içeren tek bircontentalanına sahiptir. -
Kütüphaneci Belleği: Kütüphaneci hizmeti, belgeyi S3'e yüklemeden önce tüm belgeyi belleğe aktarır. 500MB'lık bir PDF için, bu, işlem belleğinde 500MB+'yi tutmak anlamına gelir. 500MB+ işlem belleğinde tutmak anlamına gelir.
-
PDF Kod Çözücü Belleği: İşleme başladığında, PDF kod çözücü, metni çıkarmak için tüm PDF'yi belleğe yükler. PyPDF ve benzeri kütüphaneler genellikle belgenin tamamına erişim gerektirir.
-
Parçalayıcı Belleği: Metin parçalayıcı, çıkarılan tamamlanmış metni alır ve parçalar oluştururken bunu bellekte tutar.
Bellek Kullanımı Örneği (500MB PDF): Gateway: ~700MB (base64 kodlama ek yükü) Librarian: ~500MB (çözülmüş baytlar) PDF Çözücü: ~500MB + çıkarma arabellekleri Parçalayıcı: çıkarılan metin (değişken, potansiyel olarak 100MB+)
Tek bir büyük belge için toplam maksimum bellek kullanımı 2GB'ı aşabilir.
Teknik Tasarım
Tasarım İlkeleri
-
API Arayüzü: Tüm istemci etkileşimi, librarian API'si üzerinden gerçekleşir. İstemciler, temelindeki S3/Garage depolamaya doğrudan erişemez veya bu depolama hakkında bilgi sahibi değildir.
-
S3 Çoklu Parça Yükleme: Temelde standart S3 çoklu parça yükleme özelliğini kullanın. Bu, S3 uyumlu sistemlerde (AWS S3, MinIO, Garage, Ceph, DigitalOcean Spaces, Backblaze B2, vb.) yaygın olarak desteklenir ve taşınabilirliği sağlar.
-
Atomik Tamamlama: S3 çoklu parça yüklemeleri doğası gereği atomiktir; yüklenen parçalar,
CompleteMultipartUploadçağrılana kadar görünmez. Geçici dosyalar veya yeniden adlandırma işlemleri gerekmez. -
Takip Edilebilir Durum: Yükleme oturumları Cassandra'da takip edilir, bu da tamamlanmamış yüklemeler hakkında görünürlük sağlar ve devam ettirme özelliğini etkinleştirir.
Parçalı Yükleme Akışı
Client Librarian API S3/Garage
│ │ │
│── begin-upload ───────────►│ │
│ (metadata, size) │── CreateMultipartUpload ────►│
│ │◄── s3_upload_id ─────────────│
│◄── upload_id ──────────────│ (store session in │
│ │ Cassandra) │
│ │ │
│── upload-chunk ───────────►│ │
│ (upload_id, index, data) │── UploadPart ───────────────►│
│ │◄── etag ─────────────────────│
│◄── ack + progress ─────────│ (store etag in session) │
│ ⋮ │ ⋮ │
│ (repeat for all chunks) │ │
│ │ │
│── complete-upload ────────►│ │
│ (upload_id) │── CompleteMultipartUpload ──►│
│ │ (parts coalesced by S3) │
│ │── store doc metadata ───────►│ Cassandra
│◄── document_id ────────────│ (delete session) │
Müşteri, S3 ile doğrudan etkileşimde bulunmaz. Kütüphaneci, parçalı yükleme API'miz ile S3 çok parçalı işlemler arasında dahili olarak çeviri yapar.
Kütüphaneci API İşlemleri
Kütüphaneci API İşlemleri
begin-upload
Parçalı bir yükleme oturumu başlatın.
İstek:
{
"operation": "begin-upload",
"document-metadata": {
"id": "doc-123",
"kind": "application/pdf",
"title": "Large Document",
"user": "user-id",
"tags": ["tag1", "tag2"]
},
"total-size": 524288000,
"chunk-size": 5242880
}
Yanıt:
{
"upload-id": "upload-abc-123",
"chunk-size": 5242880,
"total-chunks": 100
}
Kütüphaneci:
- Benzersiz bir
upload_idveobject_idoluşturur (blob depolama için UUID). - S3'ü
CreateMultipartUploadile çağırır,s3_upload_id'i alır. - Cassandra'da oturum kaydını oluşturur.
upload_id'ı istemciye döndürür.
upload-chunk
Tek bir bölüm yükleyin.
İstek:
{
"operation": "upload-chunk",
"upload-id": "upload-abc-123",
"chunk-index": 0,
"content": "<base64-encoded-chunk>"
}
Yanıt:
{
"upload-id": "upload-abc-123",
"chunk-index": 0,
"chunks-received": 1,
"total-chunks": 100,
"bytes-received": 5242880,
"total-bytes": 524288000
}
Kütüphaneci:
upload_idile oturumu arar.- Mülkiyeti doğrular (kullanıcı, oturum oluşturucuyu eşleştirmelidir).
- Parça verileriyle S3'ü
UploadPartile çağırır,etagalır. - Parça indeksini ve etiketini kullanarak oturum kaydını günceller.
- İlerleme durumunu istemciye döndürür.
Başarısız parçalar tekrar denenebilir - aynı chunk-index'ı tekrar gönderin.
complete-upload
Yüklemeyi tamamlayın ve belgeyi oluşturun.
İstek:
{
"operation": "complete-upload",
"upload-id": "upload-abc-123"
}
Yanıt:
{
"document-id": "doc-123",
"object-id": "550e8400-e29b-41d4-a716-446655440000"
}
Kütüphaneci:
- Oturumu kontrol eder, tüm parçaların alındığından emin olur.
- Parça etiketleriyle birlikte S3'ü
CompleteMultipartUploadile çağırır (S3 parçaları dahili olarak birleştirir - kütüphaneci için bellek maliyeti sıfırdır). 3. Cassandra'da, meta veriler ve nesne referansı ile birlikte bir belge kaydı oluşturur. - Yükleme oturumu kaydını siler.
- Belge kimliğini müşteriye döndürür.
abort-upload
Devam eden bir yüklemeyi iptal et.
İstek:
{
"operation": "abort-upload",
"upload-id": "upload-abc-123"
}
Kütüphaneci:
- Parçaları temizlemek için S3
AbortMultipartUpload'ı çağırır. - Oturum kaydını Cassandra'dan siler.
get-upload-status
Bir yüklemenin durumunu sorgula (devam ettirme özelliği için).
İstek:
{
"operation": "get-upload-status",
"upload-id": "upload-abc-123"
}
Yanıt:
{
"upload-id": "upload-abc-123",
"state": "in-progress",
"chunks-received": [0, 1, 2, 5, 6],
"missing-chunks": [3, 4, 7, 8],
"total-chunks": 100,
"bytes-received": 36700160,
"total-bytes": 524288000
}
list-uploads
Bir kullanıcı için eksik yüklemeleri listele.
İstek:
{
"operation": "list-uploads"
}
Yanıt:
{
"uploads": [
{
"upload-id": "upload-abc-123",
"document-metadata": { "title": "Large Document", ... },
"progress": { "chunks-received": 43, "total-chunks": 100 },
"created-at": "2024-01-15T10:30:00Z"
}
]
}
Yükleme Oturum Depolama
Cassandra'da devam eden yüklemeleri takip edin:
CREATE TABLE upload_session (
upload_id text PRIMARY KEY,
user text,
document_id text,
document_metadata text, -- JSON: title, kind, tags, comments, etc.
s3_upload_id text, -- internal, for S3 operations
object_id uuid, -- target blob ID
total_size bigint,
chunk_size int,
total_chunks int,
chunks_received map<int, text>, -- chunk_index → etag
created_at timestamp,
updated_at timestamp
) WITH default_time_to_live = 86400; -- 24 hour TTL
CREATE INDEX upload_session_user ON upload_session (user);
TTL Davranışı: Oturumlar, tamamlanmadığı takdirde 24 saat sonra sona erer. Cassandra TTL'si dolduğunda, oturum kaydı silinir. Yalnız kalmış S3 parçaları, S3 yaşam döngüsü politikası tarafından temizlenir (kovada yapılandırılır).
Hata Yönetimi ve Atomiklik
Parça yükleme hatası:
İstemci, başarısız olan parçayı tekrar dener (aynı upload_id ve chunk-index).
S3 UploadPart, aynı parça numarası için idempotent'tir.
Oturum, hangi parçaların başarılı olduğunu takip eder.
İstemci, yükleme sırasında bağlantıyı keser:
Oturum, Cassandra'da alınan parçalarla birlikte kalır.
İstemci, eksik olanları görmek için get-upload-status'ı çağırabilir.
Yalnızca eksik parçaları yükleyerek devam edin ve ardından complete-upload'ı çağırın.
Tamamlanmış yükleme hatası:
S3 CompleteMultipartUpload atomiktir - ya tamamen başarılı olur ya da başarısız olur.
Başarısızlık durumunda, parçalar kalır ve istemci complete-upload'ı tekrar deneyebilir.
Hiçbir kısmi belge görünmez.
Oturumun sona ermesi: Cassandra TTL, oturum kaydını 24 saat sonra siler. S3 kova yaşam döngüsü politikası, tamamlanmamış çok parçalı yüklemeleri temizler. Manuel temizliğe gerek yoktur.
S3 Çok Parçalı Atomiklik
S3 çok parçalı yüklemeler, yerleşik atomiklik sağlar:
-
Parçalar görünmezdir: Yüklenen parçalar, nesne olarak erişilemez. Bunlar yalnızca tamamlanmamış bir çok parçalı yüklemenin parçaları olarak vardır.
-
Atomik tamamlama:
CompleteMultipartUploadya başarılı olur (nesne atomik olarak görünür) ya da başarısız olur (nesne oluşturulmaz). Herhangi bir kısmi durum yoktur. -
Yeniden adlandırmaya gerek yoktur: Son nesne anahtarı,
CreateMultipartUploadzamanında belirtilir. Parçalar doğrudan bu anahtara birleştirilir. -
Sunucu tarafı birleştirme: S3, parçaları dahili olarak birleştirir. Kütüphaneci parçaları asla tekrar okumaz - belgenin boyutundan bağımsız olarak sıfır bellek yükü.
BlobStore Uzantıları
Dosya: trustgraph-flow/trustgraph/librarian/blob_store.py
Çok parçalı yükleme yöntemleri ekleyin:
class BlobStore:
# Existing methods...
def create_multipart_upload(self, object_id: UUID, kind: str) -> str:
"""Initialize multipart upload, return s3_upload_id."""
# minio client: create_multipart_upload()
def upload_part(
self, object_id: UUID, s3_upload_id: str,
part_number: int, data: bytes
) -> str:
"""Upload a single part, return etag."""
# minio client: upload_part()
# Note: S3 part numbers are 1-indexed
def complete_multipart_upload(
self, object_id: UUID, s3_upload_id: str,
parts: List[Tuple[int, str]] # [(part_number, etag), ...]
) -> None:
"""Finalize multipart upload."""
# minio client: complete_multipart_upload()
def abort_multipart_upload(
self, object_id: UUID, s3_upload_id: str
) -> None:
"""Cancel multipart upload, clean up parts."""
# minio client: abort_multipart_upload()
Parça Boyutu Hususları
S3 minimumu: Parça başına 5 MB (son parça hariç) S3 maksimumu: Bir yükleme başına 10.000 parça Pratik varsayılan: 5 MB'lık parçalar 500 MB'lık bir belge = 100 parça 5 GB'lık bir belge = 1.000 parça İlerleme hassasiyeti: Daha küçük parçalar = daha hassas ilerleme güncellemeleri Ağ verimliliği: Daha büyük parçalar = daha az sayıda istek
Parça boyutu, belirli sınırlar içinde (5 MB - 100 MB) istemci tarafından yapılandırılabilir.
Belge İşleme: Akışlı Alma
Yükleme akışı, belgelerin depolamaya verimli bir şekilde aktarılmasını sağlar. İşleme akışı, belgelerin tamamını belleğe yüklemeden, belgelerin çıkarılmasını ve parçalara ayrılmasını sağlar.
Tasarım İlkesi: İçerik Değil, Tanımlayıcı
Şu anda, işleme başlatıldığında, belge içeriği Pulsar mesajları aracılığıyla akar. Bu, tüm belgelerin belleğe yüklenmesine neden olur. Bunun yerine:
Pulsar mesajları yalnızca belge tanımlayıcısını taşır İşleyiciler, belge içeriğini doğrudan kütüphaneden alırlar Alma işlemi, bir geçici dosyaya akış şeklinde gerçekleşir Belgeye özgü ayrıştırma (PDF, metin vb.), bellek arabellekleri yerine dosyalarla çalışır
Bu, kütüphanenin belge yapısına bağımlı olmamasını sağlar. PDF ayrıştırma, metin çıkarma ve diğer biçime özgü mantık, ilgili kodlayıcılarda kalır.
İşleme Akışı
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 │
Kütüphaneci Akış API'si
Bir akışlı belge alma işlemi ekleyin:
stream-document
İstek:
{
"operation": "stream-document",
"document-id": "doc-123"
}
Yanıt: Akışlı ikili veri parçaları (tek bir yanıt değil).
REST API için, bu, Transfer-Encoding: chunked ile bir akışlı yanıt döndürür.
İç hizmetler arası iletişimler (işlemci ile kütüphaneci), şu şekilde olabilir: İmza yoluyla doğrudan S3 akışı (eğer iç ağ izin veriyorsa) Hizmet protokolü üzerinden parçalı yanıtlar Özel bir akış uç noktası
Temel gereksinim: Veri, kütüphaneci tarafından asla tamamen tamponlanmadan, parçalar halinde akmalıdır.
PDF Kod Çözücü Değişiklikleri
Mevcut uygulama (bellek yoğun):
def decode_pdf(document_content: bytes) -> str:
reader = PdfReader(BytesIO(document_content)) # full doc in memory
text = ""
for page in reader.pages:
text += page.extract_text() # accumulating
return text # full text in memory
Yeni uygulama (geçici dosya, kademeli):
def decode_pdf_streaming(doc_id: str, librarian_client) -> Iterator[str]:
"""Yield extracted text page by page."""
with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp:
# Stream document to temp file
for chunk in librarian_client.stream_document(doc_id):
tmp.write(chunk)
tmp.flush()
# Open PDF from file (not memory)
reader = PdfReader(tmp.name)
# Yield pages incrementally
for page in reader.pages:
yield page.extract_text()
# tmp file auto-deleted on context exit
Bellek profili: Geçici dosya diskte: PDF'nin boyutu (disk ucuzdur) Bellekte: bir seferde bir sayfanın metni Maksimum bellek: sınırlı, belge boyutundan bağımsız
Metin Belgesi Kod Çözücü Değişiklikleri
Düz metin belgeleri için, daha da basit - geçici dosyaya ihtiyaç yok:
def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]:
"""Yield text in chunks as it streams from storage."""
buffer = ""
for chunk in librarian_client.stream_document(doc_id):
buffer += chunk.decode('utf-8')
# Yield complete lines/paragraphs as they arrive
while '\n\n' in buffer:
paragraph, buffer = buffer.split('\n\n', 1)
yield paragraph + '\n\n'
# Yield remaining buffer
if buffer:
yield buffer
Metin belgeleri, geçici bir dosyaya ihtiyaç duymadan doğrudan akış halinde iletilebilir, çünkü bunlar doğrusal bir yapıya sahiptir.
Akış Tabanlı Parçalama Entegrasyonu
Parçalayıcı, metin (sayfalar veya paragraflar)den oluşan bir yineleyici alır ve parçaları kademeli olarak üretir:
class StreamingChunker:
def __init__(self, chunk_size: int, overlap: int):
self.chunk_size = chunk_size
self.overlap = overlap
def process(self, text_stream: Iterator[str]) -> Iterator[str]:
"""Yield chunks as text arrives."""
buffer = ""
for text_segment in text_stream:
buffer += text_segment
while len(buffer) >= self.chunk_size:
chunk = buffer[:self.chunk_size]
yield chunk
# Keep overlap for context continuity
buffer = buffer[self.chunk_size - self.overlap:]
# Yield remaining buffer as final chunk
if buffer.strip():
yield buffer
Uçtan Uca İşlem Hattı
async def process_document(doc_id: str, librarian_client, embedder):
"""Process document with bounded memory."""
# Get document metadata to determine type
metadata = await librarian_client.get_document_metadata(doc_id)
# Select decoder based on document type
if metadata.kind == 'application/pdf':
text_stream = decode_pdf_streaming(doc_id, librarian_client)
elif metadata.kind == 'text/plain':
text_stream = decode_text_streaming(doc_id, librarian_client)
else:
raise UnsupportedDocumentType(metadata.kind)
# Chunk incrementally
chunker = StreamingChunker(chunk_size=1000, overlap=100)
# Process each chunk as it's produced
for chunk in chunker.process(text_stream):
# Generate embeddings, store in vector DB, etc.
embedding = await embedder.embed(chunk)
await store_chunk(doc_id, chunk, embedding)
Hiçbir noktada, tam belge veya tam çıkarılmış metin bellekte tutulmaz.
Geçici Dosya Hususları
Konum: Sistem geçici dizinini kullanın (/tmp veya eşdeğeri).
Sanallaştırılmış dağıtımlar için, geçici dizinin yeterli alana sahip olduğundan ve mümkünse hızlı depolama üzerinde olduğundan emin olun.
Temizleme: Temizlemenin, istisnalar olsa bile, sağlanması için bağlam yöneticileri (with tempfile...) kullanın.
Eşzamanlı işleme: Her işleme görevi kendi geçici dosyasına sahiptir. Paralel belge işleme arasında herhangi bir çakışma olmaz.
Disk alanı: Geçici dosyalar, kısa ömürlüdür (işlem süresi boyunca). 500MB'lık bir PDF için, işleme sırasında 500MB geçici alana ihtiyaç vardır. Disk alanı sınırlıysa, boyut sınırı yükleme sırasında uygulanabilir.
Birlikte Çalışan İşlem Arayüzü: Alt Belgeler
PDF çıkarma ve metin belge işleme, aynı aşağı akış hattına (parçalayıcı → gömüler → depolama) beslenmelidir. Bunu, tutarlı bir "ID'ye göre alma" arayüzüyle sağlamak için, çıkarılan metin blokları, "librarian"a alt belgeler olarak geri kaydedilir.
Alt Belgelerle İşlem Akışı
PDF Document Text Document
│ │
▼ │
pdf-extractor │
│ │
│ (stream PDF from librarian) │
│ (extract page 1 text) │
│ (store as child doc → librarian) │
│ (extract page 2 text) │
│ (store as child doc → librarian) │
│ ⋮ │
▼ ▼
[child-doc-id, child-doc-id, ...] [doc-id]
│ │
└─────────────────────┬───────────────────────────────┘
▼
chunker
│
│ (receives document ID)
│ (streams content from librarian)
│ (chunks incrementally)
▼
[chunks → embedding → storage]
Parçalayıcı, tek bir standart arayüze sahiptir: Bir belge kimliğini alın (Pulsar aracılığıyla) Kütüphaneden içeriği akış olarak alın Bunu parçalara ayırın
Bu, kimliğin neye atıfta bulunduğunu bilmez veya umursamaz: Kullanıcı tarafından yüklenen bir metin belgesi Bir PDF sayfasından çıkarılan bir metin bloğu Herhangi bir gelecekteki belge türü
Alt Belge Meta Verileri
Belge şemasını, ana/alt ilişkilerini izlemek için genişletin:
-- 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);
Belge türleri:
document_type |
Açıklama |
|---|---|
source |
Kullanıcı tarafından yüklenen belge (PDF, metin, vb.) |
extracted |
Kaynak bir belgeden türetilmiş (örneğin, PDF sayfa metni) |
Meta veri alanları:
| Alan | Kaynak Belge | Çıkarılan Alt Belge |
|---|---|---|
id |
kullanıcı tarafından sağlanan veya oluşturulan | oluşturulan (örneğin, {parent-id}-page-{n}) |
parent_id |
NULL |
ana belge kimliği |
document_type |
source |
extracted |
kind |
application/pdf, vb. |
text/plain |
title |
kullanıcı tarafından sağlanan | oluşturulan (örneğin, "Rapor.pdf'nin 3. sayfası") |
user |
kimliği doğrulanmış kullanıcı | ana belge ile aynı |
Alt Belgeler için Kütüphaneci API'si
Alt belgeler oluşturma (içerik, pdf-extractor tarafından kullanılır):
{
"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>"
}
Küçük boyutlu, çıkarılmış metinler için (tipik bir sayfa metni < 100KB), tek seferlik yükleme kabul edilebilir. Çok büyük metin çıkarımları için, parçalı yükleme kullanılabilir.
Alt belgelerin listelenmesi (hata ayıklama/yönetim için):
{
"operation": "list-children",
"parent-id": "doc-123"
}
Yanıt:
{
"children": [
{ "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" },
{ "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" },
...
]
}
Kullanıcı Arayüzü Davranışı
list-documents varsayılan davranış:
SELECT * FROM document WHERE user = ? AND parent_id IS NULL;
Yalnızca en üst düzey (kaynak) belgeler, kullanıcının belge listesinde görünür. Alt belgeler, varsayılan olarak filtrelenir.
İsteğe bağlı "çocukları-dahil-et" bayrağı (yönetici/hata ayıklama için):
{
"operation": "list-documents",
"include-children": true
}
Kaskad Sıralı Silme
Bir üst belge silindiğinde, tüm alt belgelerin de silinmesi gerekir:
def delete_document(doc_id: str):
# Find all children
children = query("SELECT id, object_id FROM document WHERE parent_id = ?", doc_id)
# Delete child blobs from S3
for child in children:
blob_store.delete(child.object_id)
# Delete child metadata from Cassandra
execute("DELETE FROM document WHERE parent_id = ?", doc_id)
# Delete parent blob and metadata
parent = get_document(doc_id)
blob_store.delete(parent.object_id)
execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user)
Depolama Hususları
Çıkarılan metin blokları, yinelenen içerik oluşturur: Orijinal PDF, "Garage" (Depo) içinde saklanır. Her sayfa için çıkarılan metin de "Garage" içinde saklanır.
Bu denge şunları sağlar: Tutarlı bir parçalama arayüzü: Parçalayıcı her zaman ID'ye göre veri alır. Devam ettirme/yeniden deneme: PDF'i yeniden çıkarmadan, parçalama aşamasında yeniden başlatılabilir. Hata ayıklama: Çıkarılan metin incelenebilir. Sorumlulukların ayrılması: PDF çıkarıcı ve parçalayıcı bağımsız hizmetlerdir.
200 sayfalık ve sayfa başına ortalama 5KB metin içeren 500MB'lık bir PDF için: PDF depolama: 500MB Çıkarılan metin depolama: ~1MB toplam Ek yük: ihmal edilebilir
PDF Çıkarıcı Çıktısı
pdf-çıkarıcı, bir belgeyi işledikten sonra:
- PDF'i "librarian" (kütüphaneci) üzerinden geçici bir dosyaya aktarır.
- Metni sayfa sayfa çıkarır.
- Her sayfa için, çıkarılan metni "librarian" aracılığıyla bir alt belge olarak saklar.
- Alt belge ID'lerini parçalayıcı kuyruğuna gönderir. ÇIKTI SÖZLEŞMESİ (tam olarak aşağıdaki formatı takip etmelidir):
async def extract_pdf(doc_id: str, librarian_client, output_queue):
"""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)
Parçalayıcı, bu alt kimlikleri alır ve bunları, bir kullanıcının yüklediği bir metin belgesini işlerken olduğu gibi aynı şekilde işler.
İstemci Güncellemeleri
Python SDK
Python SDK'sı (trustgraph-base/trustgraph/api/library.py), parçalı yüklemeleri şeffaf bir şekilde işlemelidir. Kamu arayüzü değişmeden kalır:
# 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"]
)
İçeride, SDK belge boyutunu algılar ve stratejiyi değiştirir:
class Library:
CHUNKED_UPLOAD_THRESHOLD = 2 * 1024 * 1024 # 2MB
def add_document(self, id, title, kind, content, tags=None, ...):
if len(content) < self.CHUNKED_UPLOAD_THRESHOLD:
# Small document: single operation (existing behavior)
return self._add_document_single(id, title, kind, content, tags)
else:
# Large document: chunked upload
return self._add_document_chunked(id, title, kind, content, tags)
def _add_document_chunked(self, id, title, kind, content, tags):
# 1. begin-upload
session = self._begin_upload(
document_metadata={...},
total_size=len(content),
chunk_size=5 * 1024 * 1024
)
# 2. upload-chunk for each chunk
for i, chunk in enumerate(self._chunk_bytes(content, session.chunk_size)):
self._upload_chunk(session.upload_id, i, chunk)
# 3. complete-upload
return self._complete_upload(session.upload_id)
İlerleme geri bildirimleri (isteğe bağlı iyileştirme):
def add_document(self, ..., on_progress=None):
"""
on_progress: Optional callback(bytes_sent, total_bytes)
"""
Bu, kullanıcı arayüzlerinin temel API'yi değiştirmeden yükleme ilerlemesini görüntülemesini sağlar.
Komut Satırı Araçları
tg-add-library-document değişmeden çalışmaya devam ediyor:
# Works transparently for any size - SDK handles chunking internally
tg-add-library-document --file large-report.pdf --title "Large Report"
İsteğe bağlı bir ilerleme durumu göstergesi eklenebilir:
tg-add-library-document --file large-report.pdf --title "Large Report" --progress
# Output:
# Uploading: 45% (225MB / 500MB)
Eski araçlar kaldırıldı:
tg-load-pdf - kullanımdan kaldırıldı, tg-add-library-document'i kullanın.
tg-load-text - kullanımdan kaldırıldı, tg-add-library-document'i kullanın.
Yönetici/hata ayıklama komutları (isteğe bağlı, düşük öncelikli):
# List incomplete uploads (admin troubleshooting)
tg-add-library-document --list-pending
# Resume specific upload (recovery scenario)
tg-add-library-document --resume upload-abc-123 --file large-report.pdf
Bunlar, ayrı araçlar yerine mevcut komuttaki bayraklar olabilir.
API Özellik Güncellemeleri
OpenAPI spesifikasyonu (specs/api/paths/librarian.yaml), aşağıdaki güncellemeleri gerektiriyor:
Yeni işlemler:
begin-upload - Parçalı yükleme oturumunu başlat
upload-chunk - Tek bir parçayı yükle
complete-upload - Yüklemeyi tamamla
abort-upload - Yüklemeyi iptal et
get-upload-status - Yükleme ilerlemesini sorgula
list-uploads - Kullanıcı için tamamlanmamış yüklemeleri listele
stream-document - Akışlı belge alma
add-child-document - Çıkarılan metni kaydet (iç)
list-children - Alt belgeleri listele (yönetici)
Değiştirilen işlemler:
list-documents - include-children parametresini ekle
Yeni şemalar:
ChunkedUploadBeginRequest
ChunkedUploadBeginResponse
ChunkedUploadChunkRequest
ChunkedUploadChunkResponse
UploadSession
UploadProgress
WebSocket spesifikasyonunda yapılan güncellemeler (specs/websocket/):
WebSocket istemcileri için REST işlemlerini yansıtın, böylece yükleme sırasında gerçek zamanlı ilerleme güncellemeleri sağlanır.
Kullanıcı Deneyimi Hususları
API spesifikasyonundaki güncellemeler, ön yüzdeki iyileştirmelere olanak tanır:
Yükleme ilerleme arayüzü: Yüklenen parçaları gösteren ilerleme çubuğu Kalan tahmini süre Duraklatma/devam ettirme özelliği
Hata kurtarma: Kesintiye uğramış yüklemeler için "Yüklemeyi devam ettir" seçeneği Yeniden bağlanırken bekleyen yüklemelerin listesi
Büyük dosya işleme: İstemci tarafında dosya boyutu tespiti Büyük dosyalar için otomatik parçalı yükleme Uzun yüklemeler sırasında net geri bildirim
Bu kullanıcı deneyimi iyileştirmeleri, güncellenmiş API spesifikasyonu tarafından yönlendirilen ön yüz işleme gerektirir.