अगर किसी कलेक्शन में ऐसे दस्तावेज़ हैं जिन्हें क्रम से इंडेक्स किया गया है, तो Cloud Firestore, ��िखने की दर को 500 राइट प्रति सेकंड तक सीमित करता है. यह पेज में बताया गया है कि इस सीमा को पार करने के लिए दस्तावेज़ ��़ी������ ��ो ������े शार्ड करें. सबसे पहले, "क्रम से लगाए गए इंडेक्स फ़ील्ड" से हमारा मतलब क्या है और साफ़ तौर पर बताएं कि यह सीमा कब लागू होगी लागू होती है.
क्रम में इंडेक्स किए गए फ़ील्ड
"क्रम से इंडेक्स किए गए फ़ील्ड" का मतलब ऐसे दस्तावेज़ों का कलेक्शन है जिसमें
इंडेक्स किए गए फ़ील्ड में एक ही तरह से बढ़ोतरी या कमी हो सकती है. ज़्यादातर मामलों में, इसका मतलब है कि
timestamp
फ़ील्ड, लेकिन एक समान रूप से बढ़ने या घटने वाला फ़ील्ड मान
500 राइट प्रति सेकंड की राइट सीमा ट्रिगर कर सकता है.
उदाहरण के लिए, यह सीमा सिर्फ़ ऐसे user
दस्तावेज़ों के कलेक्शन पर लागू होती है जिनमें
अगर ऐप्लिकेशन इस तरह की userid
वैल्यू असाइन करता है, तो इंडेक्स किए गए फ़ील्ड userid
को शामिल किया जाएगा:
1281, 1282, 1283, 1284, 1285, ...
दूसरी ओर, सभी timestamp
फ़ील्ड इस सीमा को ट्रिगर नहीं करते. अगर कोई
timestamp
फ़ील्ड, रैंडम तरीके से डिस्ट्रिब्यूट की गई वैल्यू ट्रैक करता है, लिखने की सीमा तय नहीं है
लागू करें. फ़ील्ड का वास्तविक मान भी कोई मायने नहीं रखता, बल्कि सिर्फ़ फ़ील्ड
यह लगातार बढ़ या घट रहा है. उदाहरण के लिए,
एक समान रूप से बढ़ने वाली फ़ील्ड वैल्यू के इन दोनों सेट ��ो ट्रिगर किया जाता है
लिखने की सीमा:
100000, 100001, 100002, 100003, ...
0, 1, 2, 3, ...
टाइमस्टैंप फ़ील्ड को शार्ड करना
मान लो कि आपका ऐप्लिकेशन एक ऐसे timestamp
फ़ील्ड का इस्तेमाल करता है जो एक समान रूप से बढ़ रहा है.
अगर आपका ऐप्लिकेशन किसी भी क्वेरी में timestamp
फ़ील्ड का इस्तेमाल नहीं करता है, तो
टाइमस्टैंप फ़ील्ड को इंडेक्स न करके, हर सेकंड में 500 लिखने की सीमा. अगर आपके पास
आपकी क्वेरी के लिए timestamp
फ़ील्ड होना ज़रूरी है, तो आप
शार्ड किए गए टाइमस्टैंप का इस्तेमाल करके:
timestamp
फ़ील्ड के साथshard
फ़ील्ड जोड़ें.1..n
अलग-अलग वैल्यू का इस्तेमाल करेंshard
फ़ील्ड के लिए मान. इससे राइटिंग बढ़ाने में मदद मिलती है सीमा500*n
तक ही इकट्ठा की जा सकती है, लेकिन आपकोn
क्वेरी इकट्ठा करनी होंगी.- अपने लिखने के लॉजिक को अपडेट करें, ताकि हर एक को रैंडम तरीके से
shard
वैल्यू असाइन की जा सके दस्तावेज़. - शार्ड किए गए नतीजों के सेट को एग्रीगेट करने के लिए अपनी क्वेरी अपडेट करें.
shard
फ़ील्ड औरtimestamp
, दोनों के लिए सिंगल-फ़ील्ड इंडेक्स बंद करें फ़ील्ड में डालें. उन मौजूदा कंपोज़िट इंडेक्स को मिटाएं जिनमेंtimestamp
शामिल है फ़ील्ड में डालें.- अपनी अपडेट की गई क्वेरी के हिसाब से नए कंपोज़िट इंडेक्स बनाएं. इसका क्रम
इंडेक्स में फ़ील्ड मायने रखते हैं और
shard
फ़ील्ड कोtimestamp
फ़ील्ड. ऐसा कोई भी इंडेक्स जिसमेंtimestamp
फ़ील्ड मेंshard
फ़ील्ड भी शामिल होना चाहिए.
आपको शार्ड टाइमस्टैंप को सिर्फ़ उन मामलों में लागू करना चाहिए जिनका इस्तेमाल लंबे समय तक किया गया हो
500 राइट प्रति सेकंड से ज़्यादा लिखने की दर. नहीं तो, यह
प्री-मैच्योर ऑप्टिमाइज़ेशन. timestamp
फ़ील्ड को शार्ड करने से 500 राइट हट जाते हैं
प्रति सेकंड वाली पाबंदी है, लेकिन इसके लिए क्लाइंट-साइड क्वेरी की ज़रूरत नहीं पड़ती
एग्रीगेशन.
इन उदाहरणों में, timestamp
फ़ील्ड को शार्ड करने और क्वेरी करने का तरीका बताया गया है
शार्ड किए गए परिणाम सेट किए गए.
डेटा मॉडल और क्वेरी के उदाहरण
उदाहरण के लिए, ऐसे ऐप्लिकेशन की कल्पना करें जो वित्तीय मामलों का रीयल-टाइम विश्लेषण करता है
इंस्ट्रुमेंट, जैसे कि करंसी, कॉमन स्टॉक, और ईटीएफ़. यह ऐप्लिकेशन लिखता है
दस्तावेज़ों को instruments
कलेक्शन में जोड़ना चाहता है, जैसे:
Node.js
async function insertData() { const instruments = [ { symbol: 'AAA', price: { currency: 'USD', micros: 34790000 }, exchange: 'EXCHG1', instrumentType: 'commonstock', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.010Z')) }, { symbol: 'BBB', price: { currency: 'JPY', micros: 64272000000 }, exchange: 'EXCHG2', instrumentType: 'commonstock', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.101Z')) }, { symbol: 'Index1 ETF', price: { currency: 'USD', micros: 473000000 }, exchange: 'EXCHG1', instrumentType: 'etf', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.001Z')) } ]; const batch = fs.batch(); for (const inst of instruments) { const ref = fs.collection('instruments').doc(); batch.set(ref, inst); } await batch.commit(); }
यह ऐप्लिकेशन, timestamp
फ़ील्ड के मुताबिक इन क्वेरी और ऑर्डर को चलाता है:
Node.js
function createQuery(fieldName, fieldOperator, fieldValue, limit = 5) { return fs.collection('instruments') .where(fieldName, fieldOperator, fieldValue) .orderBy('timestamp', 'desc') .limit(limit) .get(); } function queryCommonStock() { return createQuery('instrumentType', '==', 'commonstock'); } function queryExchange1Instruments() { return createQuery('exchange', '==', 'EXCHG1'); } function queryUSDInstruments() { return createQuery('price.currency', '==', 'USD'); }
insertData() .then(() => { const commonStock = queryCommonStock() .then( (docs) => { console.log('--- queryCommonStock: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); const exchange1Instruments = queryExchange1Instruments() .then( (docs) => { console.log('--- queryExchange1Instruments: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); const usdInstruments = queryUSDInstruments() .then( (docs) => { console.log('--- queryUSDInstruments: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); return Promise.all([commonStock, exchange1Instruments, usdInstruments]); });
कुछ रिसर्च के बाद, आपको लगता है कि ऐप्लिकेशन
प्रति सेकंड 1,000 और 1,500 इंस्ट्रुमेंट अपडेट. यह प्रति 500 राइट्स से ज़्यादा है
दूसरी बार, इंडेक्स किए गए टाइमस्टैंप वाले दस्तावेज़ों के कलेक्शन के लिए अनुमति दी जाती है
फ़ील्ड. राइट थ्��ूपुट बढ़ाने के लिए, आपके पास तीन शार्ड वैल्यू होनी चाहिए,
MAX_INSTRUMENT_UPDATES/500 = 3
. इस उदाहरण में शार्ड वैल्यू x
का इस्तेमाल किया गया है,
y
और z
. आप अपने शार्ड के लिए संख्याओं या अन्य वर्णों का भी उपयोग कर सकते हैं
वैल्यू.
शार्ड फ़ील्ड जोड़ना
अपने दस्तावेज़ों में shard
फ़ील्ड जोड़ें. shard
फ़ील्ड को सेट करें
वैल्यू x
, y
या z
पर सेट की जाती है. इससे कलेक्शन के डेटा में बदलाव करने की सीमा बढ़ जाती है
1,500 राइट्स प्रति सेकंड कर देते हैं.
Node.js
// Define our 'K' shard values const shards = ['x', 'y', 'z']; // Define a function to help 'chunk' our shards for use in queries. // When using the 'in' query filter there is a max number of values that can be // included in the value. If our number of shards is higher than that limit // break down the shards into the fewest possible number of chunks. function shardChunks() { const chunks = []; let start = 0; while (start < shards.length) { const elements = Math.min(MAX_IN_VALUES, shards.length - start); const end = start + elements; chunks.push(shards.slice(start, end)); start = end; } return chunks; } // Add a convenience function to select a random shard function randomShard() { return shards[Math.floor(Math.random() * Math.floor(shards.length))]; }
async function insertData() { const instruments = [ { shard: randomShard(), // add the new shard field to the document symbol: 'AAA', price: { currency: 'USD', micros: 34790000 }, exchange: 'EXCHG1', instrumentType: 'commonstock', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.010Z')) }, { shard: randomShard(), // add the new shard field to the document symbol: 'BBB', price: { currency: 'JPY', micros: 64272000000 }, exchange: 'EXCHG2', instrumentType: 'commonstock', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.101Z')) }, { shard: randomShard(), // add the new shard field to the document symbol: 'Index1 ETF', price: { currency: 'USD', micros: 473000000 }, exchange: 'EXCHG1', instrumentType: 'etf', timestamp: Timestamp.fromMillis( Date.parse('2019-01-01T13:45:23.001Z')) } ]; const batch = fs.batch(); for (const inst of instruments) { const ref = fs.collection('instruments').doc(); batch.set(ref, inst); } await batch.commit(); }
शार्ड किए गए टाइमस्टैंप के बारे में क्वेरी करना
shard
फ़ील्ड जोड़ने के लिए आपको अपनी क्वेरी एग्रीगेट करने के लिए अपडेट करना होगा
शार्ड किए गए परिणाम:
Node.js
function createQuery(fieldName, fieldOperator, fieldValue, limit = 5) { // For each shard value, map it to a new query which adds an additional // where clause specifying the shard value. return Promise.all(shardChunks().map(shardChunk => { return fs.collection('instruments') .where('shard', 'in', shardChunk) // new shard condition .where(fieldName, fieldOperator, fieldValue) .orderBy('timestamp', 'desc') .limit(limit) .get(); })) // Now that we have a promise of multiple possible query results, we need // to merge the results from all of the queries into a single result set. .then((snapshots) => { // Create a new container for 'all' results const docs = []; snapshots.forEach((querySnapshot) => { querySnapshot.forEach((doc) => { // append each document to the new all container docs.push(doc); }); }); if (snapshots.length === 1) { // if only a single query was returned skip manual sorting as it is // taken care of by the backend. return docs; } else { // When multiple query results are returned we need to sort the // results after they have been concatenated. // // since we're wanting the `limit` newest values, sort the array // descending and take the first `limit` values. By returning negated // values we can easily get a descending value. docs.sort((a, b) => { const aT = a.data().timestamp; const bT = b.data().timestamp; const secondsDiff = aT.seconds - bT.seconds; if (secondsDiff === 0) { return -(aT.nanoseconds - bT.nanoseconds); } else { return -secondsDiff; } }); return docs.slice(0, limit); } }); } function queryCommonStock() { return createQuery('instrumentType', '==', 'commonstock'); } function queryExchange1Instruments() { return createQuery('exchange', '==', 'EXCHG1'); } function queryUSDInstruments() { return createQuery('price.currency', '==', 'USD'); }
insertData() .then(() => { const commonStock = queryCommonStock() .then( (docs) => { console.log('--- queryCommonStock: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); const exchange1Instruments = queryExchange1Instruments() .then( (docs) => { console.log('--- queryExchange1Instruments: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); const usdInstruments = queryUSDInstruments() .then( (docs) => { console.log('--- queryUSDInstruments: '); docs.forEach((doc) => { console.log(`doc = ${util.inspect(doc.data(), {depth: 4})}`); }); } ); return Promise.all([commonStock, exchange1Instruments, usdInstruments]); });
इंडेक्स की परिभाषाएं अपडेट करना
हर सेकंड के 500 राइटिंग को हटाने के लिए, मौजूदा सिंगल-फ़ील्ड को मिटाएं
और ऐसे कंपोज़िट इंडेक्स जो timestamp
फ़ील्ड का इस्तेमाल करते हैं.
कंपोज़िट इंडेक्स की परिभाषाएं मिटाएं
Firebase कंसोल
Firebase कंसोल में, Cloud Firestore कंपोज़िट इंडेक्स पेज खोलें.
हर उस इंडेक्स के लिए जिसमें
timestamp
फ़ील्ड है, क्लिक करें बटन दबाएं और मिटाएं पर क्लिक करें.
जीसीपी कंसोल
Google Cloud Platform कंसोल में, डेटाबेस पेज पर जाएं.
डेटाबेस की सूची से ज़रूरी डेटाबेस चुनें.
नेविगेशन मेन्यू में, इंडेक्स पर क्लिक करें. इसके बाद, कंपोज़िट टैब पर क्लिक करें.
फ़िल्टर फ़ील्ड का इस्तेमाल करके वे इंडेक्स परिभाषाएं खोजें जिनमें
timestamp
फ़ील्ड.इनमें से हर इंडेक्स के लिए,
पर क्लिक करें और Delete पर क्लिक करें.
Firebase CLI
- अगर आपने Firebase सीएलआई सेट अप नहीं किया है, तो इंस्टॉल करने के लिए इन निर्देशों का पालन करें
सीएलआई को चुनें और
firebase init
कमांड चलाएं.init
निर्देश के दौरान,Firestore: Deploy rules and create indexes for Firestore
को चुनना न भूलें. - सेटअप के दौरान, Firebase सीएलआई आपकी मौजूदा इंडेक्स परिभाषाओं को डाउनलोड करता है
डिफ़ॉल्ट रूप से,
firestore.indexes.json
नाम वाली फ़ाइल. इंडेक्स की वे सभी परिभाषाएं हटाएं जिनमें
timestamp
फ़ील्ड शामिल है उदाहरण:{ "indexes": [ // Delete composite index definition that contain the timestamp field { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "exchange", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "instrumentType", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "price.currency", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, ] }
अपनी अपडेट की गई इंडेक्स परिभाषाओं को डिप्लॉय करें:
firebase deploy --only firestore:indexes
सिंगल-फ़ील्ड इंडेक्स की परिभाषाएं अपडेट करें
Firebase कंसोल
Cloud Firestore सिंगल फ़ील्ड इंडेक्स पेज खोलें Firebase कंसोल.
छूट जोड़ें पर क्लिक करें.
कलेक्शन आईडी के लिए,
instruments
डालें. फ़ील्ड पाथ के लिए,timestamp
डालें.क्वेरी का दायरा में जाकर, कलेक्शन, दोनों चुनें और कलेक्शन ग्रुप.
आगे बढ़ें पर क्लिक करें
इंडेक्स की सभी सेटिंग को बंद है पर टॉगल करें. सेव करें पर क्लिक करें.
shard
फ़ील्ड के लिए भी यही तरीका दोहराएं.
जीसीपी कंसोल
Google Cloud Platform कंसोल में, डेटाबेस पेज पर जाएं.
डेटाबेस की सूची से ज़रूरी डेटाबेस चुनें.
नेविगेशन मेन्यू में, इंडेक्स पर क्लिक करें. इसके बाद, सिंगल फ़ील्ड टैब पर क्लिक करें.
सिंगल फ़ील्ड टैब पर क्लिक करें.
छूट जोड़ें पर क्लिक करें.
कलेक्शन आईडी के लिए,
instruments
डालें. फ़ील्ड पाथ के ���िए,timestamp
डालें.क्वेरी का दायरा में जाकर, कलेक्शन, दोनों चुनें और कलेक्शन ग्रुप.
आगे बढ़ें पर क्लिक करें
इंडेक्स की सभी सेटिंग को बंद है पर टॉगल करें. सेव करें पर क्लिक करें.
shard
फ़ील्ड के लिए भी यही तरीका दोहराएं.
Firebase CLI
अपने इंडेक्स की परिभाषाओं के
fieldOverrides
सेक्शन में इन्हें जोड़ें फ़ाइल:{ "fieldOverrides": [ // Disable single-field indexing for the timestamp field { "collectionGroup": "instruments", "fieldPath": "timestamp", "indexes": [] }, ] }
अपनी अपडेट की गई इंडेक्स परिभाषाओं को डिप्लॉय करें:
firebase deploy --only firestore:indexes
नए कंपोज़िट इंडेक्स बनाएं
timestamp
वाले पिछले सभी इंडेक्स हटाने के बाद,
आपके ऐप्लिकेशन के लिए ज़रूरी नए इंडेक्स तय करें. कोई भी इंडेक्स जिसमें
timestamp
फ़ील्ड में shard
फ़ील्ड भी होना चाहिए. उदाहरण के लिए,
ऊपर दी गई क्वेरी के हिसाब से, इन इंडेक्स को जोड़ें:
कलेक्शन | इंडेक्स किए गए फ़ील्ड | क्वेरी का स्कोप |
---|---|---|
इंस्ट्रुमेंट | शार्ड, price.currency, टाइमस्टैंप | कलेक्शन |
इंस्ट्रुमेंट | शार्ड, एक्सचेंज, टाइमस्टैंप | कलेक्शन |
इंस्ट्रुमेंट | शार्ड, इंस्ट्रुमेंटटाइप, टाइमस्टैंप | कलेक्शन |
गड़बड़ी के मैसेज
अपडेट की गई क्वेरी चलाकर, ये इंडेक्स बनाए जा सकते हैं.
हर क्वेरी से गड़बड़ी का मैसेज मिलता है. इसमें ज़रूरी क्वेरी बनाने का लिंक भी होता है Firebase कंसोल में इंडेक्स करने के लिए किया जा सकता है.
Firebase CLI
अपनी इंडेक्स परिभाषा फ़ाइल में इन इंडेक्स को जोड़ें:
{ "indexes": [ // New indexes for sharded timestamps { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "shard", "order": "DESCENDING" }, { "fieldPath": "exchange", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "shard", "order": "DESCENDING" }, { "fieldPath": "instrumentType", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, { "collectionGroup": "instruments", "queryScope": "COLLECTION", "fields": [ { "fieldPath": "shard", "order": "DESCENDING" }, { "fieldPath": "price.currency", "order": "ASCENDING" }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, ] }
अपनी अपडेट की गई इंडेक्स परिभाषाओं को डिप्लॉय करें:
firebase deploy --only firestore:indexes
क्रम से इंडेक्स किए गए फ़ील्ड की सीमा में बदलाव करने के डेटा को समझना
क्रम में इंडेक्स किए गए फ़ील्ड के लिए, लिखने की दर की सीमा इन चीज़ों से तय होती है Cloud Firestore, इंडेक्स वैल्यू और स्केल इंडेक्स राइट को स्टोर करता है. हर एक के लिए इंडेक्स राइट करने के लिए उपलब्ध है, तो Cloud Firestore एक की-वैल्यू एंट्री तय करता है, जो एक-दूसरे से जुड़ी होती है दस्तावेज़ का नाम और इंडेक्स किए गए हर फ़ील्ड क�� वैल्यू. Cloud Firestore इन इंडेक्स एंट्री को टैबलेट नाम के डेटा के ग्रुप में व्यवस्थित करता है. हर Cloud Firestore सर्वर में एक या एक से ज़्यादा टैबलेट होते हैं. जब 'राइट' इस पर लोड होता है किसी खास टैबलेट का साइज़ बहुत ज़्यादा हो जाता है, तो Cloud Firestore, हॉरिज़ॉन्टल तौर पर अडजस्ट हो जाता है टैबलेट को छोटे-छोटे टैबलेट में बांटकर और नए टैबलेट को फैलाकर अलग-अलग Cloud Firestore सर्वर पर लागू किया जाता है.
Cloud Firestore किसी एक ही जगह पर लेक्सिकोग्राफ़िक तौर पर इंडेक्स एंट्री को बंद करता है टैबलेट. अगर टैबलेट में इंडेक्स वैल्यू बहुत पास-पास हैं, जैसे कि टाइमस्टैंप फ़ील्ड को Cloud Firestore के लिए, बेहतर तरीके से अलग नहीं किया जा सकता छोटे-छोटे टैबलेट में बदल सकते हैं. इससे एक ऐसा हॉट स्पॉट बनता है जहां एक टैबलेट वह बहुत अधिक ट्रैफ़िक प्राप्त करता है, और स्पॉट धीमा हो जाता है.
टाइमस्टैंप फ़ील्ड को शेयर करके, यह मुमकिन है कि इसके लिए, Cloud Firestore को एक साथ कई विकल्पों में इस्तेमाल किया जा सकता है टैबलेट. हालांकि, टाइमस्टैंप फ़ील्ड की वैल्यू एक-दूसरे के आस-पास रह सकती हैं, इकट्ठा किए गए शार्ड और इंडेक्स की वैल्यू से Cloud Firestore के लिए ज़रूरी जगह मिलती है का इस्तेमाल करें.
आगे क्या करना है
- स्केल के लिए डिज़ाइन करने के सबसे सही तरीके पढ़ें
- किसी एक दस्तावेज़ में लिखने की ज़्यादा दर वाले मामलों के लिए, परेशान न किए गए काउंटर देखें
- Cloud Firestore के लिए स्टैंडर्ड सीमाएं देखें