तिथि के अनुसार डायनेमोडी को छोड़ना


102

मैं एक रिलेशनल डेटाबेस बैकग्राउंड से आ रहा हूँ और amazon के DynamoDB के साथ काम करने की कोशिश कर रहा हूँ

मेरे पास एक हैश की "DataID" और एक सीमा "CreatedAt" और इसमें वस्तुओं का एक समूह है।

मैं उन सभी वस्तुओं को प्राप्त करने की कोशिश कर रहा हूं जो एक विशिष्ट तिथि के बाद बनाई गई थीं और तिथि के अनुसार क्रमबद्ध थीं। जो एक रिलेशनल डेटाबेस में बहुत सीधा है।

DynamoDB में निकटतम चीज़ जो मुझे मिल सकती है वह है एक क्वेरी और फ़िल्टर से अधिक रेंज की का उपयोग करना। एकमात्र मुद्दा यह है कि क्वेरी करने के लिए मुझे एक हैश कुंजी की आवश्यकता होती है जो उद्देश्य को हरा देती है।

तो मैं क्या गलत हूं? क्या मेरी तालिका स्कीमा गलत है, क्या हैश कुंजी अद्वितीय नहीं होनी चाहिए? या वहाँ क्वेरी करने के लिए एक और तरीका है?

जवाबों:


34

अपडेट किया गया उत्तर:

DynamoDB इस प्रकार की क्वेरी में सहायता के लिए द्वितीयक अनुक्रमणिकाओं के विनिर्देशन की अनुमति देता है। द्वितीयक सूचकांक या तो वैश्विक हो सकते हैं, जिसका अर्थ है कि सूचकांक पूरे तालिका को हैश कीज़ पर फैलाता है, या स्थानीय अर्थ यह है कि सूचकांक प्रत्येक हैश कुंजी विभाजन के भीतर मौजूद होगा, इस प्रकार क्वेरी बनाते समय हैश कुंजी को भी निर्दिष्ट करने की आवश्यकता होती है।

इस प्रश्न में उपयोग के मामले के लिए, आप "CreatedAt" फ़ील्ड पर एक वैश्विक द्वितीयक सूचकांक का उपयोग करना चाहेंगे।

डायनॉम्बि डी सेकेंडरी इंडेक्स पर अधिक के लिए सेकेंडरी इंडेक्स डॉक्यूमेंटेशन देखें

मूल उत्तर:

डायनॉम्बीडी केवल सीमा कुंजी पर अनुक्रमित लुकअप की अनुमति नहीं देता है। हैश कुंजी की आवश्यकता है जैसे कि सेवा को पता है कि डेटा को खोजने के लिए किस विभाजन को देखना है।

आप निश्चित रूप से दिनांक मान द्वारा फ़िल्टर करने के लिए एक स्कैन ऑपरेशन कर सकते हैं, हालांकि इसके लिए एक पूर्ण तालिका स्कैन की आवश्यकता होगी, इसलिए यह आदर्श नहीं है।

यदि आपको कई प्राथमिक कुंजियों में समय-समय पर रिकॉर्ड की अनुक्रमणित लुकअप करने की आवश्यकता है, तो DynamoDB आपके उपयोग के लिए आदर्श सेवा नहीं हो सकती है, या आपको आइटम संग्रहीत करने के लिए एक अलग तालिका (या तो DynamoDB या किसी रिलेशनल स्टोर में) का उपयोग करने की आवश्यकता हो सकती है मेटाडेटा जिसके विरुद्ध आप अनुक्रमणित लुकअप कर सकते हैं।


14
नीचे दिए गए उत्तर पर टिप्पणी देखें; देखते हैं नहीं तो कम से कम क्या ओपी पूछा के लिए नहीं अब इस संभाल करने के लिए, तरीके। GSI को अभी भी हैश कुंजी निर्दिष्ट करने की आवश्यकता है, इसलिए आप CreatedAtएक निश्चित बिंदु से अधिक के साथ सभी रिकॉर्ड के लिए क्वेरी नहीं कर सकते ।
pkaeding

4
@ ठीक करना सही है। आप रिकॉर्ड पुराने तो कुछ विशिष्ट प्राप्त कर सकते हैं की तारीख का उपयोग कर स्कैन , लेकिन आप नहीं उन्हें क्रमबद्ध क्रम में प्राप्त कर सकते हैं। GSI इस मामले में आपकी मदद नहीं करेगा। विभाजन कुंजी को छांटना संभव नहीं है , न ही केवल श्रेणी कुंजी को क्वेरी करना संभव है ।
gkiko

15
आप में से जो लोग भ्रमित हैं। इस उत्तर गलत है। उसका मूल उत्तर सही है लेकिन उसका अद्यतन उत्तर नहीं है। नीचे पढ़ें वारेन पारद का जवाब यह सही है।
रयान

1
@MikeBrant मैं क्वेरी करना चाहता हूं (स्कैन नहीं, जो तालिका में प्रत्येक आइटम को देखता है, जिससे यह बहुत ही अक्षम और महंगा हो जाता है) तालिका के GSI हैश कुंजी (CreatedAt) पर एक तालिका को अधिक से अधिक प्रतीक का उपयोग करके। जहाँ तक मुझे पता है, यह नहीं किया जा सकता है।
अजीज जावेद

4
प्राथमिक विभाजन के रूप में एक तारीख का उपयोग करते समय आपको जो समस्या आती है, वह यह है कि आप कुछ या एक साथियों पर एक हॉटस्पॉट बना सकते हैं, इस तथ्य के कारण कि अधिकांश डेटा स्टोरेज में नए डेटा पुराने डेटा की तुलना में अधिक बार क्वियर होते हैं।
नॉलेज

53

आपकी वर्तमान सारणी संरचना को देखते हुए यह वर्तमान में DynamoDB में संभव नहीं है। बड़ी चुनौती यह समझने की है कि तालिका (विभाजन) की हैश कुंजी को अलग-अलग टेबल बनाने के रूप में माना जाना चाहिए। कुछ मायनों में यह वास्तव में शक्तिशाली है (प्रत्येक उपयोगकर्ता या ग्राहक के लिए एक नई तालिका बनाने के रूप में विभाजन कुंजी के बारे में सोचो, आदि ...)।

क्वेरी केवल एक ही विभाजन में की जा सकती है। यह वास्तव में कहानी का अंत है। इसका मतलब है कि यदि आप तिथि के अनुसार क्वेरी करना चाहते हैं (आप युग के बाद से मिसे का उपयोग करना चाहते हैं), तो आप जिन सभी वस्तुओं को एक ही क्वेरी में प्राप्त करना चाहते हैं, उनके पास एक ही हैश (विभाजन कुंजी) होना चाहिए।

मुझे यह योग्यता चाहिए। आप पूरी तरह scanसे उस कसौटी पर खरे उतर सकते हैं, जो कोई समस्या नहीं है, लेकिन इसका मतलब है कि आप अपनी तालिका में हर एक पंक्ति को देख रहे होंगे, और फिर जाँच कर सकते हैं कि क्या उस पंक्ति में कोई तिथि है जो आपके मापदंडों से मेल खाती है। यह वास्तव में महंगा है, खासकर यदि आप पहली बार तारीख तक घटनाओं के भंडारण के व्यवसाय में हैं (यानी आपके पास बहुत सारी पंक्तियाँ हैं।)

आपको समस्या को हल करने के लिए सभी डेटा को एक ही पार्टीशन में डालने का प्रलोभन दिया जा सकता है, और आप पूरी तरह से कर सकते हैं, हालाँकि आपका थ्रूपुट दर्द कम होगा, यह देखते हुए कि प्रत्येक विभाजन को कुल सेट राशि का एक अंश प्राप्त होता है।

सबसे अच्छी बात यह है कि डेटा को बचाने के लिए अधिक उपयोगी विभाजन निर्धारित करना है:

  • क्या आपको वास्तव में सभी पंक्तियों को देखने की आवश्यकता है, या क्या यह केवल एक विशिष्ट उपयोगकर्ता द्वारा पंक्तियाँ हैं?

  • क्या पहले महीने की सूची को कम करना, और कई प्रश्न करना (प्रत्येक माह के लिए एक) करना ठीक होगा? या साल से?

  • यदि आप समय श्रृंखला विश्लेषण कर रहे हैं, तो कुछ विकल्प हैं, विभाजन कुंजी को आसान PUTबनाने के लिए गणना की गई किसी चीज़ को बदल दें query, या किसी अन्य आरईएस उत्पाद का उपयोग करें जैसे कि किनिस जो खुद को केवल लॉग-इन करने के लिए उधार देता है।


4
मैं "अंतिम वर्ष" पर विचार करने के बारे में आपके अंतिम पैराग्राफ में दिए गए विकल्प पर जोर देना चाहता हूं। एक विशेषता बनाएं yyyyऔर उस पर हैश करें, लेकिन एक createdतिथि भी बनाएं जिसे आप अपनी सीमा कुंजी के रूप में उपयोग कर सकते हैं। फिर आपको प्रति वर्ष 10GB डेटा (27 एमबी प्रति दिन) मिलता है जो शायद अधिक परिस्थितियों के लिए ठीक है। इसका मतलब यह है कि आपको प्रति वर्ष एक क्वेरी बनानी होगी जब दिनांक प्रश्न वर्ष सीमा पर जाते हैं, लेकिन कम से कम यह काम करेगा और यह डमी हैश कुंजी बनाने से अधिक सुरक्षित है।
रयान

1
एक अन्य विकल्प: stackoverflow.com/questions/35963243/…
रेयान

1
जैसा कि ऊपर दिए गए लिंक में बताया गया है, कड़ाई से समय-आधारित विभाजन की चाबियाँ गर्म स्थानों को जन्म दे सकती हैं। यदि आपको समय-आधारित विभाजन कुंजियों का उपयोग करना चाहिए, तो कई विभाजनों पर समय अवधि का प्रसार करने के लिए विभाजन कुंजी में कुछ अन्य तत्व जोड़ना बेहतर है। मैंने केवल 0-n के बीच एक उपसर्ग का उपयोग करने के सुझावों को देखा है जहां n विभाजन की संख्या है हर बार बाल्टी को फैलाया जाना चाहिए।
Dres

@RyanShillington ग्लोबल सेकेंडरी इंडेक्स पर 10GB की कोई सीमा नहीं है । यह सीमा केवल स्थानीय माध्यमिक अनुक्रमितों पर लागू होती है ।
साइमन फोर्सबर्ग

18

इस समस्या को हल करने के लिए मैंने जो दृष्टिकोण अपनाया, वह नीचे के रूप में एक वैश्विक माध्यमिक सूचकांक बनाया गया है। यकीन नहीं होता कि यह सबसे अच्छा तरीका है लेकिन उम्मीद है कि यह किसी के लिए उपयोगी है।

Hash Key                 | Range Key
------------------------------------
Date value of CreatedAt  | CreatedAt

डेटा प्राप्त करने के लिए दिनों की संख्या निर्दिष्ट करने के लिए HTTP एपीआई उपयोगकर्ता पर लगाई गई सीमा, 24 घंटे के लिए डिफ़ॉल्ट है।

इस तरह, मैं हमेशा हैशके को वर्तमान तिथि के दिन के रूप में निर्दिष्ट कर सकता हूं और रेंजकेई पुनः प्राप्त करते समय> और <ऑपरेटरों का उपयोग कर सकता हूं। इस तरह यह डेटा कई शार्प में भी फैल जाता है।


8

आपकी हैश की (प्राथमिक प्रकार की) को अद्वितीय होना चाहिए (जब तक कि आपके पास अन्य लोगों द्वारा बताई गई सीमा न हो)।

आपके मामले में, अपनी तालिका को क्वेरी करने के लिए आपके पास एक द्वितीयक सूचकांक होना चाहिए।

|  ID  | DataID | Created | Data |
|------+--------+---------+------|
| hash | xxxxx  | 1234567 | blah |

आपका हैश कुंजी ID है आपका द्वितीयक सूचकांक निम्न रूप में परिभाषित किया गया है: DataID-Created-index (यह वह नाम है जिसे DynamoDB उपयोग करेगा)

फिर, आप इस तरह से एक प्रश्न बना सकते हैं:

var params = {
    TableName: "Table",
    IndexName: "DataID-Created-index",
    KeyConditionExpression: "DataID = :v_ID AND Created > :v_created",
    ExpressionAttributeValues: {":v_ID": {S: "some_id"},
                                ":v_created": {N: "timestamp"}
    },
    ProjectionExpression: "ID, DataID, Created, Data"
};

ddb.query(params, function(err, data) {
    if (err) 
        console.log(err);
    else {
        data.Items.sort(function(a, b) {
            return parseFloat(a.Created.N) - parseFloat(b.Created.N);
        });
        // More code here
    }
});

अनिवार्य रूप से आपकी क्वेरी इस तरह दिखती है:

SELECT * FROM TABLE WHERE DataID = "some_id" AND Created > timestamp;

द्वितीयक सूचकांक आवश्यक पढ़ने / लिखने की क्षमता इकाइयों को बढ़ाएगा ताकि आपको उस पर विचार करने की आवश्यकता हो। यह अभी भी एक स्कैन करने से काफी बेहतर है, जो कि महंगे रीड एंड टाइम में महंगा होगा (और मेरा मानना ​​है कि यह 100 आइटम तक सीमित है)।

यह ऐसा करने का सबसे अच्छा तरीका नहीं हो सकता है, लेकिन आरडी के लिए इस्तेमाल होने वाले किसी व्यक्ति के लिए (मैं एसक्यूएल के लिए भी उपयोग किया जाता हूं) यह उत्पादक होने का सबसे तेज़ तरीका है। चूंकि स्कीमा के संबंध में कोई अड़चन नहीं है, इसलिए आप कुछ ऐसे काम कर सकते हैं जो काम करते हैं और एक बार आपके पास सबसे कुशल तरीके से काम करने के लिए बैंडविड्थ है, तो आप चीजों को बदल सकते हैं।


1
आप कहते हैं कि कोई अड़चन नहीं है, लेकिन आपको पता होना चाहिए कि इस दृष्टिकोण का अर्थ है कि आप अधिकतम 10GB डेटा (एकल विभाजन का अधिकतम) बचा सकते हैं।
रयान

यदि DataID ज्ञात है, तो यह दृष्टिकोण होता। लेकिन यहां हमें प्रत्येक पंक्ति प्राप्त करने की आवश्यकता है जिसके लिए निर्मित कुछ दिनांक से अधिक है।
यसिथ प्रबुद्धका

3

आप एक 'उत्पाद श्रेणी' आईडी की तर्ज पर हैश की कुछ बना सकते हैं, फिर टाइमस्टैम्प के संयोजन के रूप में रेंज कुंजी अंत में संलग्न एक अद्वितीय आईडी के साथ। इस तरह से आप हैश कुंजी को जानते हैं और फिर भी तारीख को अधिक से अधिक क्वेरी कर सकते हैं।


1

आपके पास कई समान हैश कुंजी हो सकती हैं; लेकिन केवल अगर आपके पास एक रेंज कुंजी है जो भिन्न होती है। इसे फ़ाइल स्वरूपों की तरह सोचें; आप एक ही फ़ोल्डर में एक ही नाम के साथ 2 फाइलें रख सकते हैं जब तक कि उनका प्रारूप अलग हो। यदि उनका प्रारूप समान है, तो उनका नाम अलग होना चाहिए। यही अवधारणा डायनेमोडीबी की हैश / रेंज कुंजियों पर लागू होती है; बस हैश को नाम और सीमा को प्रारूप के रूप में समझें।

इसके अलावा, मुझे यह याद नहीं है कि ओपी के समय उनके पास ऐसा था (मुझे विश्वास नहीं है कि उन्होंने किया था), लेकिन वे अब स्थानीय माध्यमिक सूचकांक पेश करते हैं।

इनमें से मेरी समझ यह है कि अब आपको पूर्ण स्कैन किए बिना वांछित प्रश्नों को करने की अनुमति देनी चाहिए। नकारात्मक पक्ष यह है कि इन अनुक्रमों को तालिका निर्माण में निर्दिष्ट किया जाना है, और आइटम बनाते समय भी (मेरा मानना ​​है) रिक्त नहीं हो सकता है। इसके अलावा, उन्हें अतिरिक्त थ्रूपुट की आवश्यकता होती है (हालांकि आमतौर पर स्कैन के रूप में ज्यादा नहीं) और भंडारण, इसलिए यह कुछ के लिए एक आदर्श समाधान नहीं है, लेकिन एक व्यवहार्य विकल्प है।

मैं अभी भी डायनमोडीबी का उपयोग करने के पसंदीदा तरीके के रूप में माइक ब्रैंट के जवाब की सिफारिश करता हूं; और स्वयं उस विधि का उपयोग करें। मेरे मामले में, मेरे पास केवल एक केंद्रीय तालिका है जिसमें मेरी आईडी के रूप में केवल एक हैश कुंजी है, फिर माध्यमिक तालिकाएं जिनके पास एक हैश और श्रेणी है, जिन्हें उद्धृत किया जा सकता है, फिर आइटम केंद्रीय तालिका के "रुचि के आइटम" पर कोड को सीधे इंगित करता है ।

द्वितीयक अनुक्रमितों के बारे में अतिरिक्त डेटा अमेज़ॅन के डायनेमोडी प्रलेखन में रुचि रखने वालों के लिए यहां पाया जा सकता है ।

वैसे भी, उम्मीद है कि यह किसी और की मदद करेगा जो इस धागे पर होता है।


मैंने एक डायनॉम्बीडी टेबल बनाने की कोशिश की, जहाँ टाइप का हैश का AWSDynamoDBKeySchemaElement 'createAt' और फिर AWSDynamoDBKeySchemaElement 'typeAt' प्रकार की श्रेणी का था और मुझे एक त्रुटि मिली, जिसमें त्रुटि डोमेन = com.amazonaws.AWSDynamoDerrrorrub के साथ एक त्रुटि मिली। = {__ प्रकार = com.amazon.coral.validate # ValidationException, message = कुंजीशब्द में हैश कुंजी और श्रेणी कुंजी तत्व दोनों का एक ही नाम है}। इसलिए मुझे नहीं लगता कि आप जो कह रहे हैं वह सही है।
user1709076

मेरा मानना ​​है कि आप गलत समझे (हालांकि मुझे लगता है कि मैं अपने विवरण में बहुत स्पष्ट नहीं था, या तो)। आपके पास तालिका में समान नाम के साथ 2 अलग-अलग विशेषताएँ (कॉलम) नहीं हो सकती हैं, लेकिन जब आप रेंज कुंजी के साथ एक हैश कुंजी बनाते हैं, तो आपके पास कई आइटम हो सकते हैं जो सभी उसी हैश का उपयोग करते हैं जब तक कि उनकी सीमा अलग हो, और विपरीत क्रम में। उदाहरण के लिए: आपका हैश "आईडी" है और आपकी सीमा "तिथि" है, जब तक आईडी "1234" के 2 उदाहरण हो सकते हैं, जब तक कि उनकी तिथि अलग है।
DGolberg

आह DGoldberg! आई गेट यू नाउ। एक दम बढ़िया। इसलिए मेरे मामले के बाद से मैं केवल और हमेशा केवल पाठ संदेशों के लिए 'तारीख = x' के बाद क्वेरी करना चाहता हूं, ऐसा लगता है कि मैं सभी पाठ संदेशों को समान 'नकली_श = 1' सेट कर सकता हूं। इसके बाद my query.keyConditionExpression = @ "fake_hash = 1 और #Date>: val" करें। आपका बहुत बहुत धन्यवाद। यदि आपके पास कोई अन्य इनपुट है तो मुझे यह सुनकर खुशी होगी क्योंकि यह हैश है कि हमेशा एक ही मूल्य है अजीब लगता है?
191 बजे उपयोगकर्ता 1709076

मुझे फिर से जांच करनी होगी, लेकिन मुझे पूरा यकीन है कि आप हैश-ओनली टेबल पर एक क्वेरी कर सकते हैं ... हालाँकि यदि आप अपने हैश के रूप में एक तारीख / समय टिकट का उपयोग कर रहे हैं, तो मैं आपको नीचे रिकॉर्ड करने की सलाह दूंगा सबसे छोटी इकाई संभव है, जैसे कि मिलीसेकंड या नैनो / माइक्रोसेकंड (कोड को रिकॉर्ड करने की सबसे छोटी इकाई जो भी हो), अतिव्यापी दिनांक / समय की संभावना को कम करने के लिए। इसके अतिरिक्त, आप ओवरलैप्स की संभावना को कम करने के लिए आशावादी लॉकिंग जोड़ सकते हैं: docs.aws.amazon.com/amazondynamodb/latest/developerguide/… बस एक और समय फिर से प्रयास करें यदि कोई संघर्ष है।
डीजीबर्गबर्ग

-11

अद्यतित उत्तर डायनामो डीबी क्वेरीज़ का अनुमान लगाने योग्य थ्रूपुट के साथ उपयोग करने का कोई सुविधाजनक तरीका नहीं है। एक (उप इष्टतम) विकल्प कृत्रिम HashKey और CreatedAt के साथ GSI का उपयोग करना है। फिर अकेले HashKey द्वारा क्वेरी करें और परिणाम ऑर्डर करने के लिए ScanIndexForward का उल्लेख करें। यदि आप एक प्राकृतिक HashKey (आइटम आदि की श्रेणी कह सकते हैं) के साथ आ सकते हैं तो यह तरीका एक विजेता है। दूसरी ओर, यदि आप सभी वस्तुओं के लिए समान हैशके रखते हैं, तो यह अधिकतर थ्रूपुट को प्रभावित करेगा जब आपका डेटा सेट 10GB (एक विभाजन) से आगे बढ़ता है

मूल उत्तर: आप इसे GSI का उपयोग करके डायनमोबडी में कर सकते हैं। "CreatedAt" फ़ील्ड को GSI के रूप में बनाएँ और प्रश्नों को जारी करें (GT some_date)। इस तरह के प्रश्नों के लिए दिनांक को एक संख्या (msecs के बाद से) के रूप में संग्रहीत करें।

विवरण यहां उपलब्ध हैं: ग्लोबल सेकेंडरी इंडेक्स - अमेजन डायनमोबीडी: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using

यह एक बहुत शक्तिशाली विशेषता है। विदित हो कि क्वेरी (EQ | LE | LT | GE | GT | BEGINS_WWE. BETWEEN) स्थिति - Amazon DynamoDB: http://docs.aws.amazon.com/amazondynamodb/lairest/APIReference/API_Condition.html


31
मैंने अस्वीकार कर दिया क्योंकि जहां तक ​​मैं बता सकता हूं, आपका उत्तर गलत है। तालिका की प्राथमिक कुंजी के समान, आप केवल EQ ऑपरेटर के साथ GSI की हैश कुंजी को क्वेरी कर सकते हैं। यदि आप यह अनुमान लगा रहे थे कि CreatedAtजीएसआई की रेंज कुंजी होनी चाहिए, तो आपको एक हैश कुंजी चुनने की आवश्यकता होगी - और फिर आप वापस वहीं आ जाएं, जहां से आपने शुरुआत की थी, क्योंकि आप जीटी पर CreatedAtकेवल एक विशिष्ट मूल्य के लिए क्वेरी कर पाएंगे । हैश कुंजी।
पाफ

पाफ से सहमत। हैश कुंजी के साथ जीएसआई का उपयोग करना क्योंकि निर्माण समय ओपी में पूछे गए प्रश्न के साथ मदद नहीं करता है।
4-8-15-16-23-42
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.