
कम-मेमोरी graphdb जिसमें Bolt+tls समर्थन, एट-रेस्ट एन्क्रिप्शन और वेक्टर शामिल हैं, जो लोकल रेप्लिका ग्राफ उपयोग-मामलों के लिए डिज़ाइन किया गया है।
वर्तमान संस्करण: v0.25.2 — सभी रिलीज़.
एक पंक्ति में: Slater उन ग्राफ़ों को सेव करता है जो मेमोरी में फिट नहीं होते — करोड़ों नोड और अरबों एज, सिर्फ़ कुछ सौ MB RAM में — मानक Bolt प्रोटोकॉल पर, ताकि कोई भी neo4j ड्राइवर बिना बदलाव के काम करे, ग्राफ़ के बगल में डिस्क-नेटिव वेक्टर सर्च हो, और यह लाइव, स्थायी राइट्स भी स्वीकार करता है बिना उस सुविधा को छोड़े। रेज़िडेंट मेमोरी आपके चुने हुए कैश बजट से तय होती है, ग्राफ़ के आकार से नहीं।
शॉर्टकट
एक ग्राफ़ डेटाबेस डेटा को चीज़ों (नोड्स) और उनके बीच के संबंधों (एज) के रूप में संग्रहीत करता है, जिसमें संबंध प्रथम श्रेणी के नागरिक होते हैं। यही वह चीज़ है जो आप चाहते हैं जब आपके प्रश्न कनेक्शन से संबंधित हों न कि पंक्तियों से — "इस खाते से तीन हॉप्स के भीतर कौन है?", "इस बिल्ड के पीछे पूरी डिपेंडेंसी चेन क्या है?", "कौन से खाते एक डिवाइस, एक पता और एक कार्ड साझा करते हैं?" — ऐसे क्वेरी जो SQL में रिकर्सिव जॉइन का दलदल बन जाते हैं लेकिन ग्राफ़ में स्वाभाविक रूप से निकल आते हैं।
ग्राफ़ डेटाबेस के बारे में सबसे आम शिकायत यह है कि वे RAM में जो समा सकता है उससे आगे स्केल नहीं करते। उनमें से कई (जैसे neo4j, Memgraph, FalkorDB, आदि) पूरे ग्राफ़ को रेज़िडेंट रखते हैं: एक 40 GB ग्राफ़ को 40 GB मेमोरी चाहिए — प्रति इंस्टेंस। प्रति क्षेत्र, प्रति टेनेंट, या प्रति पॉड एक रेप्लिका चाहिए? बिल को गुणा करें। और एक निश्चित आकार से आगे वे लोड ही नहीं होते: उदाहरण के लिए 90 मिलियन नोड / 1.5B-एज Wikidata ग्राफ़ को ~64–128 GiB रेज़िडेंट चाहिए, इसलिए इन-मेमोरी इंजन इसे खोल ही नहीं सकते।
Slater इसका जवाब है। ग्राफ़ को मेमोरी में लोड करने के बजाय, यह इसे एक बार, ऑफ़लाइन कंपाइल करता है: slater-build आपके डेटा को एक content-addressed, अपरिवर्तनीय ऑन-डिस्क इमेज में बदल देता है, और कोई भी संख्या में Slater सर्वर उस इमेज को Bolt पर सेव करते हैं (ताकि आपके मौजूदा neo4j ड्राइवर बस काम करें), ब्लॉक्स को मांग पर पेज करते हुए और केवल एक निश्चित कैश बजट रेज़िडेंट रखते हुए। इसी तरह वही 90M-नोड ग्राफ़ कुछ सौ MB RAM से सेव होता है — ग्राफ़ का आकार और मेमोरी बिल अलग हो जाते हैं। एक 4 GB ग्राफ़ और एक 400 GB ग्राफ़ को सेव करने के लिए समान RAM खर्च होती है, इसलिए आप सस्ते, स्टेटलेस रीड रेप्लिका फैला सकते हैं और ग्राफ़ को हीप के बजाय स्टोर में रख सकते हैं।
यह इसे RAG के पीछे नॉलेज ग्राफ़, रिकमेंडेशन और आइडेंटिटी ग्राफ़, डिपेंडेंसी ग्राफ़ — किसी भी बड़ी और जुड़ी हुई चीज़ के लिए स्वाभाविक फिट बनाता है जिसे आप सस्ते और बार-बार क्वेरी करना चाहते हैं। डिस्क-नेटिव वेक्टर सर्च ग्राफ़ के ठीक बगल में रहता है, इसलिए वही इंजन एम्बेडिंग के लिए भी रिट्रीवल लेयर है।
हालाँकि, एक बार कंपाइल होने का मतलब जमा हुआ नहीं है। वह इमेज एक बेस है, अंतिम स्थिति नहीं: उसके ऊपर एक ऑप्ट-इन राइट लेयर बैठती है, ताकि एक लाइव ग्राफ़ को बिना कुछ रीबिल्ड किए सही और विस्तारित किया जा सके।
कोर अपरिवर्तनीय है; ग्राफ़ नहीं है। राइटेबल लेयर चालू करें (delta.enabled) और आप Bolt पर लिखें — एक प्रॉपर्टी सही करें, एक नोड जोड़ें, एक एज वापस लें — और परिवर्तन स्थायी रूप से दर्ज हो जाता है, इमेज के किसी रीबिल्ड के बिना। रीड साइड पर इसे सस्ता रखने वाली चीज़ राइट्स कहाँ रहते हैं है।
राइट्स एक log-structured-merge (LSM) लेयर में अपरिवर्तनीय कोर के ऊपर जमा होते हैं: एक write-ahead log और एक इन-मेमोरी टेबल, जो अपरिवर्तनीय डेल्टा सेगमेंट में फैलती है, और एक आवधिक कंसोलिडेशन द्वारा एक नए कोर में वापस मोड़ दी जाती है। इससे आपको क्या मिलता है:
count(*), लेबल और रिलेशनशिप-टाइप मार्जिनल — राइट्स बकाया होने पर भी मेटाडेटा रीड्स बने रहते हैं: डेल्टा अपने स्वयं के काउंटर रखता है, इसलिए 91.6M-नोड कोर पर आधे मिलियन लंबित राइट्स के साथ count(*) अभी भी दसियों मिलीसेकंड में उत्तर देता है बिना एक भी ब्लॉक छुए।SUCCESS केवल उस fsync के बाद लौटाता है जो राइट को कवर करता है। अपने राइट्स को समूहित करें और वे सस्ते होते हैं — एक write-UNWIND प्रति बैच एक fsync कमिट करता है न कि प्रति पंक्ति।MERGE / MATCH … SET / DELETE (और CREATE / REMOVE, डिटैच डिलीट, रिलेशनशिप राइट्स) जो नोड की आइडेंटिटी प्रॉपर्टी पर की जाती हैं — या समकक्ष ISO GQL डेटा-संशोधित स्टेटमेंट ( / / / ), जो उसी पाथ पर उतरते हैं। सही करें, इन्सर्ट करें, अपसर्ट करें और वापस लें, नोड्स और एज पर, उसी तरह संबोधित करें जैसे आपका डेटा पहले से है।लेयर बंद होने पर — डिफ़ॉल्ट — Slater शुद्ध अपरिवर्तनीय कोर सेव करता है और राइट्स से इनकार करता है। पूर्ण मॉडल के लिए द राइटेबल लेयर देखें।
नाम पर। Slater का नाम Archer (एक बेहतरीन शो) में CIA एजेंट के नाम पर रखा गया है जो एक ही नाम से चलने पर ज़ोर देता है — "बस… Slater" — और मेरे पसंदीदा पात्रों में से एक है। देखें कैरेक्टर विकी पेज।
MERGE / SET / DELETE, ग्रुप-कमिटेड और fsync-स्थायी, कंसोलिडेशन द्वारा एक नए कोर में वापस मोड़ा गया। रीड्स इसके लिए भुगतान नहीं करते।current पॉइंटर को परमाणु रूप से फ्लिप करें, और सर्वर इसे उठा लेते हैं। हर ब्लॉक checksummed है, इसलिए आधी-कॉपी की गई इमेज को सेव करने के बजाय अस्वीकार कर दिया जाता है।वर्कस्पेस दो बाइनरी से बना है:
| बाइनरी | भूमिका |
|---|---|
slater | ऑनलाइन Bolt सर्वर (कंटेनर ENTRYPOINT): रीड्स सेव करता है और, delta.enabled के साथ, सिंगल-राइटर स्थायी राइट पाथ। |
slater-build | ऑफ़लाइन कंपाइलर: एक primitive-Cypher डंप को एक अपरिवर्तनीय, content-hashed जनरेशन डायरेक्टरी में बदल देता है। |
Slater बल्क बिल्डिंग को सर्विंग से अलग करता है: slater-build भारी काम ऑफ़लाइन करता है — आपके डेटा को इन्जेस्ट करके एक अपरिवर्तनीय जनरेशन में कंपाइल करता है — इसलिए एक कोल्ड ग्राफ़ कभी सर्विंग हॉट पाथ पर असेंबल नहीं होता। सर्वर के भीतर, रीड सतह एक व्यापक Cypher स्लाइस का उत्तर देती है — पैटर्न मैचिंग, WITH/UNION/CALL {…} सबक्वेरी, 70+ स्केलर और एग्रीगेट फ़ंक्शन, टेम्पोरल और जियोस्पेशियल मान, ग्राफ़ एल्गोरिदम (algo.*), और डिस्क-नेटिव वेक्टर KNN (db.idx.vector.queryNodes) — जबकि राइटेबल लेयर का डेल्टा ओवरले उस सतह के नीचे बैठता है और खाली होने पर शून्य-लागत है, इसलिए रीड्स कभी राइट-साइड मशीनरी नहीं ले जाते। आप एक ग्राफ़ को दो तरीकों से अपडेट कर सकते हैं: Bolt पर लाइव लिखें (देखें द राइटेबल लेयर), या एक नई जनरेशन ऑफ़लाइन बनाएँ और current पॉइंटर को परमाणु रूप से स्वैप करें, जिसे चल रहा सर्वर अपने जनरेशन गार्ड के माध्यम से उठा लेता है (देखें जनरेशन गार्ड)।
पूर्ण उपयोगकर्ता मैनुअल docs/manual/ में है — एक फ़ीचर-दर-फ़ीचर गाइड जो हर क्षमता के लिए समझाता है कि यह क्या है, क्यों मौजूद है, और इसका उपयोग कैसे करें, बंडल किए गए नमूना ग्राफ़ के खिलाफ चलाए जा सकने वाले काम के उदाहरणों के साथ। इस अवलोकन से आगे किसी भी चीज़ के लिए वहीं से शुरू करें।
graphiti-slater एक एडाप्टर है जो Graphiti को अपने टेम्पोरल नॉलेज ग्राफ़ को Slater में संग्रहीत करने देता है, एक चलाने योग्य docker-example/ के साथ — जिसमें इसे Claude Code को MCP सर्वर के रूप में एक्सपोज़ करना शामिल है। यह कैसे काम करता है और इसे कैसे चलाना है, इसके लिए उस रिपॉज़िटरी को देखें।
docker pull hikarisystems/slater:latest
Docker-कमांड-केवल उपयोग, कॉन्फ़िगरेशन और संचालन गाइड
[`DOCKERHUB.md`](https://github.com/hikari-systems/slater/blob/main/DOCKERHUB.md) में रहता है (और Docker Hub अवलोकन पृष्ठ पर मिरर किया गया है) —
**यदि आप डिप्लॉय कर रहे हैं तो वहीं से शुरू करें।** संक्षेप में:```sh
# Build a graph generation with the offline writer:
docker run --rm -v slater-data:/data -v "$PWD/dumps:/dumps:ro" \
--entrypoint /app/slater-build hikarisystems/slater:latest \
--input /dumps/people.cypher --graph people --data-dir /data
# Serve it over Bolt on 7687 (read-only unless `delta.enabled`):
docker run -d --name slater -p 7687:7687 \
-v slater-data:/data:ro -v "$PWD/acl.json:/config/acl.json:ro" \
hikarisystems/slater:latest
छवि को स्थानीय रूप से बनाने के लिए (जैसे विकास के लिए):```sh
docker compose build
docker compose up slater
build):docker compose run --rm builder
--input /dumps/people.cypher --graph people --data-dir /data
बिल्डर स्टेज `rustls` के `aws-lc-rs` बैकएंड के लिए `cmake`, `clang` और `libclang-dev` इंस्टॉल करता है; `git` (जो पहले से बेस इमेज में मौजूद है) `hs-utils` की git+tag निर्भरता के लिए आवश्यक है, जिसे `.cargo/config.toml` git CLI के माध्यम से प्राप्त करता है।
नीचे दिए गए अनुभाग डिस्क-फॉर्मेट, कॉन्फ़िगरेशन, ACLs, और एक स्थानीय (गैर-Docker) कार्यशील उदाहरण को कवर करते हैं।
## यह कैसे काम करता है```
slater-build slater (Bolt server)
dump.cypher ──────────▶ /data/<graph>/<uuid>/ ──────────▶ neo4j driver
(offline, atomic) MANIFEST.json, *.blk, (bolt / bolt+s)
range/*.isam, vector/*.{vamana,pq},
current → <uuid>
MANIFEST.json (प्रतीक तालिकाएँ,
इंडेक्स डिस्क्रिप्टर, एक वैकल्पिक एन्क्रिप्शन हेडर), कॉलमर ब्लॉक फ़ाइलें
(node_props.blk, node_labels.blk, edge_props.blk, topology.csr.blk,
vectors.f32.blk), रेंज इंडेक्स (range/<name>.isam), थ्रेशोल्ड-ऊपर ANN
इंडेक्स (vector/<label>.<prop>.{vamana,pq}), और एक current टेक्स्ट पॉइंटर।--encrypt के साथ प्रत्येक
ब्लॉक को अतिरिक्त रूप से XChaCha20-Poly1305 (आराम पर AEAD) से सील किया जाता है।delta.enabled के साथ, अपरिवर्तनीय जनरेशन एक छोटे लॉग-स्ट्रक्चर्ड-मर्ज ट्री का
पूरी तरह से कॉम्पैक्ट किया गया निचला स्तर (कोर) बन जाता है, और लाइव राइट्स
उसके ऊपर सवार होते हैं:```
write (Bolt) read (Bolt)
│ │
▼ ▼
┌──────────────┐ flush ┌──────────────┐ ┌──────────────────────┐
│ WAL + active │ ───────▶ │ L0 delta │ │ a query pins one │
│ memtable │ │ segments │ │ (core, delta) view │
└──────────────┘ └──────┬───────┘ │ and reads the merge │
(fsync = ack) │ └──────────────────────┘
consolidation │ (folds core + delta → fresh core)
▼
┌─────────────┐
│ new core │ (atomic current swap)
└─────────────┘
* **स्थायित्व की निचली सीमा — WAL।** प्रत्येक म्यूटेशन प्रति ग्राफ एक ही
राइटर के पीछे क्रमबद्ध (serialised) होता है, प्रति ग्राफ राइट-अहेड लॉग में जोड़ा
जाता है, और Bolt `SUCCESS` लौटाने से पहले `fsync` किया जाता है — इसलिए *स्वीकृत ⇒ स्थायी*,
और रिप्ले पर एक फटी हुई पूँछ (torn tail) हटा दी जाती है। एक बैच किया गया राइट-`UNWIND`
अपनी पंक्तियाँ जोड़ता है और पूरे बैच के लिए **एक** `fsync` कमिट करता है। WAL **केवल
स्थानीय डिस्क** है (इसे स्टोरेज बैकएंड के माध्यम से रूट नहीं किया जाता), जो *राइटर*
नोड को स्टेटफुल बनाता है: इसे `delta.walDir` पर एक स्थायी स्थानीय वॉल्यूम चाहिए।
रीड रेप्लिका स्टेटलेस रहती हैं।
* **मेमटेबल → L0 → समेकन (consolidation)।** राइट्स एक इन-रैम मेमटेबल में जमा होते हैं
(`delta.memtableBytes` द्वारा सीमित); जब यह भर जाता है तो यह एक अपरिवर्तनीय L0
डेल्टा सेगमेंट में फ्लश होता है। एक **समेकन** मर्ज किए गए दृश्य को `slater-build` के
माध्यम से वापस क्रमबद्ध करके और `current` को परमाणु रूप से बदलकर `{core + delta}` को
एक नए core में मोड़ता है — किसी भी प्रकाशित जनरेशन के समान कंटेंट-हैश गार्ड। इसे हाथ से
`CALL slater.consolidate()` के साथ ट्रिगर करें, core के आकार के `delta.deltaCorePercent`
पर स्वचालित रूप से (वैकल्पिक रूप से ऑफ-पीक `delta.consolidateWindow` तक सीमित), या
`delta.deltaHardBytes` थ्रॉटल को अनियंत्रित वृद्धि के लिए बैकस्टॉप के रूप में काम करने दें।
* **ओवरले रीड सतह के नीचे बैठता है।** एक्ज़ीक्यूटर एक `ReadView` के माध्यम से पढ़ता है
जो या तो नंगा core है (डेल्टा हमेशा खाली) या एक मर्ज किया गया `(core, delta)` दृश्य;
इंजन इसके ऊपर मोनोमोर्फाइज़्ड है, इसलिए एक खाली डेल्टा एक ही पूर्वानुमानित शाखा में
संकलित होता है और केवल-पढ़ने वाला पथ बाइट-समान होता है। पूरे-ग्राफ काउंटर (`count(*)`,
लेबल/रेलटाइप मार्जिनल) डेल्टा के अपने लाइव काउंटर से परोसे जाते हैं, इसलिए वे लंबित
राइट्स के साथ भी मेटाडेटा रीड बने रहते हैं।
* **एक क्वेरी एक स्थिर स्नैपशॉट देखती है।** यह अपने पूरे जीवन के लिए एक `(core, delta)`
टपल को पिन करती है। कोई मल्टी-स्टेटमेंट ट्रांज़ैक्शन और कोई रोलबैक नहीं है — एक राइट
एक स्थायी, बिज़नेस-की-एड्रेस्ड सुधार है, OLTP ट्रांज़ैक्शन नहीं।
सटीक राइट व्याकरण और नॉब्स [Configuration](#environment--configuration)
तालिका (`delta.*`) और नीचे [Worked example](#worked-example) में हैं।
### रेंज इंडेक्स (ISAM)
एक रेंज इंडेक्स (`range/<name>.isam`, प्रति अनुक्रमित `(label, property)` एक) एक
`MATCH (n:Label {prop: v})` या `WHERE n.prop <op> v` को **लेबल को स्कैन किए बिना**
मिलान करने वाले नोड आईडी तक हल करने देता है। यह एक
**[ISAM](https://en.wikipedia.org/wiki/ISAM)** (Indexed Sequential Access Method)
संरचना है — क्लासिक *स्टैटिक, सॉर्टेड, ब्लॉक-स्ट्रक्चर्ड* इंडेक्स, जो एक अपरिवर्तनीय
जनरेशन के लिए बिल्कुल सही आकार है: रीबैलेंस करने के लिए कोई इंसर्ट नहीं हैं, इसलिए
ISAM की सरलता वह खरीदती है जिसे B-ट्री का म्यूटेशन तंत्र केवल जटिल बनाता।
* एंट्रीज़ `(value, entity_id)` मान के अनुसार सॉर्ट की जाती हैं और बाकी सब कुछ के
समान zstd-संपीड़ित 256 KiB ब्लॉक में पैक की जाती हैं।
* एक छोटा **रेजिडेंट टॉप-लेवल** प्रत्येक ब्लॉक की पहली कुंजी रखता है (एक स्पार्स
इंडेक्स)। एक लुकअप उस इन-मेमोरी टॉप लेवल को बाइनरी-सर्च करता है ताकि वह *एक* ब्लॉक
ढूंढ सके जिसमें एक कुंजी हो सकती है, उस ब्लॉक को पढ़ता + डीकंप्रेस करता है, और उसे
स्कैन करता है — इसलिए एक समानता लुकअप **एक ब्लॉक रीड** है, और एक रेंज स्कैन उन ब्लॉकों
के सन्निहित रन को चलता है जिन्हें वह कवर करता है। (यही कारण है कि एक `meshUi`-अनुक्रमित
लुकअप एकल-अंक मिलीसेकंड है जबकि एक अनुक्रमित संपत्ति पर समान मैच पूरे लेबल को स्कैन करता है।)
* प्लानर इसे `NodeScan::RangeEq` / `RangeRange` के माध्यम से चुनता है; एक अनुक्रमित
विधेय लेबल स्वीप या पूर्ण स्कैन पर वापस आ जाता है, एक्ज़ीक्यूटर किसी भी तरह से हर
विधेय को फिर से जाँचता है।
### वेक्टर खोज (Vamana + PQ) — cosine, L2 और dot, रीड *और* राइट
वेक्टर KNN (`db.idx.vector.queryNodes`) **cosine, L2, या dot-product (MIPS)**
इंडेक्स पर चलता है। बेस इंडेक्स ऑफ़लाइन दो निष्पादन पथों के साथ बनाया जाता है, प्रति इंडेक्स
`--ann-threshold` (डिफ़ॉल्ट 50 000 वेक्टर) द्वारा चुना जाता है:
* **थ्रेशोल्ड से नीचे — ब्रूट फोर्स।** पूर्ण `f32` वेक्टर `vectors.f32.blk` में रहते हैं;
एक क्वेरी इंडेक्स के समूह को स्कैन करती है और इंडेक्स के मीट्रिक में सटीक दूरी की गणना करती है।
सरल और सटीक; ठीक है जब वेक्टर सेट छोटा हो।
* **थ्रेशोल्ड पर या उससे ऊपर — Vamana + PQ**, डिस्क-नेटिव ANN पथ जो रेजिडेंट
मेमोरी को सीमित रखता है चाहे कितने भी वेक्टर हों:
* **[Vamana](https://arxiv.org/pdf/2401.11324)** DiskANN कार्य की श्रृंखला से ग्राफ इंडेक्स है:
एक एकल प्रॉक्सिमिटी ग्राफ जिसके किनारों को छंटनी की जाती है (the
`--vamana-r` आउट-डिग्री और `--vamana-alpha` लॉन्ग-एज फैक्टर) ताकि एक *ग्रीडी
बीम सर्च* — मेडॉइड से शुरू करें, बार-बार क्वेरी की ओर कूदें, चौड़ाई की उम्मीदवार सूची रखते हुए
`vectorQuery.beamWidth` — कुछ ही हॉप्स में एक नोड के सच्चे पड़ोसियों तक पहुँचता है, यानी
**प्रति क्वेरी कुछ रैंडम ब्लॉक रीड**। ग्राफ ब्लॉक (`vector/<label>.<prop>.vamana`) वेक्टर कैश के
माध्यम से पेज किए जाते हैं, पूरी तरह से नहीं रखे जाते।
* **[प्रोडक्ट क्वांटाइज़ेशन (PQ)](https://medium.com/aiguys/product-quantization-k-nn-for-big-datasets-12431d764c4e)**
प्रत्येक वेक्टर को एक छोटे कोड में संपीड़ित करता है (`--pq-subspaces` × `--pq-bits`):
आयामों को सबस्पेस में विभाजित किया जाता है, प्रत्येक स्वतंत्र रूप से k-means-क्लस्टर किया जाता है, और
वेक्टर को निकटतम-सेंट्रॉइड आईडी के टपल के रूप में संग्रहीत किया जाता है। ये कोड
(`vector/<label>.<prop>.pq`) **रेजिडेंट** रखने के लिए पर्याप्त छोटे हैं, इसलिए
बीम सर्च RAM से उम्मीदवारों को स्कोर करता है और केवल चुने हुए कुछ पूर्ण वेक्टर ही
डिस्क से पढ़े जाते हैं। वह रेजिडेंट PQ सेट वही है जिसे `cache.vectorCacheBytes` पूल
पिन करता है।
**राइटेबल एम्बेडिंग — वेक्टर राइट सीढ़ी ([FreshDiskANN](https://arxiv.org/abs/2105.09613)-शैली)।**
एक अनुक्रमित एम्बेडिंग एक प्रथम श्रेणी का राइटेबल मान है। `SET n.embedding = vecf32([…])` (और `REMOVE`) राइट
डेल्टा में उतरता है और **सटीक रैंक के साथ तुरंत KNN-दृश्यमान** होता है, फिर एक सेगमेंट
फ्लश, एक मर्ज और एक समेकन से बच जाता है। एक क्वेरी तीन स्तरों तक मर्ज करती है — सील किया गया बेस
इंडेक्स, एक सील किया गया प्रति-सेगमेंट इंडेक्स, और एक इन-मेमोरी **RW-इंडेक्स** (राइट डेल्टा पर एक लाइव म्यूटेबल Vamana)
— इसलिए लेटेंसी स्थिर रहती है क्योंकि राइट्स जमा होते हैं, लंबित राइट्स की गिनती के साथ बढ़ने के बजाय। एक डिलीट एक *छेद* छोड़ती है: नोड लौटाया जाना बंद हो जाता है
लेकिन एक नेविगेशनल वेपॉइंट बना रहता है जब तक कि एक बैकग्राउंड **डिलीट-समेकन** इसे
ग्राफ से बाहर नहीं निकालता, इसलिए डिलीट क्वेरी IO की लागत रोक देते हैं। और क्योंकि ऑन-डिस्क ग्राफ
अपने पड़ोसियों को नोड आईडी के बजाय लेआउट स्थिति से संबोधित करता है, `CALL slater.consolidate()`
Vamana को **संदर्भ द्वारा** ले जाता है — हार्ड-लिंक्ड, बाइट-समान — और केवल एक
छोटा आईडी कॉलम फिर से लिखता है, वेक्टर राइट्स को O(N·R·L) ग्राफ
रीबिल्ड **के बिना** बेस में मोड़ता है। मापे गए नंबर, चेतावनियों के साथ, [performance report](https://github.com/hikari-systems/slater/blob/main/docs/PERF-REPORT.md) में हैं।
## स्टोरेज बैकएंड (filesystem / S3 / GCS)
प्रत्येक जनरेशन फ़ाइल `std::fs` के बजाय सीधे एक **`ObjectStore`** अमूर्तता के माध्यम से खोली जाती है,
इसलिए *समान* ऑन-डिस्क बाइट प्रारूप — ब्लॉक, इंडेक्स,
मैनिफेस्ट, `current` पॉइंटर — किसी भी बैकएंड से अपरिवर्तित परोसा जाता है; केवल *बाइट्स कहाँ से आते हैं*
भिन्न होता है, कभी भी रीडर, क्वेरी इंजन, या
अखंडता जाँच नहीं। हॉट पथ स्थितीय रीड (`read_exact_at`) है, जो
स्थानीय फ़ाइल पर `pread` और ऑब्जेक्ट स्टोर पर HTTP बाइट-रेंज अनुरोध पर मैप करता है
— Slater कभी mmap नहीं करता, इसलिए स्पष्ट, सीमित-रीड मॉडल हर जगह समान है।
**तीन प्रथम श्रेणी के बैकएंड**, `dataBackend.kind` द्वारा चुने गए। फाइलसिस्टम
सरल डिफ़ॉल्ट है; **Amazon S3 और Google Cloud Storage समान, पूरी तरह से
समर्थित ऑब्जेक्ट-स्टोर बैकएंड हैं** — प्रकाशित इमेज दोनों के साथ संकलित आती है,
इसलिए प्रत्येक केवल-कॉन्फ़िगरेशन है, और एक बार बनाया गया जनरेशन उनमें से किसी से भी परोसा जा सकता है
(यहाँ तक कि `fs` → S3 → GCS माइग्रेट किया गया) बिना रीबिल्ड के।
| `dataBackend.kind` | स्थितीय रीड | खोलने पर अखंडता | क्रेडेंशियल |
| --- | --- | --- | --- |
| `fs` *(डिफ़ॉल्ट)* | `pread` | प्रत्येक फ़ाइल का पूर्ण BLAKE3 पुनः-हैश | — |
| `s3` | HTTP `Range` GET | सर्वर **SHA-256** `HEAD` के माध्यम से (→ BLAKE3 बॉडी पुनः-हैश यदि अनुपस्थित) | कॉन्फ़िग कुंजियाँ, AWS चेन, या IAM भूमिका |
| `gcs` | HTTP रेंज रीड | सर्वर **CRC32C** `get_object` के माध्यम से (→ BLAKE3 बॉडी पुनः-हैश यदि अनुपस्थित) | ADC / Workload Identity, या सेवा-खाता JSON |
दोनों ऑब्जेक्ट स्टोर उस **चेकसम से अखंडता सत्यापित करते हैं जिसे स्टोर पहले से
गणना और रखता है**, ऑब्जेक्ट मेटाडेटा के रूप में प्राप्त: `slater-build` अपलोड पर
चेकसम भेजता है (स्टोर इसके विरुद्ध बाइट्स को मान्य करता है और इसे संग्रहीत करता है), और
सर्वर इसे खोलने पर वापस पढ़ता है और मैनिफेस्ट से तुलना करता है — प्रति
फ़ाइल एक मेटाडेटा अनुरोध, कोई बॉडी डाउनलोड नहीं। यह कंटेंट-ग्रेड है और S3 (SHA-256) और GCS (CRC32C) में आत्मा में समान है। जब एक ऑब्जेक्ट **कोई** सर्वर-संग्रहीत
चेकसम नहीं रखता (बैंड-आउट में कॉपी किया गया, या एक अलग डिफ़ॉल्ट के साथ अपलोड किया गया), सर्वर
अपनी बाइट लंबाई पर भरोसा करने के बजाय **मैनिफेस्ट BLAKE3 के विरुद्ध ऑब्जेक्ट बॉडी को पुनः-हैश करता है**
— एक अनुरोधित अखंडता जाँच कभी भी चुपचाप आकार
तुलना में डाउनग्रेड नहीं होती। Slater-प्रकाशित जनरेशन हमेशा चेकसम रखते हैं, इसलिए वे
सस्ते मेटाडेटा पथ पर रहते हैं।
यह कॉलम, हर बैकएंड पर, जाँचता है कि फ़ाइलें **मैनिफेस्ट से मेल खाती हैं**।
क्या मैनिफेस्ट पर भरोसा किया जा सकता है यह एक अलग प्रश्न है, और यही
मास्टर कुंजी है जो इसका उत्तर देती है: एक कुंजी कॉन्फ़िगर होने पर मैनिफेस्ट एक कुंजीयुक्त MAC रखता है
जिसे सर्वर किसी भी फ़ील्ड (इन हैशों सहित) पर भरोसा करने से पहले सत्यापित करता है, इसलिए एक
छेड़छाड़ की गई फ़ाइलों का वर्णन करने के लिए फिर से लिखा गया मैनिफेस्ट अस्वीकार कर दिया जाता है; एक कुंजी के बिना तुलना पूरी तरह से अकुंजीयुक्त है, और
कोई व्यक्ति जो डेटा निर्देशिका में लिख सकता है वह एक फ़ाइल और मैनिफेस्ट को
एक साथ फिर से लिख सकता है। देखें
[What integrity means in each configuration](https://github.com/hikari-systems/slater/blob/main/THREAT_MODEL.md#what-integrity-means-in-each-configuration)।
जाँच को स्वयं `dataBackend.verifyIntegrity: false` के साथ बंद किया जा सकता है, जो
इसे तेज़ खोलने के लिए बदल देता है।
### फाइलसिस्टम (`fs`)
डिफ़ॉल्ट, `dataBackend.fs.dir` पर आधारित। अधिकांश
परिनियोजनों के लिए सही विकल्प: स्थानीय SSD (या NFS/EBS माउंट) पर एक जनरेशन केवल-पढ़ने के लिए परोसा जाता है।
अखंडता खोलने पर हर फ़ाइल का पूर्ण BLAKE3 पुनः-हैश है।
### Amazon S3 (`s3`)
एक S3 या S3-संगत बकेट (AWS, MinIO, localstack)। क्रेडेंशियल **पहले**
कॉन्फ़िग से आते हैं (`dataBackend.s3.awsAccessKey` / `awsSecretKey`, साथ ही
अस्थायी STS क्रेडेंशियल के लिए `awsSessionToken`) और मानक AWS
चेन (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` env, साझा प्रोफ़ाइल, या
इंस्टेंस/IRSA भूमिका) पर वापस आते हैं जब खाली छोड़ दिया जाता है।```sh
# serve from S3 (env-var form; see the config table for every key)
dataBackend__kind=s3
dataBackend__s3__bucket=slater
dataBackend__s3__region=eu-west-2
dataBackend__s3__awsAccessKey=… # omit to use the AWS chain / instance role
dataBackend__s3__awsSecretKey=…
# S3-compatible (e.g. MinIO): also set
dataBackend__s3__endpoint=http://minio:9000
dataBackend__s3__pathStyle=true # required by most S3-compatible servers
# publish a generation into the bucket (remote `current` pointer written last)
slater-build --input people.cypher --graph people --data-dir /data \
--publish-s3-bucket slater --publish-s3-region eu-west-2 --publish-s3-prefix prod
# MinIO: add --publish-s3-endpoint http://localhost:9000 --publish-s3-path-style
gcs)एक GCS बकेट, जो JSON API के माध्यम से एक्सेस की जाती है। प्रमाणीकरण GCP-मूल है: डिफ़ॉल्ट रूप से यह
Application Default Credentials को हल करता है — GKE Workload Identity, GCE
मेटाडेटा सर्वर, या एक gcloud / GOOGLE_APPLICATION_CREDENTIALS कुंजी। सेट करें
dataBackend.gcs.credentialsPath (एक service-account JSON key फ़ाइल) या इनलाइन
credentialsJson एक स्पष्ट कुंजी के लिए। dataBackend.gcs.endpoint एक
fake-gcs-server एमुलेटर की ओर इशारा करता है, और dataBackend.gcs.anonymous=true अप्रमाणित
एक्सेस को सक्षम करता है केवल उस एमुलेटर के लिए — वास्तविक GCS के विरुद्ध कभी नहीं।```sh
dataBackend__kind=gcs dataBackend__gcs__bucket=slater dataBackend__gcs__prefix=prod dataBackend__gcs__credentialsPath=/secrets/sa.json # omit for ADC / Workload Identity
```sh
# publish a generation into the bucket (remote `current` pointer written last)
slater-build --input people.cypher --graph people --data-dir /data \
--publish-gcs-bucket slater --publish-gcs-prefix prod
# explicit key: add --publish-gcs-credentials /secrets/sa.json
सभी मामलों में slater-build पहले तैयार जनरेशन को --data-dir में लिखता है
(इसका स्थानीय स्टेजिंग क्षेत्र) और इसके अतिरिक्त इसे बकेट पर अपलोड करता है; रिमोट
current पॉइंटर सबसे अंत में लिखा जाता है, इसलिए एक सर्विंग नोड कभी भी आधा-प्रकाशित
जनरेशन नहीं देखता।
s3 या gcs का उपयोग तब करें जब आप जनरेशन को नोड की डिस्क के बजाय टिकाऊ, केंद्रीय ऑब्जेक्ट
स्टोरेज में चाहते हैं — आम तौर पर: एक बार प्रकाशित करें और कई स्टेटलेस, डिस्क-रहित सर्वर
प्रतिकृतियों में फैलाएं जो सभी एक ही बकेट पढ़ते हैं; बिल्ड होस्ट को सर्व होस्ट से अलग करें;
या स्टोर की स्थायित्व/संस्करण/लाइफसाइकिल सुविधाओं पर निर्भर रहें, वॉल्यूम प्रबंधित करने के
बजाय। ट्रेड-ऑफ़ विलंबता है: एक कोल्ड ब्लॉक एक नेटवर्क राउंड-ट्रिप (~10–50 ms) है, स्थानीय
रीड (~0.1 ms) के बजाय। Slater इन-मेमोरी ब्लॉक कैश, समवर्ती रीड-अहेड, और नीचे दिए गए
वैकल्पिक डिस्क कैश के साथ इसका अधिकांश हिस्सा छिपा देता है। यदि आपके जनरेशन पहले से ही तेज़
स्थानीय स्टोरेज पर हैं और आपको केंद्रीय-बकेट मॉडल की आवश्यकता नहीं है, तो fs सरल और तेज़ है।
इन-मेमोरी BlockCache जानबूझकर छोटा है (बाउंडेड RSS मुख्य गारंटी है),
इसलिए RAM से बड़े कार्यशील सेट पर वही ब्लॉक हर स्पिल पर ऑब्जेक्ट स्टोर से फिर से
लाए जाएंगे। एक वैकल्पिक स्थानीय-SSD दूसरा कैश स्तर इसे ठीक करता है: RAM से
निकाला गया ब्लॉक ताज़ा ऑब्जेक्ट GET के बजाय स्थानीय डिस्क (~0.1 ms) से परोसा जाता है,
इन-मेमोरी निष्कासन से बचता है और ऑब्जेक्ट-स्टोर अनुरोध/लागत को कम करता है — एक
ऑब्जेक्ट-स्टोर-समर्थित नोड को गर्म होने पर स्थानीय-फाइलसिस्टम प्रदर्शन के करीब लाता है।
यह s3 और gcs दोनों के लिए ऑप्ट-इन है, जो dataBackend.<s3|gcs>.diskCacheBytes > 0
और एक लिखने योग्य diskCacheDir सेट करके सक्षम होता है।
--encrypt जनरेशन के लिए) अभी भी AEAD-सील — डिक्रिप्ट/डीकंप्रेस के नीचे।
कैश परत कभी भी एन्क्रिप्शन कुंजी नहीं रखती और कभी पुनः-एन्क्रिप्ट नहीं करती, इसलिए
आराम-स्थिति स्थिति मुफ्त में संरक्षित रहती है: एक एन्क्रिप्टेड जनरेशन डिस्क पर अभी भी
सील होकर उतरता है।diskCacheDir एक वास्तविक लिखने योग्य वॉल्यूम पर इंगित करना चाहिए — कभी tmpfs नहीं
(tmpfs RAM है और बाउंडेड-RSS गारंटी को विफल कर देगा)। इसे ट्रैक करने वाला इन-मेमोरी इंडेक्स
थोड़ी RAM खर्च करता है (~प्रति कैश ब्लॉक दसियों बाइट्स), जो आपकी RSS सीमा के खिलाफ गिना जाता
है — निर्देशिका को इन-मेमोरी ब्लॉक कैश से ≫ आकार दें।blockCacheBytes / 8 पर बाउंडेड है (diskCacheBytes द्वारा फ्लोर किया गया) — डिफ़ॉल्ट पर
8 MiB — और बढ़ने के बजाय कम होता है, इसलिए एक कोल्ड स्कैन इसे बढ़ा नहीं सकता; एक कम किया गया
ब्लॉक अपने अगले मिस पर बस पुनः प्राप्त करता है। इसे किसी कॉन्फ़िगरेशन की आवश्यकता नहीं है:
यह blockCacheBytes के साथ स्केल करता है, इसलिए डिस्क स्तर अपने इंडेक्स से परे RSS बजट में
कोई नया नंबर नहीं जोड़ता।एक रीड रेप्लिका रीड-ओनली रूट फाइलसिस्टम और एक गैर-रूट उपयोगकर्ता
(appuser:1000) के साथ चलती है — इसे जो कुछ भी चाहिए वह रीड-ओनली माउंट किया जाता है। एक
राइटर (delta.enabled) को अपने WAL के लिए अतिरिक्त रूप से एक टिकाऊ, लिखने योग्य वॉल्यूम की आवश्यकता होती है।
कॉन्फ़िग हाउस-मानक स्तरित लोडर द्वारा लोड किया जाता है: बेक-इन config.json,
फिर /sandbox/config.json उस पर डीप-मर्ज किया जाता है, फिर KEY__sub पर्यावरण
ओवरराइड (नेस्टिंग के लिए डबल अंडरस्कोर; कुंजियाँ camelCase कॉन्फ़िग से मेल खाती हैं)।
हर कॉन्फ़िगरेशन नॉब — इसकी camelCase कुंजी, KEY__sub पर्यावरण ओवरराइड, इसका डिफ़ॉल्ट, और यह क्या करता है — कॉन्फ़िगरेशन संदर्भ में सारणीबद्ध है। सबसे अधिक ट्यून किए गए नॉब कैश बजट (cache.*), क्वेरी गार्ड (query.*), कनेक्शन कैप (server.*), स्टोरेज बैकएंड (dataBackend.*), और लिखने योग्य परत (delta.*) हैं।
रेजिडेंट मेमोरी ट्रैक करती है
blockCacheBytes + vectorCacheBytes + resultCacheBytes बाउंडेड प्रति-प्रविष्टि और
आवंटक ओवरहेड के भीतर — प्रत्येक पूल अपनी सामग्री का वजन करता है (स्ट्रिंग्स और
कंटेनर आवंटित क्षमता द्वारा) और बजट के भीतर रहने के लिए निष्कासित करता है, लेकिन
प्रति-प्रविष्टि बहीखाता और आवंटक का आकार-वर्ग राउंडिंग आपके द्वारा सेट किए गए नंबर के
ऊपर बैठता है — साथ ही एक छोटा निश्चित ओवरहेड (और lazy डिग्री कॉलम के लिए
degreeColumnBytes तक, एक बार डिग्री-सम count(endpoint) फास्ट पथ
चलाया जाता है)। यह ग्राफ आकार से स्वतंत्र है — यह मुख्य गारंटी है,
जो rss_stays_bounded_under_sustained_knn_load एकीकरण परीक्षण द्वारा प्रयोग की जाती है,
जो पीक-बनाम-वार्म RSS वृद्धि को संक्षेपित बजट के भीतर अच्छी तरह रखता है। प्रति-कनेक्शन
बफ़र कैश बजट के बाहर रहते हैं, इसलिए गारंटी प्रतिकूल लोड के तहत केवल इसलिए रहती है
क्योंकि server.maxConnections सीमित करता है कि एक बार में कितने मौजूद हो सकते हैं।
Slater एक रीड रेप्लिका हैंडल है; प्राथमिक कनेक्शन-सुरक्षा नियंत्रण नेटवर्क है,
बाइनरी नहीं। इसे एक निजी इंटरफ़ेस से बांधें, नेटवर्क परत पर स्रोत रेंज प्रतिबंधित करें
(सुरक्षा समूह / NetworkPolicy), और — यदि यह विश्वसनीय क्लाइंट के अलावा कुछ भी सामना करता है —
इसे कनेक्शन-सीमित L4 प्रॉक्सी (HAProxy maxconn +
प्रति-स्रोत stick-table, या nftables connlimit + hashlimit) के साथ सामने रखें। यह फ़ाइल
डिस्क्रिप्टर को प्रक्रिया को सौंपे जाने से पहले बैठता है, इसलिए यह सबसे मजबूत सीमा है।
उपरोक्त इन-बाइनरी सीमाएँ (maxConnections, maxPreAuthConnections,
maxConnectionsPerIp, डिफरेंशियल बाइट कैप, और loginTimeoutMs) गहराई में रक्षा हैं:
वे डिफ़ॉल्ट रूप से चालू और उदार हैं ताकि वे एक वैध क्लाइंट आबादी के लिए अदृश्य हों,
लेकिन वे बाउंडेड-RSS गारंटी को तब भी रखते हैं जब प्रॉक्सी भूल जाता है। पूर्ण
रक्षात्मक स्थिति के लिए docs/HARDENING.md देखें, और विहित
विवरण के लिए THREAT_MODEL.md / SECURITY_WORKLIST.md देखें।
Slater प्रत्येक ग्राफ के current पॉइंटर को हर generationPollMs पर पोल करता है
(पोल, inotify नहीं — डेटा निर्देशिका रिमोट/नेटवर्क स्टोरेज जैसे NFS हो सकती है,
जहां फाइलसिस्टम परिवर्तन ईवेंट अविश्वसनीय हैं)। जब यह बदलता है:
reloadStrategy=exit (डिफ़ॉल्ट): सर्वर घातक लॉग करता है और गैर-शून्य के साथ बाहर निकलता है ताकि
ऑर्केस्ट्रेटर इसे नए जनरेशन के खिलाफ साफ-सुथरा पुनः आरंभ करे।reloadStrategy=swap: सर्वर नए जनरेशन को खोलता है और सत्यापित करता है
(बूट के समान सामग्री-हैश गार्ड), इसे परमाणु रूप से स्वैप करता है, और चल रही
क्वेरी को पुराने पर समाप्त करने देता है। एक दूषित/अपूर्ण नई छवि अस्वीकार कर दी जाती है और
पुराना जनरेशन सेवा देता रहता है।acl.json उपयोगकर्ताओं को argon2id पासवर्ड हैश और प्रति-ग्राफ read / write
अनुदान मैप करता है। एक हैश बनाएं (कभी भी स्पष्ट पाठ संग्रहीत न करें) इसके साथ:```sh
slater hash-password 's3cret' # prints a $argon2id$… string for acl.json
एक स्टार्टर `acl.json` रिपॉजिटरी रूट पर शामिल है; इसका आकार इस प्रकार है:```json
{
"users": {
"reporting": {
"passwordArgon2id": "$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>",
"grants": {
"people": ["read"],
"products": ["read", "write"]
}
}
}
}
users — प्रत्येक लॉगिन के लिए एक प्रविष्टि, उपयोगकर्ता नाम से कुंजीबद्ध।
passwordArgon2id — slater hash-password से प्राप्त $argon2id$… स्ट्रिंग
(कभी भी स्पष्ट पाठ में नहीं; फ़ाइल स्वयं सादा JSON है और साझा स्टोरेज पर रहती है)।
grants — प्रति-ग्राफ क्षमता सूचियाँ। दो अनुमतियाँ सार्थक हैं:
read — ग्राफ़ को क्वेरी करें। किसी उपयोगकर्ता के grants में अनुपस्थित ग्राफ़ उनके लिए अदृश्य होता है।write — राइटेबल लेयर (delta.enabled) के माध्यम से ग्राफ़ को बदलें:
MERGE / SET / DELETE स्टेटमेंट और CALL slater.consolidate()।इसे aclPath (डिफ़ॉल्ट /config/acl.json) द्वारा नामित पथ पर केवल-पठनीय माउंट करें।
सर्वर इसे प्रत्येक जनरेशन हॉट-स्वैप पर पुनः लोड करता है, और स्थिर ACL स्टैम्प की
हर पुनः लोड पर पुनः जाँच की जाती है (देखें requireAclStamp)।
slater बाइनरी अपनी स्वयं की लाइवनेस प्रोब के रूप में भी कार्य करती है: slater healthcheck [host] [port] सर्वर के विरुद्ध एक Bolt हैंडशेक (HTTP अनुरोध नहीं) करता है और
यदि यह एक प्रोटोकॉल संस्करण पर बातचीत करता है तो 0 से बाहर निकलता है, अन्यथा 1 — डिफ़ॉल्ट रूप से
localhost और कॉन्फ़िगर किया गया Bolt पोर्ट। यही कंटेनर
HEALTHCHECK चलाता है, इसलिए ऑर्केस्ट्रेटर एक वास्तविक Bolt-तैयार सर्वर देखते हैं, न कि केवल एक खुला सॉकेट:```sh
slater healthcheck localhost 7687 # exit 0 = healthy
docker exec slater /app/slater healthcheck # inside the container
## One-shot क्वेरी
स्क्रिप्टिंग, CI जाँच और त्वरित लुकअप के लिए, `slater query` ग्राफ़ की
वर्तमान पीढ़ी को माउंट करता है, प्रोसेस में एक एकल केवल-पढ़ने वाली Cypher क्वेरी चलाता है, परिणाम को
JSON ऑब्जेक्ट के रूप में प्रिंट करता है, और बाहर निकल जाता है — कोई सर्वर नहीं, कोई Bolt कनेक्शन नहीं। यह
सर्वर के समान कॉन्फ़िगरेशन का सम्मान करता है (स्टोरेज बैकएंड, एन्क्रिप्शन कुंजी, क्वेरी बजट):```sh
# GRAPH defaults to `defaultGraph`. Without -q, normal datestamped logging
# (config, "opened generation", …) is written to stdout alongside the result.
slater query mygraph 'MATCH (n) RETURN count(n) AS c'
# -q/--quiet ⇒ logging suppressed, so stdout is *only* the compact result JSON
slater query mygraph -q 'MATCH (c:Company) RETURN c.ticker AS t LIMIT 3' | jq
# {"columns":["t"],"rows":[["AUPH"],["KYMR"],["MREO"]]}
नोड्स और संबंध अपने लेबल/प्रकार और गुणों तक विस्तारित होते हैं। मशीन-पार्स करने योग्य आउटपुट चाहिए तो -q का उपयोग करें (परिणाम JSON ही stdout पर एकमात्र चीज़ होता है); ऑपरेटर-सामना वाले रन के लिए लॉग के साथ इसे छोड़ दें। -q के बिना प्रत्येक रन के बाद केवल मेट्रिक्स-आधारित सारांश लॉग किया जाता है — जैसे।```text
INFO query executed cost=2389 resultCount=10 execMs=441 limitRowCount=10
`cost` (लगाए गए तत्व), `resultCount`, `execMs`, और
`limitRowCount` (केवल तब जब क्वेरी `LIMIT` निर्दिष्ट करती है) — कभी भी क्वेरी टेक्स्ट
या कोई परिणाम मान नहीं। सफलता पर निकास स्थिति `0` है, पार्स/ओपन/एक्ज़ीक्यूट
त्रुटि पर `1` (संदेश stderr पर)।
## एक ग्राफ़ निर्यात करें (`slater dump`)
`slater dump` एक **चालू** सर्वर से ग्राफ़ को बिज़नेस-की `MERGE`
Cypher के रूप में निर्यात करता है — वही डायलेक्ट जो `slater-build` ग्रहण करता है — ताकि एक ग्राफ़ राउंड-ट्रिप
(dump → `slater-build` → नई पीढ़ी) माइग्रेशन या टेक्स्ट बैकअप के लिए हो सके। `slater query` के विपरीत,
यह **Bolt** पर कनेक्ट होता है, प्रमाणित करता है, और प्रति-ग्राफ़
ACL का सम्मान करता है, इसलिए इसे सर्वर तक डिस्क एक्सेस की आवश्यकता नहीं होती। पासवर्ड
`SLATER_DUMP_PASSWORD` या stdin से पढ़ा जाता है (कभी भी फ़्लैग से नहीं, इसे `ps`/हिस्ट्री से बाहर रखते हुए)।```sh
# List the graphs the authenticated user may read.
SLATER_DUMP_PASSWORD=pw slater dump --list -u reporting
# Dump a graph to a file (identity keys inferred from range indexes).
SLATER_DUMP_PASSWORD=pw slater dump people -u reporting -o people.cypher
# Rebuild it into a fresh generation.
slater-build --input people.cypher --graph people --data-dir ./data
प्रत्येक लेबल की पहचान कुंजी उसकी रेंज इंडेक्स द्वारा वहन की गई संपत्ति है; --key Label=prop (दोहराने योग्य) या वैश्विक --pk <field> के साथ ओवरराइड करें। CREATE INDEX DDL पहले उत्सर्जित होता है ताकि रीबिल्ड इंडेक्स को फिर से बना सके। एक मल्टी-लेबल नोड हर लेबल रखता है — इसे MERGE (n:Ident:Other {key: v}) के रूप में उत्सर्जित किया जाता है, जिसमें पहचान लेबल (वह जो बिजनेस कुंजी प्रदान करता है) पहले और बाकी क्रमबद्ध होते हैं; मर्ज केवल पहचान लेबल पर कुंजीबद्ध होता है, इसलिए अनुगामी लेबल नोड पर लिखे जाते हैं बिना कोई और नोड बनाए। विशेष वर्णों वाले लेबल, संबंध प्रकार और संपत्ति कुंजियाँ उत्सर्जन पर बैकटिक-कोटेड होती हैं, इसलिए असामान्य नाम विश्वसनीय रूप से राउंड-ट्रिप होते हैं और रीबिल्ड में Cypher इंजेक्ट नहीं कर सकते। वेक्टर (और अन्य मान जिनमें Cypher-लिटरल वर्तनी नहीं है) MERGE डंप पर सवार नहीं हो सकते और stderr पर चेतावनी के साथ हटा दिए जाते हैं। सफलता पर निकास स्थिति 0 है, त्रुटि पर 1।
एक पूर्ण, चलाने योग्य वॉकथ्रू — एक ग्राफ बनाएं, उसे सर्व करें, neo4j JavaScript और Python ड्राइवरों से कनेक्ट करें, और उसमें लिखें — मैनुअल के Quickstart और Writing data पृष्ठों में है, जिसमें docs/manual/examples/ में बंडल किया गया नमूना ग्राफ उपयोग किया गया है।
export PATH="$HOME/.cargo/bin:$PATH" cargo build cargo test # unit + the bounded-RSS headline integration test cargo clippy --all-targets -- -D warnings cargo fmt --all -- --check
### ऑब्जेक्ट-स्टोर बैकएंड वैकल्पिक कार्गो फीचर्स हैं
एक सादा `cargo build` एक **केवल-फाइलसिस्टम** बाइनरी बनाता है — `s3` और `gcs`
बैकएंड कार्गो फीचर्स के पीछे गेटेड हैं ताकि डिफ़ॉल्ट बिल्ड छोटा रहे (कोई AWS
या Google SDK नहीं, कोई async रनटाइम नहीं)। जिसकी भी आपको आवश्यकता हो, उसे **दोनों** `slater`
(सर्व) और `slater-build` (पब्लिश) पर सक्षम करें:```sh
# S3 only / GCS only / both
cargo build -p slater -p slater-build --features s3
cargo build -p slater -p slater-build --features gcs
cargo build -p slater -p slater-build --features s3,gcs
प्रत्येक क्रेट समान s3 / gcs फीचर्स उजागर करता है जो graph-format/{s3,gcs} पर फॉरवर्ड होते हैं। रनटाइम पर बैकएंड का अनुरोध करना (dataBackend.kind=s3|gcs, या slater-build --publish-{s3,gcs}-*) बिना उसके फीचर कंपाइल किए हुए, स्पष्ट "built without the … feature" त्रुटि के साथ तुरंत विफल हो जाता है। प्रकाशित Docker इमेज दोनों को सक्षम करती है (Dockerfile CARGO_FEATURES), इसलिए प्रीबिल्ट इमेज को अतिरिक्त फ्लैग की आवश्यकता नहीं होती — यह केवल स्रोत से बिल्ड करते समय मायने रखता है। एकीकरण परीक्षण भी इसी तरह गेटेड हैं: --features s3 --test s3_minio, --features gcs --test gcs_emulator (एक fake-gcs-server), और --features gcs --test gcs_real (ADC के माध्यम से वास्तविक GCS); प्रत्येक तब तक स्किप होता है जब तक उसके SLATER_* env वेरिएबल सेट न हों।
डिज़ाइन, माइलस्टोन लेजर और निर्णय लॉग के लिए docs/PLAN.md, docs/PROGRESS.md और docs/DECISIONS.md देखें।
छह इंजन तक, एक सिंगल-क्लाइंट सूट, 62k-नोड टॉय से लेकर Wikidata 91.6M नोड्स / 1.5B एज तक के ग्राफ़। प्रत्येक इंजन को अलगाव में मापा जाता है (हर दूसरा कंटेनर रोका जाता है — RSS और लेटेंसी उसका अपना फुटप्रिंट है)। नीचे दी गई लेटेंसी टेबल Slater 0.21.0 पर फिर से मापी गईं (राइटेबल बिल्ड): छोटे/मध्यम ग्राफ़ (MeSH, EU-AI-Act) ताज़ा, और 91.6M ग्राफ़ एक ताज़ा same-box, shared-anchor slater-vs-Neo4j पास के रूप में (उस टेबल देखें)। रेजिडेंट-मेमोरी आंकड़े पिछले पास से आगे बढ़ते हैं (कंटेनर cgroup के माध्यम से मापा गया; रीड पाथ राइटेबल लेयर के निष्क्रिय होने पर बाइट-समान है)। अन्य इंजनों के नंबर स्थापित क्रॉस-इंजन रन हैं (उनके संस्करण/प्रदर्शन अपरिवर्तित हैं)। सभी आंकड़े मेडियन (ms) या पीक रेजिडेंट मेमोरी (MiB) हैं। हर जगह कम बेहतर है; बोल्ड = पंक्ति में सर्वश्रेष्ठ। slater को उसके लोकल-फाइलसिस्टम (fs) बैकएंड पर चलाया गया था; S3 और GCS बैकएंड लोकल-रीड लेटेंसी को ऑब्जेक्ट-स्टोर राउंड-ट्रिप के लिए बदलते हैं (इन-मेमोरी कैश और वैकल्पिक लोकल-डिस्क कैश टियर द्वारा कम किया गया), इसलिए ये आंकड़े इंजन की विशेषता बताते हैं, नेटवर्क-स्टोरेज डिप्लॉयमेंट की नहीं।
तीन इंजन जो डिस्क से पेज करते हैं — slater, Neo4j 5, और LadybugDB — सभी पाँच ग्राफ़ लोड करते हैं। इन-मेमोरी तिकड़ी (Memgraph · FalkorDB · ArcadeDB) 1.5B एज ग्राफ़ को बिल्कुल नहीं रख सकती (इसे ~64–128 GiB रेजिडेंट चाहिए), और ArcadeDB का इम्पोर्टर भी इसे पूरा नहीं कर सकता।
प्रत्येक आंकड़ा प्रतिबद्ध वर्किंग मेमोरी है — जिसे OS पुनः प्राप्त नहीं कर सकता। slater को छोड़कर हर इंजन अपने ग्राफ़ को प्रतिबद्ध अनाम मेमोरी में रखता है (अपना हीप, Neo4j का ऑफ-हीप पेज कैश, या एक बफर पूल), इसलिए उसका पीक RSS उसका प्रतिबद्ध फुटप्रिंट है। केवल slater अपने ऑन-डिस्क स्टोर के रीक्लेमेबल OS पेज कैश से सेवा करता है, इसलिए उसका आंकड़ा अनाम वर्किंग सेट है; स्टोर का पेज कैश (दबाव में निकालने योग्य — slater सेवा जारी रखता है) बाहर रखा गया है, और 91.6M ग्राफ़ के लिए कोष्ठक में कुल के रूप में दिखाया गया है। बोल्ड = सबसे कम।
slater हर पैमाने पर सबसे कम है और ग्राफ़ के ~1,500× बढ़ने पर ~50× बढ़ता है — इसका फुटप्रिंट क्वेरी वर्किंग सेट को ट्रैक करता है, ग्राफ़ को नहीं (निष्क्रिय ~16–71 MiB पूरे समय)। इन-मेमोरी तिकड़ी ~रैखिक रूप से बढ़ती है और 1.5B ग्राफ़ लोड नहीं कर सकती; Neo4j क्वेरी की परवाह किए बिना ~2 GiB हीप प्रतिबद्ध करता है। († LadybugDB केवल बाउंडेड शेप पर — 1.5B एज पर इसके हब / var-length / shortestPath ट्रैवर्सल को अपने रीड पूल को ≥2 GiB तक बढ़ाने की आवश्यकता होती है, जबकि slater का स्वचालित maxIntermediate कैप होता है।) बिल्ड-टाइम value→count हिस्टोग्राम नगण्य रेजिडेंट मेमोरी जोड़ते हैं — कम-कार्डिनैलिटी इंडेक्स्ड कॉलम के लिए कुछ KB, और Wikidata जैसे यूनिक-की ग्राफ़ के लिए शून्य (wikidata_id हिस्टोग्राम कार्डिनैलिटी कैप से अधिक है, इसलिए कोई संग्रहीत नहीं होता) — इसलिए ये आंकड़े उस फीचर से अपरिवर्तित हैं।
slater मेटाडेटा / इंडेक्स / स्कैन शेप (count, लेबल, idx-eq, स्कैन — ~0.4 ms, सर्विस इंजन से 10–200×), इंडेक्स्ड पॉइंट लुकअप (0.43 ms, अब इन-मेमोरी जोड़ी के 0.48 ms को पीछे छोड़ते हुए), अनएंकर्ड मल्टी-हॉप (2-हॉप 1.40 ms रिलेशनशिप-टाइप स्कैन के माध्यम से, क्षेत्र में सबसे तेज़), और — इंडेक्स्ड ग्रुपिंग की पर बिल्ड-टाइम value→count हिस्टोग्राम के माध्यम से — पूरे-लेबल group-by / count(DISTINCT) (0.45 ms, LadybugDB के कॉलमनार 5.3 ms से आगे) का मालिक है। इन-मेमोरी सर्वर केवल रॉ 1-हॉप रखते हैं (Memgraph 1.21 ms बनाम slater का 1.28 ms)। (pole 62k/106k समान दिखता है: slater count/स्कैन ~0.4 ms पर अकेला सबसे तेज़, हॉप्स पर ~1.3–2.6 ms।)
slater kNN को सटीक ब्रूट-फोर्स स्कैन के साथ उत्तर देता है (ये सेट इसकी 50k-वेक्टर ANN थ्रेशोल्ड से नीचे हैं) जहाँ अन्य अनुमानित रेजिडेंट HNSW का उपयोग करते हैं — इसलिए slater के परिणाम सटीक हैं (रिकॉल 1.0)। एक SIMD दूरी कर्नेल + एक रेजिडेंट, प्री-नॉर्मलाइज़्ड वेक्टर मैट्रिक्स ने Concept को ~23 → ~2.9 ms और Chunk को ~10 → ~2.4 ms पर ला दिया, इसलिए slater अब Neo4j और LadybugDB को हराता है और Memgraph के ~1.4× के भीतर है, केवल FalkorDB से पीछे — जबकि सटीक है।
ऊपर की टेबल क्रॉस-इंजन रीड तुलनाएँ हैं। वेक्टर राइट पाथ (स्टैटिक Vamana बेस पर FreshDiskANN-शैली राइट लैडर) का कोई क्रॉस-इंजन समकक्ष नहीं है — यहाँ कोई अन्य इंजन डिस्क-नेटिव, राइटेबल ANN नहीं करता — इसलिए नीचे के नंबर एक सिंथेटिक, एम्बेडिंग-जैसे फिक्स्चर (एक लो-रैंक मैनिफोल्ड, dim 768, असमान नॉर्म्स) पर सिंगल-इंजन कंपोनेंट बेंचमार्क हैं, जो crates/slater/benches/ के अंतर्गत प्रतिबद्ध हैं और पूरी तरह से — कार्यप्रणाली और हर चेतावनी के साथ — docs/PERF-REPORT.md में लिखे गए हैं। रिकॉल हमेशा लाइव सेट पर सटीक ब्रूट फोर्स के विरुद्ध मापा जाता है, कभी एक इंडेक्स दूसरे के विरुद्ध नहीं। यहाँ का पैमाना प्रतिनिधि है और केवल वहीं एक्सट्रपोलेट किया गया है जहाँ मीट्रिक आकार-रैखिक है।
एक आंकड़ा जो समर्पित परफ़ बॉक्स चाहता है वह स्लो-पाथ कंसोलिडेशन रीराइट थ्रूपुट है — जब एक कंसोलिडेशन शुद्ध परम्यूटेशन के बजाय डिलीट या नए वेक्टर ले जाता है, यह एक अनुक्रमिक रीकंप्रेस है जो सिंगल-थ्रेड zstd और लोकल डिस्क से बंधा होता है, इसलिए पूर्ण MiB/s पर्यावरण-विशिष्ट है (रिपोर्ट आकार दिखाती है और पर्यावरणीय सीमा की व्याख्या करती है)।
इन-मेमोरी इंजन (Memgraph / FalkorDB / ArcadeDB) इस ग्राफ़ को बिल्कुल लोड नहीं कर सकते (~64–128 GiB रेजिडेंट)। केवल slater और Neo4j 5 करते हैं। यह एक ताज़ा same-box, same-day पास है जो एक साझा, फिक्स्ड एंकर सेट के विरुद्ध है — हर क्वेरी दोनों इंजनों पर समान नोड्स को हिट करती है, इसलिए हेड-टू-हेड सेब-से-सेब है (मध्यम-डिग्री एंकरों का एक सामान्य wikidata_id पूल; यह क्यों मायने रखता है इस पर नीचे नोट देखें)। slater दोनों फैनआउट पर दिखाया गया है (query.maxFanout 1 = थ्रूपुट डिफ़ॉल्ट, 8 = लेटेंसी डायल जो कोल्ड ब्लॉक रीड्स को ओवरलैप करता है)। बोल्ड = पंक्ति में सर्वश्रेष्ठ।
ईमानदार तस्वीर: slater मेटाडेटा / इंडेक्स शेप पर हावी है — count(*) मेटाडेटा-सर्व्ड है (0.41 ms बनाम Neo4j का 3.6 s डिस्क स्कैन, ~8800×), और पॉइंट-लुकअप / डिग्री / 3-हॉप ~2–10× तेज़ चलते हैं — 1–2-हॉप पर Neo4j के बराबर है (फैनआउट 8 कोल्ड रीड्स पर आगे निकल जाता है), लेकिन var-length *1..2 distinct निर्णायक रूप से हारता है (≈1 s बनाम Neo4j का 47 ms): slater का वेरिएबल-लेंथ distinct विस्तार यहाँ काफी धीमा है, एक वास्तविक कमजोरी जो अपनी स्वयं की जाँच के योग्य है। यह सब कुछ सौ MB RSS पर बनाम Neo4j के प्रतिबद्ध ~2 GiB हीप के साथ।
एंकरों पर। ये ट्रैवर्सल नंबर काफी हद तक इस बात पर निर्भर करते हैं कि आप किन नोड्स से शुरू करते हैं — एक Wikidata मेगा-हब ("human", "country") से एक लिंक दूर एक नोड का लाखों-मजबूत 2-हॉप पड़ोस होता है, इसलिए var-length/हॉप लागत एंकर चयन के साथ परिमाण के क्रमों से बदलती है। इस टेबल का पहले का संस्करण प्रत्येक इंजन के अपने "स्कैन द्वारा पहले N" का नमूना लेता था, जो न तो स्थिर है और न ही तुलनीय; यह पास दोनों इंजनों के लिए एक एकल साझा, डिग्री-बाउंडेड एंकर सेट तय करता है। (shortestPath इस पास से हटा दिया गया है — दो मनमाने एंकरों के बीच यह पाथ-अस्तित्व-निर्भर है और मेडियन को सार्थक रूप से देने के लिए बहुत उच्च-वेरिएंस है।)
count(*) — मेमोरी परिणाम आकार से अलगअनकैप्ड मल्टी-हॉप RETURN count(*) मैच की गई पंक्तियों को मटेरियलाइज़ करने के बजाय विस्तार के दौरान गिनता है। 91.6M ग्राफ़ पर समान हब एंकर, maxIntermediate=20M:
| 3-हॉप count(*) @ 91.6M | फैनआउट=1 | फैनआउट=8 |
|---|---|---|
| लेटेंसी / पीक वर्किंग सेट | 554 ms / 0.66 GiB | 298 ms / 1.9 GiB |
काउंट O(1) पंक्तियाँ रखता है। चार्जिंग अपरिवर्तित है, इसलिए एक मेगा-हब काउंट अभी भी कंप्यूट (एडजेसेंसी रीड्स) पर maxIntermediate को ट्रिप करता है, पहले की तरह बाउंडेड।
maxFanout)query.maxFanout बढ़ाना एक क्वेरी के कोल्ड, I/O-बाउंड ब्लॉक रीड्स को कोर में ओवरलैप करता है — यह बड़े-कोल्ड-वर्किंग-सेट डिस्क-बाउंड शेप में मदद करता है और वार्म शेप पर फ्लैट है। 1.5B ग्राफ़ पर: shortestPath ≤6 918 → 608 ms (1.5×, सबसे बड़ी खोज 6,269 → 2,350 ms, 2.7×); 3-हॉप काउंट 547 → 298 ms। maxFanout=1 डिफ़ॉल्ट है (थ्रूपुट-उन्मुख); 8 लेटेंसी डायल है, अधिक क्षणिक वर्कर मेमोरी पर।
पूर्ण प्रति-इंजन टेबल (pole, MeSH, EU-AI-Act + blockCacheBytes RAM↔लेटेंसी डायल, Wikidata 1M & 91.6M) perf/cross-engine-hs/README.md में हैं; ताज़ा slater-केवल पास (दोनों फैनआउट, हर डेटासेट) perf/PERF_CURRENT_STATUS.md में है।
ऊपर के बेंचमार्क सिंगल-क्लाइंट हैं। पूरक अक्ष — कई समवर्ती क्लाइंट्स के तहत व्यवहार — का अपना हार्नेस है, perf/loadtest/: Bolt पर एक Locust ड्राइवर प्लस एक कोऑर्डिनेटर जो लोड को रैंप करता है, CALL slater.diagnostics() पढ़ता है, क्षमता घुटना ढूंढता है, और लिमिटर का नाम देता है (पूरी विधि docs/LOAD-TESTING.md में)। Wikidata-1M ग्राफ़ पर 256 MiB-कैश रन से हेडलाइन्स (एक 16-कोर बॉक्स):
| परिणाम | माप |
|---|---|
| 1000 समवर्ती क्लाइंट्स, शून्य विफलताओं तक धारण करता है | थ्रूपुट ~2.5k rps पर चरम; लेटेंसी घुटना लगभग 750 क्लाइंट्स पर शुरू होता है (p99 51 → 750 ms) — कोर प्रतिस्पर्धा के तहत कतारबद्ध, हार्ड कैप नहीं (सिंगल-रन, WSL2) |
| ब्लॉक कैश बाउंडेड और प्रभावी | 100% हिट रेट, 0 इविक्शन, कैश-फिटिंग वर्किंग सेट के लिए 50 MB रेजिडेंट |
INSERTSETREMOVEDELETE| फ़ीचर | आपके लिए इसका क्या मतलब है |
|---|
| बाउंडेड, पूर्वानुमानित मेमोरी | रेज़िडेंट मेमोरी तीन कैश बजटों को ट्रैक करती है जो आप सेट करते हैं, बाउंडेड प्रति-एंट्री और एलोकेटर ओवरहेड के भीतर — यह ग्राफ़ के आकार के साथ नहीं बढ़ती; आप पूरे ग्राफ़ के लिए प्रोविज़न करने के बजाय परफ़ॉर्मेंस/RAM ट्रेड-ऑफ़ ट्यून करते हैं। बैकग्राउंड पर्ज के साथ एक jemalloc एलोकेटर भारी क्वेरी बर्स्ट के बाद फ्री की गई मेमोरी को OS को लौटा देता है, इसलिए रेज़िडेंट आकार अपने आइडल फ्लोर की ओर वापस गिरता है न कि बर्स्ट-बाद के हाई-वॉटर मार्क पर पिन रहता है। |
| आउट-ऑफ-द-बॉक्स मल्टी-टेनेंट | एक सर्वर कई ग्राफ़ होस्ट करता है जिसमें प्रति-उपयोगकर्ता रीड अनुदान होते हैं — मल्टी-डेटाबेस आइसोलेशन जो अधिकांश ग्राफ़ DB पेड/एंटरप्राइज़ टियर के लिए आरक्षित रखते हैं। |
| At-rest और in-transit एन्क्रिप्शन | प्रति-ब्लॉक XChaCha20-Poly1305 सीलिंग (की कभी डिस्क पर नहीं लिखी जाती) साथ ही वैकल्पिक TLS (bolt+s://)। निर्माण से GDPR-अनुकूल। एन्क्रिप्शन ही प्रमाणित इंटीग्रिटी भी खरीदता है: बिल्डर मैनिफेस्ट को keyed MAC से सील करता है, और की रखने वाला सर्वर इसे सत्यापित करता है और ऐसी जनरेशन को सेव करने से इनकार करता है जिसका मैनिफेस्ट जाली, बदला हुआ, या जिसका MAC हटा दिया गया हो। एक बिना-की (प्लेनटेक्स्ट) इमेज केवल बिना-की content hash द्वारा सुरक्षित होती है — पूर्णता और भ्रष्टाचार, छेड़छाड़ नहीं। देखें प्रत्येक कॉन्फ़िगरेशन में इंटीग्रिटी का क्या मतलब है। |
| छोटा इंस्टॉल | एक छोटा stripped बाइनरी distroless glibc बेस पर (कोई shell/apt नहीं) — मल्टी-आर्क (amd64/arm64) इमेज ~22 MB खींचती है, या सर्वर-ओनली slater:latest-lite टैग के लिए ~12 MB; शुद्ध-Rust TLS, कोई OpenSSL नहीं। खींचें और चलाएँ। |
| आवधिक प्रकाशन के लिए बनाया गया | एक ग्राफ़ ऑफ़लाइन बनाएँ, इसे अपरिवर्तनीय रूप से सेव करें, फिर शून्य डाउनटाइम के साथ एक नया संस्करण परमाणु रूप से स्वैप करें — डेटा-वेयरहाउस / शेड्यूल्ड-रिफ्रेश वर्कलोड के लिए आदर्श। |
| लोड के तहत मज़बूत | सर्वर और ऑफ़लाइन बिल्डर दोनों #![forbid(unsafe_code)] के साथ कंपाइल होते हैं — इंजन का एकमात्र unsafe ऑडिटेड jemalloc एलोकेटर क्रेट में रहता है। कोर अपरिवर्तनीय है, इसलिए रीड्स कोई लॉक नहीं लेते और कभी राइटर का इंतज़ार नहीं करते; एक एकल राइटर केवल राइट पाथ के पीछे म्यूटेशन को सीरियलाइज़ करता है। कोई GC पॉज़ नहीं, कोई डेटा रेस नहीं। एक खराब क्वेरी सर्वर को नीचे नहीं ला सकती। |
| आपके neo4j टूल्स के साथ काम करता है | Bolt 5.4 / 4.4 / 4.1 बोलता है — मानक neo4j ड्राइवर (JS, Python, Go, Java…), cypher-shell, या ग्राफ़ ब्राउज़र बिना बदलाव के उपयोग करें। |
| समृद्ध Cypher क्वेरी सतह | एक व्यापक रीड सतह: MATCH/WHERE/WITH/UNION, CALL {…} सबक्वेरी, 70+ फ़ंक्शन और एग्रीगेशन, टेम्पोरल और जियोस्पेशियल मान, और regex। |
| लाइव, स्थायी राइट्स | अपरिवर्तनीय कोर के ऊपर एक ऑप्ट-इन सिंगल-राइटर LSM लेयर (delta.enabled): नोड्स और रिलेशनशिप पर बिज़नेस-की MERGE / SET / DELETE / CREATE / REMOVE, बैच्ड write-UNWIND (प्रति बैच एक fsync), और CALL slater.consolidate() — ग्रुप-कमिटेड, fsync-स्थायी, और कंसोलिडेशन द्वारा एक नए कोर में वापस मोड़ा गया। डेल्टा खाली होने पर रीड पाथ बाइट-समान है। |
| ISO GQL, रीड और राइट | उसी Bolt कनेक्शन पर ISO GQL (ISO/IEC 39075) का एक सबसेट बोलता है — quantified paths, path restrictors, shortest-path selectors, label/type boolean expressions, FOR, CAST, एक वैकल्पिक GQL/CYPHER डायलेक्ट प्रीफ़िक्स — और, राइटेबल लेयर चालू होने पर, GQL के डेटा-संशोधित स्टेटमेंट (INSERT / SET / REMOVE / [DETACH] DELETE) उसी स्थायी राइट पाथ पर उतरते हैं। Cypher और GQL, रीड्स और राइट्स, एक इंजन में। |
| वेक्टर + ग्राफ़ एक इंजन में | एम्बेडिंग/RAG के लिए डिस्क-नेटिव ANN वेक्टर सर्च (Vamana + PQ; cosine / L2 / dot), साथ ही ग्राफ़ एल्गोरिदम (PageRank, BFS, betweenness, WCC…) — लाखों वेक्टर के साथ भी बाउंडेड मेमोरी। एम्बेडिंग लिखने योग्य हैं (FreshDiskANN-शैली राइट लैडर): एक वेक्टर इन्सर्ट / अपडेट / डिलीट करें, तुरंत KNN-दृश्यमान, बिना रीबिल्ड के बेस में मोड़ा गया। |
| नेटवर्क स्टोरेज पर सुरक्षित | हर फ़ाइल BLAKE3 content-hashed है और खोलने पर सत्यापित होती है; फटी या आधी-कॉपी इमेज को सेव करने के बजाय अस्वीकार किया जाता है। NFS/रिमोट वॉल्यूम के लिए डिज़ाइन किया गया (कोई mmap आश्चर्य नहीं)। |
| प्लगेबल स्टोरेज बैकएंड | उसी जनरेशन फ़ॉर्मेट को स्थानीय फ़ाइलसिस्टम, S3 (S3-संगत) बकेट, या Google Cloud Storage बकेट से सेव करें — एक बार प्रकाशित करें, स्टेटलेस रेप्लिका में फैलाएँ — ऑब्जेक्ट स्टोर के सामने एक वैकल्पिक स्थानीय-SSD कैश टियर के साथ। देखें स्टोरेज बैकएंड। |
| पथ | उद्देश्य | नोट्स |
|---|
/data | ग्राफ जनरेशन (<graph>/<uuid>/… + current)। | रेप्लिका के लिए रीड-ओनली; slater-build द्वारा निर्मित। रिमोट/नेटवर्क स्टोरेज (जैसे NFS) पर रह सकता है, इसलिए रीड को तेज़ स्थानीय-SSD विलंबता माना नहीं जाता। |
/sandbox | प्रति-पर्यावरण कॉन्फ़िग ओवरले + सीक्रेट्स। | /sandbox/config.json बेक-इन config.json पर डीप-मर्ज किया जाता है; इसमें acl.json, TLS PEM सामग्री, आराम-स्थिति कुंजी फ़ाइल भी होती है। |
/tmp, /run | स्क्रैच (tmpfs)। | एक रीड रेप्लिका डिफ़ॉल्ट रूप से कभी डिस्क पर नहीं लिखती। |
(राइटर) delta.walDir | राइट-अहेड लॉग + L0 डेल्टा सेगमेंट, जब delta.enabled। | लिखने योग्य, और एक टिकाऊ, वास्तविक वॉल्यूम — कभी tmpfs नहीं (यह स्थायित्व की निचली सीमा है)। एक सापेक्ष पथ डेटा निर्देशिका के अंतर्गत हल होता है; एक राइटर को यहां अपना स्वयं का स्थायी वॉल्यूम दें। |
| (वैकल्पिक) डिस्क कैश | स्थानीय-डिस्क ब्लॉक कैश, जब dataBackend.s3.diskCacheBytes / dataBackend.gcs.diskCacheBytes > 0। | लिखने योग्य, और एक वास्तविक वॉल्यूम — tmpfs नहीं। s3 और gcs बैकएंड द्वारा उपयोग किया जाता है; स्टोरेज बैकएंड देखें। |
ये स्वतंत्र हैं: read अनुदान कोई लेखन पहुँच प्रदान नहीं करता। इसलिए राइटेबल
लेयर चालू करने से आपके मौजूदा पाठक लेखक नहीं बन सकते। एक लेखक को दोनों की आवश्यकता होती है —
["read", "write"] — क्योंकि लिखने के लिए व्यावसायिक कुंजी को हल करना एक पठन है।
अपरिचित अनुमति स्ट्रिंग्स को अनदेखा किया जाता है (वे कुछ भी अनुदान नहीं देतीं)।
| इंजन | क्लास | मेमोरी बाउंड |
|---|
| slater | डिस्क-बैक्ड, पेज्ड | query.maxIntermediate वर्किंग सेट को स्वचालित रूप से सीमित करता है |
| Neo4j 5 | डिस्क-बैक्ड, JVM | ~2 GiB हीप + ऑफ-हीप, क्वेरी की परवाह किए बिना प्रतिबद्ध |
| Memgraph · FalkorDB | इन-मेमोरी | पूरा ग्राफ़ RAM में रेजिडेंट |
| ArcadeDB | इन-मेमोरी, JVM | पूरा ग्राफ़ रेजिडेंट; सबसे भारी |
| LadybugDB | एम्बेडेड, कॉलमनार | मैनुअल बफर पूल जिसे क्वेरी से अधिक होना चाहिए |
| ग्राफ़ (नोड्स / एज) | slater | Neo4j 5 | Memgraph | FalkorDB | ArcadeDB | LadybugDB |
|---|
| pole — 62k / 106k | 11 | 746 | 114 | 140 | 1,556 | 198 |
| MeSH — 341k / 469k | 63 | 1,083 | 358 | 455 | 1,631 | 121 |
| EU-AI-Act — 21k / 45k (+55 MiB vec) | 99 | 729 | 229 | 312 | 1,948 | 286 |
| Wikidata — 91.6M / 1.5B | 584 (4,595 कुल) | ~2,900 | लोड-नहीं-कर-सकता | लोड-नहीं-कर-सकता | लोड-नहीं-कर-सकता | ~652 † |
| शेप | slater | Neo4j 5 | Memgraph | FalkorDB | ArcadeDB | LadybugDB |
|---|
| count(*) सभी नोड्स | 0.41 | 15.0 | 23.8 | 16.4 | 82.0 | 2.2 |
| लेबल काउंट | 0.42 | 4.2 | 20.7 | 1.1 | 4.4 | 4.3 |
| इंडेक्स्ड पॉइंट लुकअप | 0.43 | 3.9 | 0.48 | 0.48 | 0.65 | 8.8 |
| idx-eq काउंट | 0.42 | 4.9 | 5.0 | 2.0 | 381 | 2.5 |
| 1-हॉप (इंडेक्स्ड एंकर) | 1.28 | 5.8 | 1.21 | 4.1 | 390 | 4.9 |
| 2-हॉप (अनएंकर्ड) | 1.40 | 5.6 | 8.5 | 16.7 | 444 | 6.4 |
| group-by / count(DISTINCT) | 0.45 | 47–51 | 63–64 | 31–39 | 411 | 5.3 |
फुल-स्कैन CONTAINS | 0.43 | 5.4 | 24.1 | 1.7 | 16.3 | 4.1 |
| शेप | slater | Neo4j 5 | Memgraph | FalkorDB | LadybugDB |
|---|
| kNN top-10 Concept | 2.9 | 8.6 | 1.9 | 1.2 | 2.8 |
| kNN top-10 Chunk | 2.4 | 5.7 | 1.9 | 1.5 | 3.2 |
| गुण | मापा गया | यह क्यों मायने रखता है |
|---|
| KNN लेटेंसी बनाम पेंडिंग राइट्स | RW-इंडेक्स ~1.5–2 ms, फ्लैट 50k पेंडिंग तक; प्री-इंडेक्स ब्रूट-फोर्स्ड ओवरले 1.9 → 115 ms (डेल्टा में रैखिक) — 50k पर 61× | क्वेरी लेटेंसी डिग्रेड नहीं होती जब राइट्स कंसोलिडेशन के बीच जमा होते हैं |
| एम्बेडिंग इंसर्ट | लाइव इंडेक्स में प्रति वेक्टर ~1.5–2 ms | एक राइट तुरंत KNN-दृश्यमान है; डेल्टा-रीबिल्ड बजट ≈ 2 ms × डेल्टा कैप है |
| आइसो-रिकॉल पर डिलीट IO | 67 % डिलीटेड पर प्रति क्वेरी 2.9× कम नोड-फ़ेच, 80 % पर 5.2× (रिकॉल ≥ 0.90) | एक कंसोलिडेटेड ग्राफ़ डिलीटेड वेक्टर के लिए कोई रीड टैक्स नहीं देता |
| कंसोलिडेशन, शुद्ध परम्यूटेशन | O(1) — .vamana हार्ड-लिंक्ड बाइट-समान है, केवल id कॉलम फिर से लिखा जाता है | वेक्टर राइट्स को बेस में फोल्ड करना O(N·R·L) रीबिल्ड को छोड़ देता है |
| लैडर में रिकॉल | cosine, L2 और dot के लिए कंसोलिडेटेड ≥ बेस | राइट लैडर हर रंग पर रिकॉल संरक्षित करता है |
| शेप | slater (फैन 1) | slater (फैन 8) | Neo4j 5 |
|---|
| count(*) सभी नोड्स | 0.41 | 0.41 | 3606 |
| पॉइंट लुकअप (इंडेक्स्ड) | 0.72 | 0.49 | 6.3 |
| डिग्री (1-हॉप काउंट) | 0.43 | 0.44 | 6.0 |
| 1-हॉप नेबर्स | 9.8 | 4.5 | 10.1 |
| 2-हॉप | 37 | 23 | 34.5 |
| 3-हॉप | 32 | 25 | 74 |
var-length *1..2 distinct | 985 | 1056 | 47 |
| आयाम | slater | क्षेत्र में सर्वश्रेष्ठ | फैसला |
|---|
| रेजिडेंट मेमोरी, किसी भी पैमाने पर | 11–584 MiB (62k → 91.6M) | इन-मेमोरी 1.5–2.7 GiB; 1.5B लोड नहीं कर सकता | slater |
| count / मेटाडेटा / स्कैन | ~0.4 ms | सर्विस इंजन 5–80 ms | slater (10–200×) |
| इंडेक्स्ड पॉइंट लुकअप | 0.43 ms (MeSH) | Memgraph · FalkorDB 0.48 ms | slater (इन-मेमोरी जोड़ी को पीछे छोड़ता है) |
| अनएंकर्ड मल्टी-हॉप (पंक्तियाँ) | 1.40 ms (MeSH 2-हॉप) | Neo4j 5.6 ms | slater (रिलेशनशिप-टाइप स्कैन) |
| एग्रीगेशन (group-by / DISTINCT) | 0.45 ms | LadybugDB 5 ms (कॉलमनार) | slater (बिल्ड-टाइम हिस्टोग्राम) |
| kNN | 2.4–2.9 ms (सटीक) | FalkorDB 1.2 ms (HNSW) | Neo4j/Ladybug को हराता है; Memgraph से ~1.4× दूर; सटीक |
| 91.6M मेटाडेटा / पॉइंट / डिग्री / 3-हॉप | 0.4–32 ms | Neo4j 6–3,600 ms | slater (2–8800×) |
| 91.6M 1–2-हॉप | 4.5–23 ms (फैन 8) | Neo4j 10–35 ms | ~बराबर |
91.6M var-length *1..2 distinct | ~1 s | Neo4j 47 ms | Neo4j (एक वास्तविक slater कमजोर स्थान) |
पैमाने पर मल्टी-हॉप count(*) | 0.3–0.6 GiB | इन-मेमोरी इंजन पंक्ति सेट को मटेरियलाइज़ करते हैं | slater, बाउंडेड |
| सतत लोड के तहत RSS धारण किया गया |
| jemalloc एलोकेटर RSS को 100→ |