दो अलग-अलग संग्रहों में डुप्लीकेट मोंगो ऑब्जेक्टआईड के बनने की संभावना?


187

क्या दो अलग-अलग संग्रहों में दस्तावेज़ के लिए एक ही सटीक मानगो ऑब्जेक्टआईड उत्पन्न करना संभव है? मुझे पता है कि यह निश्चित रूप से बहुत ही संभावना नहीं है, लेकिन क्या यह संभव है?

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

खाता बनाने के बाद हम अभी भी उस डेटा को हाइलाइट करते हैं जो निर्वाचित अधिकारी से जुड़ा है, लेकिन वे अब भी उपयोगकर्ताओं के संग्रह का एक हिस्सा हैं, जो संबंधित उपयोगकर्ता ऑब्जेक्टआईड के साथ अपने प्रोफ़ाइल को हमारे आवेदन के साथ बातचीत करने के लिए मैप करते हैं।

हमने कुछ महीने पहले MySql से Mongo में अपने एप्लिकेशन को परिवर्तित करना शुरू कर दिया था और जब हम संक्रमण में हो तो हम इन दोनों डेटा प्रकारों के लिए विरासत MySql id स्टोर कर रहे हैं और अब हम उपयोगकर्ताओं में निर्वाचित आधिकारिक Mongo ObjectId को भी स्टोर करना शुरू कर रहे हैं। दस्तावेज़ चुने गए आधिकारिक डेटा पर वापस जाने के लिए।

मैं नए उपयोगकर्ता ObjectId को निर्दिष्ट करने के लिए पिछले चुने गए आधिकारिक ObjectId के रूप में निर्दिष्ट कर रहा था और चीजों को सरल बनाने के लिए विचार कर रहा था, लेकिन यह सुनिश्चित करना चाहता था कि किसी भी मौजूदा उपयोगकर्ता ObjectId के साथ टकराव संभव नहीं था।

आपकी अंतर्दृष्टि के लिए धन्यवाद।

संपादित करें: इस प्रश्न को पोस्ट करने के तुरंत बाद, मुझे एहसास हुआ कि मेरा प्रस्तावित समाधान बहुत अच्छा विचार नहीं था। बेहतर होगा कि हम वर्तमान स्कीमा को अपने पास रखें और उपयोगकर्ताओं के दस्तावेज़ में चुने गए आधिकारिक '_id' से लिंक करें।



1
मैंने उस पृष्ठ को पहले पढ़ा है। विडंबना यह है कि मैं वास्तव में पिछले उत्तर में उसी पृष्ठ से जुड़ा हुआ हूं। और मुझे "अद्वितीय होने की यथोचित उच्च संभावना" अस्वीकरण दिखाई दिया, लेकिन अगर संग्रह में किसी भी कारक को डाला जा रहा है तो यह अनिश्चित था। मुझे लगता है मैं क्या अनिश्चित हूँ वास्तव में 2 बाइट प्रक्रिया आईडी भाग ObjectId का वास्तव में प्रतिनिधित्व करता है। अगर इसका संग्रह से कुछ लेना-देना है तो विभिन्न संग्रह में सटीक एक ही मशीन पर एक ही समय में बनाए गए दो अलग-अलग दस्तावेजों के बीच विशिष्टता होगी।
एंथनी जैक

1
2byte प्रोसेस आईडी, ObjectID जनरेट करने वाली प्रक्रिया का pid है। एक उदाहरण के रूप में, यहाँ कोड पिमोन्गो का उपयोग ऑब्जेक्ट जनरेट करने के लिए किया जाता है: github.com/mongodb/mongo-python-driver/blob/master/bson/…
mstearn

एक बैच मुझे भागा, बैच डालने में है। मैं 10k दस्तावेजों के बैच बना रहा था, और हर बार टकरा रहा था क्योंकि काउंटर का हिस्सा हर बार लुढ़कता था।
जूल

मुझे पता है कि यह एक समय हो गया है, लेकिन 10K दस्तावेज़ काउंटर पर रोल नहीं करेंगे। काउंटर भाग तीन बाइट्स है, न कि तीन अंक। यह 16 मिलियन से अधिक है।
अस्य कामस्की

जवाबों:


318

संक्षिप्त जवाब

बस अपने प्रारंभिक प्रश्न के लिए एक सीधी प्रतिक्रिया जोड़ने के लिए: हाँ, यदि आप BSON ऑब्जेक्ट आईडी पीढ़ी का उपयोग करते हैं, तो अधिकांश ड्राइवरों के लिए आईडी लगभग निश्चित रूप से संग्रह में अद्वितीय होने जा रहे हैं। "लगभग निश्चित रूप से" का क्या अर्थ है, इसके लिए नीचे देखें।

लंबा जवाब

मानगो डीबी ड्राइवरों द्वारा बनाई गई BSON ऑब्जेक्ट आईडी संग्रह के पार अद्वितीय होने की संभावना है। यह मुख्य रूप से आईडी के अंतिम 3 बाइट्स के कारण है, जो कि अधिकांश ड्राइवरों के लिए एक स्थिर वेतन वृद्धि काउंटर के माध्यम से उत्पन्न होता है। वह काउंटर संग्रह-स्वतंत्र है; यह वैश्विक है। उदाहरण के लिए, जावा ड्राइवर, बेतरतीब ढंग से आरंभिक, स्थिर परमाणुइंटर का उपयोग करता है।

तो क्यों, मैंगो डॉक्स में, क्या वे कहते हैं कि आईडी "अत्यधिक होने की संभावना है" अद्वितीय होने के बजाय, यह कहते हुए कि वे अद्वितीय होंगे? तीन संभावनाएं हो सकती हैं, जहां आपको एक विशिष्ट आईडी नहीं मिलेगी (कृपया मुझे बताएं कि क्या अधिक हैं):

इस चर्चा से पहले, याद रखें कि BSON ऑब्जेक्ट आईडी में निम्न शामिल हैं:

[4 बाइट्स सेकंड के बाद से युग, 3 बाइट्स मशीन हैश, 2 बाइट्स प्रक्रिया आईडी, 3 बाइट्स काउंटर]

यहां तीन संभावनाएं हैं, इसलिए आप अपने लिए निर्णय लेते हैं कि एक डुबकी लगाने की कितनी संभावना है:

1) काउंटर ओवरफ्लो: काउंटर में 3 बाइट्स हैं। यदि आप एक ही मशीन पर, एक ही प्रक्रिया में, 16,777,216 (2 ^ 24) दस्तावेजों को एक ही प्रक्रिया में सम्मिलित करते हैं, तो आप बढ़े हुए काउंटर बाइट्स को ओवरफ्लो कर सकते हैं और एक ही समय, मशीन को साझा करने वाली दो ऑब्जेक्ट आईडी के साथ समाप्त हो सकते हैं , प्रक्रिया, और काउंटर मान।

2) काउंटर नॉन-इंक्रीमेंटिंग: कुछ मोंगो ड्राइवर काउंटर बाइट्स के लिए संख्या बढ़ाने के बजाय रैंडम नंबर का उपयोग करते हैं। इन मामलों में, एक गैर-विशिष्ट आईडी बनाने का 1 / 16,777,216 मौका है, लेकिन केवल अगर वे दो आईडी एक ही सेकंड में उत्पन्न होती हैं (यानी आईडी के समय सेक्शन से अगले सेकंड तक), उसी पर मशीन, एक ही प्रक्रिया में।

3) मशीन और प्रक्रिया हैश को समान मान। मशीन आईडी और प्रक्रिया आईडी मान, कुछ अत्यधिक असंभावित परिदृश्य में, दो अलग-अलग मशीनों के लिए समान मानों के लिए मैप कर सकते हैं। यदि ऐसा होता है, और एक ही समय में, दो अलग मशीनों पर दो काउंटर, एक ही सेकंड के दौरान, एक ही मान उत्पन्न करते हैं, तो आप एक डुप्लिकेट आईडी के साथ समाप्त करेंगे।

इन तीन परिदृश्यों के लिए बाहर देखने के लिए कर रहे हैं। परिदृश्य 1 और 3 की संभावना बहुत कम लगती है, और यदि आप सही ड्राइवर का उपयोग कर रहे हैं तो परिदृश्य 2 पूरी तरह से बचा जा सकता है। आपको सुनिश्चित करने के लिए ड्राइवर के स्रोत की जांच करनी होगी।


क्या 3 बाइट्स काउंटर प्रति मशीन प्रति सेकंड प्रति प्रक्रिया में डाले गए 2 ^ 24 = 16777216 दस्तावेजों की संख्या को स्वीकार करने की क्षमता का प्रतिनिधित्व नहीं करता है?
फॉरेस्ट ये

आप बिल्कुल सही हैं, मैंने गलती से बिट्स की संख्या को आधा कर दिया - जवाब में संशोधन किया गया है।
राज आडवाणी

चूँकि मैंने अभी इसमें कदम रखा है, इसलिए मुझे जोड़ने दो कि कुछ ड्राइवर (जैसे C), हालांकि वेतन वृद्धि का उपयोग करते हैं, कभी-कभी वेतन वृद्धि नहीं करते हैं, इसलिए समय-समय पर, रेस की स्थिति के कारण यह एक ही oid उत्पन्न करता है
पावेल वेसेली

39
आप इस तथ्य पर पूरी तरह से फ़िदा हो गए हैं कि 136 वर्षों में आपके पास एक और शॉट होगा जो कि आपके पास ObjectIdमशीन हैश, प्रक्रिया आईडी और काउंटर के रूप में लंबे समय से पहले था, सभी को समान रूप से चालू करें
जैमाइलक

25
@jamylak हम उस समस्या का ध्यान रखेंगे जब यह अत्यावश्यक हो जाता है (उन लोगों ने कहा जो 70 के दशक में YYMMDD तिथि प्रारूप को मानकीकृत करते हैं)
फिलिप्पुस

14

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

अब यदि आप सामान्य रूप से _id क्षेत्र की बात कर रहे हैं, तो हमें संग्रह में विशिष्टता की आवश्यकता नहीं है, इसलिए पुराने _id का पुन: उपयोग करना सुरक्षित है। एक ठोस उदाहरण के रूप में, यदि आपके पास दो संग्रह हैं, colorsऔर fruits, दोनों एक साथ एक वस्तु की तरह हो सकते हैं {_id: 'orange'}

यदि आप ऑब्जेक्ट्स कैसे बनाए जाते हैं, इसके बारे में अधिक जानना चाहते हैं, तो यहाँ कल्पना है: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification


11

यदि किसी को डुप्लिकेट मैंगो ऑब्जेक्ट्स के साथ समस्या हो रही है, तो आपको पता होना चाहिए कि मैंगो में होने वाले डुप्लिकेट्स की अवांछितता के बावजूद, मैंगो में PHP के साथ डुप्लिकेट _id का उत्पन्न होना संभव है।

उपयोग-मामला जहां मेरे लिए नियमितता के साथ हुआ है, जब मैं एक डेटासेट के माध्यम से लूप कर रहा हूं और डेटा को एक संग्रह में इंजेक्ट करने का प्रयास कर रहा हूं।

इंजेक्शन डेटा रखने वाले सरणी को प्रत्येक पुनरावृत्ति पर स्पष्ट रूप से रीसेट किया जाना चाहिए - भले ही आप _id मान निर्दिष्ट नहीं कर रहे हों। किसी कारण से, INSERT प्रक्रिया मानगो _id को सरणी में जोड़ता है जैसे कि यह एक वैश्विक चर था (भले ही सरणी में वैश्विक गुंजाइश न हो)। यह तब भी आपको प्रभावित कर सकता है जब आप एक अलग फ़ंक्शन कॉल में सम्मिलन को बुला रहे हैं जहां आप सामान्य रूप से सरणी के मूल्यों को कॉलिंग फ़ंक्शन पर वापस नहीं बनाए रखने की अपेक्षा करेंगे।

इसके तीन समाधान हैं:

  1. आप unset()सरणी से _id फ़ील्ड कर सकते हैं
  2. array()जब भी आप अपने डेटासेट के माध्यम से लूप करेंगे, तो आप हर बार के साथ संपूर्ण सरणी को फिर से संगठित कर सकते हैं
  3. आप अपने आप को स्पष्ट रूप से _id मान को परिभाषित कर सकते हैं (इस तरह से परिभाषित करने के लिए ध्यान रखना कि आप अपने आप को द्वैध उत्पन्न नहीं करते हैं)।

मेरा अनुमान है कि यह PHP इंटरफ़ेस में एक बग है, और मोंगो के साथ ऐसा कोई मुद्दा नहीं है, लेकिन यदि आप इस समस्या में भाग लेते हैं, तो बस _id को परेशान करें और आपको ठीक होना चाहिए।


यहाँ देखें: php.net/manual/en/mongocollection.insert.php : "ध्यान दें: यदि पैरामीटर के पास _id कुंजी या प्रॉपर्टी नहीं है, तो एक नया MongoId उदाहरण बनाया जाएगा और उसे सौंपा जाएगा। इस विशेष संस्करण का मतलब यह नहीं है। यह पैरामीटर संदर्भ द्वारा पारित किया गया है। ", यह एक फीचर है, बग नहीं है, यह इस तरह से है
ओलिवर कोनिग

1
मैं आपके द्वारा वर्णित परिदृश्य को नहीं समझता; शायद आप कुछ कोड दिखा सकते हैं जो बग प्रदर्शित करता है?
मार्क अमेरी

-7

संग्रह के दौरान ObjectId विशिष्टता के बारे में कोई गारंटी नहीं है। यहां तक ​​कि अगर यह संभावित रूप से बहुत संभावना नहीं है, तो यह एक बहुत ही खराब एप्लिकेशन डिज़ाइन होगा जो संग्रह के पार अद्वितीयता पर निर्भर था।

इसे आसानी से मूंग खोल में परीक्षण कर सकते हैं:

MongoDB shell version: 1.6.5
connecting to: test
> db.foo.insert({_id: 'abc'})
> db.bar.insert({_id: 'abc'})
> db.foo.find({_id: 'abc'})
{ "_id" : "abc" }
> db.bar.find({_id: 'abc'})
{ "_id" : "abc" }
> db.foo.insert({_id: 'abc', data:'xyz'})
E11000 duplicate key error index: test.foo.$_id_  dup key: { : "abc" }

इसलिए, पूरी तरह से _id के संग्रह में अद्वितीय होने पर निर्भर नहीं है, और चूंकि आप ObjectId जनरेशन फ़ंक्शन को नियंत्रित नहीं करते हैं, इसलिए इस पर भरोसा न करें।

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

याद रखें कि आप एक ही संग्रह में विभिन्न "प्रकारों" की वस्तुओं को रख सकते हैं, इसलिए केवल एक ही संग्रह में अपने दो "टेबल" क्यों न डालें। वे समान _id स्थान साझा करेंगे, और इस प्रकार, अद्वितीय गारंटी दी जाएगी। "संभावित" से "पंजीकृत" पर स्विच करना एक क्षेत्र का एक सरल फ़्लिपिंग होगा ...


1
मुझे लगता है कि आप ऑब्जेक्ट प्रकार के साथ सामान्य रूप से _id फ़ील्ड को भ्रमित कर सकते हैं। ऑब्जेक्ट प्रकार को विशेष रूप से इस लक्ष्य के साथ विशिष्टता के लिए डिज़ाइन किया गया था कि इसे UUID की तरह माना जा सकता है। हालांकि _id क्षेत्र किसी भी प्रकार का हो सकता है और केवल एकल संग्रह पर विशिष्टता की गारंटी देता है यदि आप कुंजी के लिए अन्य प्रकारों का उपयोग करते हैं, जैसे कि आपके उदाहरण में एक स्ट्रिंग।
मासिक धर्म

@ मस्टर्न (नाइटिक) यह धारणा कि एक यूयूआईडी स्वाभाविक रूप से अद्वितीय है त्रुटिपूर्ण है। एक अच्छा यूयूआईडी / अनुक्रम पीढ़ी की रणनीति टकराव की संभावना को कम कर सकती है लेकिन इसे जनरेटर के बीच पूर्ण विशिष्टता की गारंटी के लिए अद्वितीय जनरेटर (उदाहरण के लिए अद्वितीय स्थान) लेने की आवश्यकता है । दी गई, अधिकांश में संभावनाएं इतनी कम हैं कि यह किसी भी चिंता का विषय नहीं है :-) GUID । एक मुद्दा यह है कि करता है , हालांकि आने, दोहराव / बजाय एक नई पीढ़ी के आईडी की प्रतिलिपि बनाई जा रही है।

1
@pst: MongoDBs ऑब्जेक्ट में शामिल हैं जनरेटिंग प्रक्रिया के pid और hostname के हैश के आधार पर कुछ बाइट्स। एक टाइमस्टैम्प और इंक्रीमेंटिंग काउंटर के साथ ये संयुक्त रूप से यह संभावना है कि किसी भी दो अलग-अलग उत्पन्न ऑब्जेक्ट्स विश्व स्तर पर / सार्वभौमिक रूप से अद्वितीय होंगे। बेशक जैसा कि आपने कहा कि केवल नए सिरे से तैयार किए गए ऑब्जेक्ट पर लागू होता है।
मासिक धर्म

1
मैं ObjectId प्रकार की बात कर रहा हूँ। '_Id' के लिए स्ट्रिंग मान निर्दिष्ट नहीं करना। यदि आप उन्हें एक ही स्ट्रिंग मैन्युअल रूप से सेट करते हैं, तो निश्चित रूप से वे समान और संघर्ष करने वाले हैं।
एंथनी जैक

हाँ, मैंने अपनी पोस्ट में चीजें स्पष्ट की हैं। _id निश्चित रूप से अद्वितीय नहीं हैं, और चूंकि आप ObjectId जनरेशन फ़ंक्शन को नियंत्रित नहीं करते हैं, इसलिए शायद इस पर भरोसा करना एक बुरा विचार है।
slacy
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.