2011-12-14 13 views
16

में यादृच्छिक रूप से परिणाम सेट करने का आदेश मैंने हाल ही में पाया है कि मोंगो के पास इसके कमांड सिंटैक्स (https://jira.mongodb.org/browse/SERVER-533) में "ऑर्डर द्वारा रैंड()" के बराबर कोई एसक्यूएल नहीं है।मोंगो

मैंने http://cookbook.mongodb.org/patterns/random-attribute/ पर अनुशंसा देखी है और स्पष्ट रूप से, किसी दस्तावेज़ में यादृच्छिक विशेषता जोड़ने से हैक की तरह लगता है। यह काम नहीं करेगा क्योंकि यह किसी दिए गए प्रश्न के लिए एक निहित सीमा रखता है जिसे मैं यादृच्छिक बनाना चाहता हूं।

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

मेरे पास कुछ विचार हैं कि मैं इसे कोड के माध्यम से कैसे हल कर सकता हूं, लेकिन मुझे लगता है कि मुझे एक और स्पष्ट और मूल समाधान याद आ रहा है। क्या किसी के पास यह विचार या विचार है कि इसे और अधिक सुन्दर तरीके से कैसे हल किया जाए?

+2

मोंगोडीबी टिकट ट्रैकर में एक संग्रह से यादृच्छिक आइटम प्राप्त करने के लिए एक [सुविधा अनुरोध] है [https://jira.mongodb.org/browse/SERVER-533)। यदि मूल रूप से लागू किया गया है, तो यह संभवतः सबसे कुशल विकल्प होगा। (यदि आप सुविधा चाहते हैं, तो इसे वोट दें।) –

+0

इस सवाल को स्टैक ओवरफ़्लो पर कई रूपों में पूछा गया है। सबसे लोकप्रिय सवाल है [मोंगोडीबी से यादृच्छिक रिकॉर्ड] (http://stackoverflow.com/questions/2824157/random-record-from-mongodb) - इसमें अच्छे प्रतिक्रियाएं हैं। उस ने कहा, मुझे लगता है कि सवाल के बारे में सोचने का सबसे अच्छा तरीका एक यादृच्छिक दस्तावेज़ प्राप्त करने के बारे में सोचना नहीं है, बल्कि, परिणाम सेट को यादृच्छिक बनाना, जैसा आपने पूछा था! देखें [मोंगो में यादृच्छिक रूप से परिणाम सेट ऑर्डर करना] (http://stackoverflow.com/questions/8500266/ordering-a-result-set-randomly-in-mongo) इसके लिए। –

उत्तर

0

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

क्यों? यदि आपके पास 7.000 दस्तावेज़ हैं और आप 0 से 69 99 तक तीन यादृच्छिक ऑफ़सेट चुनते हैं, तो चुने गए दस्तावेज़ यादृच्छिक होंगे, भले ही संग्रह स्वयं वर्णानुक्रम में क्रमबद्ध हो।

+1

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

2

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

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

+1

यह एक अंतर्निहित सीमा जोड़ता है क्योंकि किसी भी यादृच्छिक रूप से जेनरेट किए गए नंबर पर केवल कुछ निश्चित दस्तावेज हो सकते हैं - उदाहरण के लिए, यदि मैं यादृच्छिक संख्या खींचना 0.9111 है तो केवल कुछ निश्चित दस्तावेज होने जा रहे हैं जो अर्हता प्राप्त करने जा रहे हैं मानदंड $ gte => 0.9111 –

+0

@ एंडी, यह मानदंडों के अनुरूप दस्तावेजों की मात्रा की केवल एक सीमा है जो आपके आवेदन के लिए आवश्यक राशि से कम है। यदि आप उस किनारे के मामले को दबाते हैं तो आप अपने सेट को नए जेनरेट किए गए यादृच्छिक संख्या के साथ एक नई क्वेरी के साथ पूरक करते हैं। –

+0

@ एंडी, आप 0.9111 से शुरू होने वाले सेट के बजाय प्रति यादृच्छिक मूल्य को एक ही दस्तावेज़ ढूंढना चाहते हैं, यदि आपको अपने सेट को वास्तव में यादृच्छिक होने की आवश्यकता है (उदाहरण के लिए उस मामले से बचें जहां 0.9111 द्वारा सेट किया गया सेट 90% जैसा ही है उदाहरण के लिए 0.9222 का उपयोग करके लौटाया गया) –

7

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

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

हालांकि यह निश्चित रूप से एक हैक है, तो आप एक बहुत ही आसान बचाव मार्ग है: MongoDB स्कीमा से मुक्त प्रकृति को देखते हुए, तो आप बस एक बार वहाँ सर्वर में यादृच्छिक प्रकार के लिए समर्थन है यादृच्छिक क्षेत्र को शामिल करना बंद कर सकते हैं। यदि आकार एक मुद्दा है, तो आप मौजूदा दस्तावेजों से फ़ील्ड को हटाने के लिए बैच नौकरी चला सकते हैं। यदि आप इसे सावधानी से डिजाइन करते हैं तो आपके क्लाइंट कोड में कोई महत्वपूर्ण बदलाव नहीं होना चाहिए।

एक वैकल्पिक विकल्प यादृच्छिक रूप से परिणामों की संख्या के बारे में लंबे और कठिन सोचने के लिए होगा और किसी दिए गए प्रश्न के लिए वापस लौटाया जाएगा। क्लाइंट कोड में शफल होने के लिए यह अत्यधिक महंगा नहीं हो सकता है (यानी, अगर आप केवल हाल ही में 10,000 पदों पर विचार करते हैं)।

+1

हाँ, यह वास्तव में पूरे संग्रह को पकड़ने और क्लाइंट कोड पर ऐसा करने के लिए वास्तव में उचित है, इसलिए मैं यही कर रहा हूं। यह सिर्फ * लगता है * कार्यक्षमता की तरह जो डेटा भंडारण के मूल निवासी होना चाहिए। –

+0

मुझे नहीं लगता कि यादृच्छिकता डेटाबेस के लिए एक बहुत ही आम आवश्यकता है और निरंतर समय में कुशलता से कार्यान्वित करना थोड़ा मुश्किल है। –

+0

मैं भी जोड़ दूंगा कि एक यादृच्छिक क्रम के साथ पेजिनेशन काफी अजीब हो जाता है। – juanpaco

0

कोई आईडी फ़ील्ड डाल सकता है ($ आईडी फ़ील्ड काम नहीं करेगा क्योंकि यह वास्तविक संख्या नहीं है) यादृच्छिक छोड़ने के लिए मॉड्यूलस गणित का उपयोग करें। यदि आपके पास 10,000 रिकॉर्ड हैं और आप 10 परिणाम चाहते थे तो आप 253 के रूप में 1 और 1000 यादृच्छिक रूप से sucH के बीच एक मॉड्यूलस चुन सकते हैं और फिर अनुरोध करें कि जहां मोड (आईडी, 253) = 0 और यह आईडी के अनुक्रमित होने पर उचित रूप से तेज़ है। फिर यादृच्छिक रूप से क्लाइंट पक्ष को उन 10 परिणामों को सॉर्ट करें। निश्चित रूप से वे वास्तव में यादृच्छिक रूप से यादृच्छिक रूप से बाहर हैं, लेकिन यह वांछित के करीब है।

2

आप इस एक कोशिश दे सकते हैं - यह तेज है, कई दस्तावेजों के साथ काम करता है और शुरुआत में rand क्षेत्र को आबाद करने की आवश्यकता नहीं है, जो अंततः खुद से स्थापित हो जाएगा:

  1. पर क्षेत्र .rand को सूचकांक में जोड़ अपने संग्रह
  2. उपयोग खोजने के लिए और ताज़ा करते हैं, की तरह कुछ:
// Install packages: 
// npm install mongodb async 
// Add index in mongo: 
// db.ensureIndex('mycollection', { rand: 1 }) 

var mongodb = require('mongodb') 
var async = require('async') 

// Find n random documents by using "rand" field. 
function findAndRefreshRand (collection, n, fields, done) { 
    var result = [] 
    var rand = Math.random() 

    // Append documents to the result based on criteria and options, if options.limit is 0 skip the call. 
    var appender = function (criteria, options, done) { 
    return function (done) { 
     if (options.limit > 0) { 
     collection.find(criteria, fields, options).toArray(
      function (err, docs) { 
      if (!err && Array.isArray(docs)) { 
       Array.prototype.push.apply(result, docs) 
      } 
      done(err) 
      } 
     ) 
     } else { 
     async.nextTick(done) 
     } 
    } 
    } 

    async.series([ 

    // Fetch docs with unitialized .rand. 
    // NOTE: You can comment out this step if all docs have initialized .rand = Math.random() 
    appender({ rand: { $exists: false } }, { limit: n - result.length }), 

    // Fetch on one side of random number. 
    appender({ rand: { $gte: rand } }, { sort: { rand: 1 }, limit: n - result.length }), 

    // Continue fetch on the other side. 
    appender({ rand: { $lt: rand } }, { sort: { rand: -1 }, limit: n - result.length }), 

    // Refresh fetched docs, if any. 
    function (done) { 
     if (result.length > 0) { 
     var batch = collection.initializeUnorderedBulkOp({ w: 0 }) 
     for (var i = 0; i < result.length; ++i) { 
      batch.find({ _id: result[i]._id }).updateOne({ rand: Math.random() }) 
     } 
     batch.execute(done) 
     } else { 
     async.nextTick(done) 
     } 
    } 

    ], function (err) { 
    done(err, result) 
    }) 
} 

// Example usage 
mongodb.MongoClient.connect('mongodb://localhost:27017/core-development', function (err, db) { 
    if (!err) { 
    findAndRefreshRand(db.collection('profiles'), 1024, { _id: true, rand: true }, function (err, result) { 
     if (!err) { 
     console.log(result) 
     } else { 
     console.error(err) 
     } 
     db.close() 
    }) 
    } else { 
    console.error(err) 
    } 
}) 
0

दोनों विकल्पों में से मेरे लिए गैर आदर्श हैक्स तरह लगता है, यादृच्छिक दायर एक डी हमेशा एक ही मूल्य होगा और छोड़ें एक ही संख्या के लिए एक ही रिकॉर्ड वापस कर देगा।

यादृच्छिक रूप से स्कैन करने के लिए आप कुछ यादृच्छिक फ़ील्ड का उपयोग क्यों नहीं करते हैं, मैं मानता हूं कि यह एक हैक भी है लेकिन मेरे अनुभव में यादृच्छिकता की बेहतर भावना है।

संबंधित मुद्दे