mongodb মংডুবি থেকে র্যান্ডম রেকর্ড



(20)

আপনার যদি একটি সহজ আইডি কী থাকে তবে আপনি সমস্ত আইডি একটি অ্যারের মধ্যে সংরক্ষণ করতে পারেন এবং তারপরে একটি এলোমেলো আইডি চয়ন করতে পারেন। (রুবি উত্তর):

ids = @coll.find({},fields:{_id:1}).to_a
@coll.find(ids.sample).first

আমি একটি বিশাল (100 মিলিয়ন রেকর্ড) mongodb থেকে একটি র্যান্ডম রেকর্ড পেতে mongodb

তাই দ্রুততম এবং সবচেয়ে কার্যকর উপায় কি? তথ্য ইতিমধ্যে আছে এবং কোন ক্ষেত্র নেই যেখানে আমি একটি র্যান্ডম সংখ্যা তৈরি করতে পারি এবং একটি র্যান্ডম সারি পেতে পারি।

কোনও পরামর্শ?


Answer #1

আপনি এলোমেলো _id বাছাই এবং অনুরূপ বস্তু ফেরত নিতে পারেন:

 db.collection.count( function(err, count){
        db.collection.distinct( "_id" , function( err, result) {
            if (err)
                res.send(err)
            var randomId = result[Math.floor(Math.random() * (count-1))]
            db.collection.findOne( { _id: randomId } , function( err, result) {
                if (err)
                    res.send(err)
                console.log(result)
            })
        })
    })

এখানে আপনি সংগ্রহের মধ্যে র্যান্ডম সংখ্যা সংরক্ষণের স্থান ব্যয় করতে হবে না।


Answer #2

আপনি একটি এলোমেলো টাইমস্ট্যাম্প বাছাই করতে পারেন এবং পরে তৈরি করা প্রথম বস্তুর জন্য অনুসন্ধান করতে পারেন। এটি শুধুমাত্র একটি একক দস্তাবেজ স্ক্যান করবে, যদিও এটি আপনাকে একটি অভিন্ন বিতরণ দেয় না।

var randRec = function() {
    // replace with your collection
    var coll = db.collection
    // get unixtime of first and last record
    var min = coll.find().sort({_id: 1}).limit(1)[0]._id.getTimestamp() - 0;
    var max = coll.find().sort({_id: -1}).limit(1)[0]._id.getTimestamp() - 0;

    // allow to pass additional query params
    return function(query) {
        if (typeof query === 'undefined') query = {}
        var randTime = Math.round(Math.random() * (max - min)) + min;
        var hexSeconds = Math.floor(randTime / 1000).toString(16);
        var id = ObjectId(hexSeconds + "0000000000000000");
        query._id = {$gte: id}
        return coll.find(query).limit(1)
    };
}();

Answer #3

আমি মানচিত্র / কমা ব্যবহার করে সুপারিশ করব, যেখানে আপনি মানচিত্র ফাংশনটি ব্যবহার করবেন যখন কেবলমাত্র একটি র্যান্ডম মান একটি প্রদত্ত সম্ভাব্যতার উপরে থাকে।

function mapf() {
    if(Math.random() <= probability) {
    emit(1, this);
    }
}

function reducef(key,values) {
    return {"documents": values};
}

res = db.questions.mapReduce(mapf, reducef, {"out": {"inline": 1}, "scope": { "probability": 0.5}});
printjson(res.results);

উপরের কমানো ফাংশন কাজ করে কারণ কেবল একটি কী ('1') মানচিত্র ফাংশন থেকে নির্গত হয়।

"সম্ভাব্যতা" এর মানটি "স্কোপ" -এর মধ্যে সংজ্ঞায়িত করা হয়, যখন ম্যাপআরড্রীস (...)

এই মত mapReduce ব্যবহার করে একটি sharded ডিবি ব্যবহারযোগ্য হতে হবে।

আপনি ডিবি থেকে সঠিকভাবে এম নথির নির্বাচন করতে চান তবে আপনি এটি এমনভাবে করতে পারেন:

function mapf() {
    if(countSubset == 0) return;
    var prob = countSubset / countTotal;
    if(Math.random() <= prob) {
        emit(1, {"documents": [this]}); 
        countSubset--;
    }
    countTotal--;
}

function reducef(key,values) {
    var newArray = new Array();
for(var i=0; i < values.length; i++) {
    newArray = newArray.concat(values[i].documents);
}

return {"documents": newArray};
}

res = db.questions.mapReduce(mapf, reducef, {"out": {"inline": 1}, "scope": {"countTotal": 4, "countSubset": 2}})
printjson(res.results);

কোথায় "গণনা totals" (মি) ডিবি মধ্যে নথি সংখ্যা, এবং "countSubset" (এন) পুনরুদ্ধারের নথি সংখ্যা।

এই পদ্ধতির sharded ডাটাবেস কিছু সমস্যা দিতে পারে।


Answer #4

মংডোডিবির 3.2 মুক্তির সাথে শুরু করে, আপনি $sample একীকরণ পাইপলাইন অপারেটর ব্যবহার করে একটি সংগ্রহ থেকে N র্যান্ডম ডক্স পেতে পারেন:

// Get one random document from the mycoll collection.
db.mycoll.aggregate([{ $sample: { size: 1 } }])

Answer #5

আপনি mongoose ব্যবহার করা হয়, তাহলে আপনি mongoose- র্যান্ডম mongoose-random র্যান্ডম ব্যবহার করতে পারেন


Answer #6

আমার পিএইচপি / MongoDB সাজানোর / RANDOM সমাধান দ্বারা অর্ডার। এই কেউ সাহায্য করে আশা করি।

দ্রষ্টব্য: আমার মঙ্গোডিবি সংগ্রহের মধ্যে সংখ্যাসূচক আইডি আছে যা একটি MySQL ডাটাবেস রেকর্ড উল্লেখ করে।

প্রথম আমি 10 এলোমেলোভাবে উত্পন্ন সংখ্যা সহ একটি অ্যারে তৈরি

    $randomNumbers = [];
    for($i = 0; $i < 10; $i++){
        $randomNumbers[] = rand(0,1000);
    }

আমার একীকরণে আমি $ অ্যাডফিল্ড পাইপলাইন অপারেটরটি $ arrayElemAt এবং $ mod (modulus) সহ মিলিত করে ব্যবহার করি। মডুলাস অপারেটর আমাকে 0 - 9 থেকে একটি নম্বর দেবে যা আমি এলোমেলো উত্পাদিত সংখ্যার সাথে অ্যারে থেকে একটি নম্বর চয়ন করতে ব্যবহার করি।

    $aggregate[] = [
        '$addFields' => [
            'random_sort' => [ '$arrayElemAt' => [ $randomNumbers, [ '$mod' => [ '$my_numeric_mysql_id', 10 ] ] ] ],
        ],
    ];

তারপরে আপনি সাজানোর পাইপলাইন ব্যবহার করতে পারেন।

    $aggregate[] = [
        '$sort' => [
            'random_sort' => 1
        ]
    ];

Answer #7

এটি বন্ধ করার জন্য কোন তথ্য নেই যদি এটি কঠিন। _ আইড ফিল্ড কি? তারা কি mongodb বস্তুর আইডি এর? যদি তাই হয়, আপনি সর্বোচ্চ এবং সর্বনিম্ন মান পেতে পারে:

lowest = db.coll.find().sort({_id:1}).limit(1).next()._id;
highest = db.coll.find().sort({_id:-1}).limit(1).next()._id;

তারপরে আপনি যদি আইডিগুলির সমানভাবে বিতরণ করেন তবে অনুমান করুন (তবে তারা তা নয়, তবে অন্তত এটি একটি শুরু):

unsigned long long L = first_8_bytes_of(lowest)
unsigned long long H = first_8_bytes_of(highest)

V = (H - L) * random_from_0_to_1();
N = L + V;
oid = N concat random_4_bytes();

randomobj = db.coll.find({_id:{$gte:oid}}).limit(1);

Answer #8

মানচিত্র / হ্রাস ব্যবহার করে, আপনি অবশ্যই একটি র্যান্ডম রেকর্ড পেতে পারেন, যার ফলে আপনি শেষ পর্যন্ত ফিল্টারযুক্ত সংগ্রহের আকারের উপর নির্ভর করে খুব কার্যকরীভাবে প্রয়োজনীয় নন।

আমি 50,000 নথির সাথে এই পদ্ধতিটি পরীক্ষা করেছি (ফিল্টার এটি প্রায় 30,000 হ্রাস করে), এবং এটি 16 গিগাবাইট RAM এবং SATA3 HDD সহ একটি Intel I3 এ প্রায় 400 মিমি সঞ্চালিত হয় ...

db.toc_content.mapReduce(
    /* map function */
    function() { emit( 1, this._id ); },

    /* reduce function */
    function(k,v) {
        var r = Math.floor((Math.random()*v.length));
        return v[r];
    },

    /* options */
    {
        out: { inline: 1 },
        /* Filter the collection to "A"ctive documents */
        query: { status: "A" }
    }
);

মানচিত্র ফাংশনটি কেবলমাত্র ক্যোয়ারির সাথে মেলে এমন সকল নথির আইডিগুলির একটি অ্যারে তৈরি করে। আমার ক্ষেত্রে আমি 50,000 সম্ভাব্য নথির মধ্যে প্রায় 30,000 দিয়ে এটি পরীক্ষা করেছি।

হ্রাস ফাংশনটি অ্যারেতে 0 এবং সংখ্যাগুলির সংখ্যা (-1) এর মধ্যে একটি র্যান্ডম পূর্ণসংখ্যা বাছাই করে এবং তারপর অ্যারের থেকে _id প্রদান করে।

400 মিমি দীর্ঘ সময়ের মত শোনাচ্ছে, এবং এটি আসলেই, যদি আপনার পঞ্চাশ হাজারের পরিবর্তে পঞ্চাশ মিলিয়ন রেকর্ড থাকে তবে এটি ঊর্ধ্বমুখী বিন্দুটিকে বাড়িয়ে তুলতে পারে যেখানে এটি বহু-ব্যবহারকারী পরিস্থিতিতে অব্যবহারযোগ্য হয়।

মংডোডিবির জন্য এই বৈশিষ্ট্যটি অন্তর্ভুক্ত করার জন্য একটি উন্মুক্ত সমস্যা রয়েছে ... https://jira.mongodb.org/browse/SERVER-533

যদি এই "র্যান্ডম" নির্বাচনটি অ্যারের মধ্যে আইডস সংগ্রহ করার পরিবর্তে সূচী-সন্ধানে তৈরি হয় এবং তারপরে একটি নির্বাচন করে, এটি অবিশ্বাস্যভাবে সাহায্য করবে। (এটা ভোট দিন!)


Answer #9

Python (pymongo) ব্যবহার করে, সমষ্টিগত ফাংশনও কাজ করে।

collection.aggregate([{'$sample': {'size': sample_size }}])

এই পদ্ধতিটি একটি র্যান্ডম নম্বর (যেমন সংগ্রহ.ফিন্ড ([random_int]) এর জন্য একটি ক্যোয়ারী চালানোর চেয়ে অনেক দ্রুত । এটি বিশেষত বড় সংগ্রহের ক্ষেত্রে।


Answer #10

সমস্ত রেকর্ড গণনা করুন, 0 এবং গণনার মধ্যে একটি র্যান্ডম সংখ্যা জেনারেট করুন, এবং তারপর করুন:

db.yourCollection.find().limit(-1).skip(yourRandomNumber).next()

Answer #11

আপনি ম্যান্ডোডিবির জিওস্প্যাটিয়াল ইন্ডেক্সিং বৈশিষ্ট্যটিও একটি র্যান্ডম সংখ্যাতে 'নিকটতম' নথি নির্বাচন করতে ব্যবহার করতে পারেন।

প্রথমত, সংগ্রহের উপর জ্যোস্প্যাটিয়াল ইন্ডেক্সিং সক্ষম করুন:

db.docs.ensureIndex( { random_point: '2d' } )

এক্স অক্ষে র্যান্ডম পয়েন্ট দিয়ে নথির গুচ্ছ তৈরি করতে:

for ( i = 0; i < 10; ++i ) {
    db.docs.insert( { key: i, random_point: [Math.random(), 0] } );
}

তারপর আপনি এই ধরনের সংগ্রহ থেকে একটি র্যান্ডম নথি পেতে পারেন:

db.docs.findOne( { random_point : { $near : [Math.random(), 0] } } )

অথবা আপনি একটি এলোমেলো বিন্দুর নিকটবর্তী বেশ কয়েকটি নথি পুনরুদ্ধার করতে পারেন:

db.docs.find( { random_point : { $near : [Math.random(), 0] } } ).limit( 4 )

এটি কেবলমাত্র একটি প্রশ্ন এবং কোনও নিল চেকের প্রয়োজন নেই, প্লাস কোডটি পরিষ্কার, সহজ এবং নমনীয়। আপনি আপনার প্রশ্নের একটি দ্বিতীয় এলোমেলো মাত্রা যোগ করতে জিওপয়েন্টের Y-axis ব্যবহার করতে পারেন।


Answer #12

এখন আপনি সমষ্টি ব্যবহার করতে পারেন। উদাহরণ:

db.users.aggregate(
   [ { $sample: { size: 3 } } ]
)

$sample


Answer #13

আমি প্রতিটি বস্তুর একটি র্যান্ডম int ক্ষেত্র যোগ করার পরামর্শ চাই। তারপর আপনি শুধু একটি করতে পারেন

findOne({random_field: {$gte: rand()}}) 

একটি র্যান্ডম নথি বাছাই করা। নিশ্চিত করুন যে আপনি নিশ্চিত করুন ইন্ডেক্স ({random_field: 1})


Answer #14

এটি চমৎকার কাজ করে, এটি দ্রুত, একাধিক নথির সাথে কাজ করে এবং rand ফিল্ডের জনসংখ্যা প্রয়োজন হয় না যা অবশেষে নিজেই তৈরি হবে:

  1. আপনার সংগ্রহে .and ক্ষেত্রের মধ্যে সূচক যোগ করুন
  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)
  }
})

গীত। Mongodb প্রশ্নে কিভাবে র্যান্ডম রেকর্ড খুঁজে পাওয়া যায় এই প্রশ্নের সদৃশ হিসাবে চিহ্নিত করা হয়। পার্থক্য হল যে এই প্রশ্ন স্পষ্টভাবে একক রেকর্ড সম্পর্কে জিজ্ঞেস করে, অন্যটি স্পষ্টভাবে র্যান্ডম দস্তাবেজগুলি পাওয়ার বিষয়ে।


Answer #15

যখন আমি একই ধরণের সমাধানটি মোকাবেলা করছিলাম, তখন আমি ব্যাকগ্রাউন্ড করেছিলাম এবং দেখলাম যে ব্যবসায়িক অনুরোধ প্রকৃতপক্ষে সরবরাহ করা জায়ের কিছু রূপ তৈরি করার জন্য ছিল। সেই ক্ষেত্রে, অনেকগুলি ভাল বিকল্প রয়েছে, যা সোলারের মতো অনুসন্ধান ইঞ্জিনগুলির উত্তর আছে, মংডোডবি মত তথ্য সঞ্চয় নয়।

সংক্ষেপে, প্রয়োজন অনুসারে "বুদ্ধিমানভাবে ঘোরান" সামগ্রীর সাথে, সমস্ত নথিতে একটি র্যান্ডম সংখ্যা পরিবর্তে আমাদের কী করা উচিত ব্যক্তিগত ক্স স্কোর সংশোধনকারী অন্তর্ভুক্ত করা। ব্যবহারকারীদের একটি ছোট জনসংখ্যার অনুমান করার জন্য, ব্যবহারকারীদের একটি ছোট জনসংখ্যার অনুমান করার জন্য, আপনি ব্যবহারকারীকে এমন একটি দস্তাবেজ সঞ্চয় করতে পারেন যার মধ্যে পণ্য আইড, ইমপ্রেশন গণনা, ক্লিক-থ্রু গণনা, শেষ দেখা তারিখ এবং ব্যবসায়ের যেকোনো কারণ যা AQ স্কোর গণনা করার অর্থপূর্ণ হিসাবে খুঁজে পাওয়া যায় পরিবর্তক। প্রদর্শনের জন্য সেটটি পুনরুদ্ধার করার সময়, সাধারণত ব্যবহারকারীর অনুরোধের চেয়ে আপনি ডেটা স্টোর থেকে আরো দস্তাবেজগুলির জন্য অনুরোধ করেন, তারপরে Q স্কোর সংশোধনকারী প্রয়োগ করুন, শেষ ব্যবহারকারীর অনুরোধকৃত রেকর্ডগুলির সংখ্যা গ্রহণ করুন, তারপরে ফলাফলগুলির পৃষ্ঠাটি র্যান্ডমাইজ করুন, একটি ক্ষুদ্র সেট, তাই অ্যাপ্লিকেশন স্তর (মেমরি) মধ্যে ডকুমেন্ট সহজভাবে সাজান।

ব্যবহারকারীদের মহাবিশ্বটি যদি খুব বড় হয় তবে আপনি ব্যবহারকারীর পরিবর্তে ব্যবহারকারীদের আচরণ গোষ্ঠী এবং সূচী গোষ্ঠী অনুসারে শ্রেণিবদ্ধ করতে পারেন।

যদি পণ্যগুলির মহাবিশ্ব যথেষ্ট ছোট হয় তবে আপনি প্রতি ব্যবহারকারীর জন্য একটি সূচক তৈরি করতে পারেন।

আমি এই কৌশলটি আরও দক্ষ হতে পেয়েছি, কিন্তু সফ্টওয়্যার সমাধান ব্যবহার করার প্রাসঙ্গিক, উপযুক্ত অভিজ্ঞতা তৈরি করতে আরো গুরুত্বপূর্ণভাবে আরও কার্যকর।


Answer #16

পিএইচপি আমার সমাধান:

/**
 * Get random docs from Mongo
 * @param $collection
 * @param $where
 * @param $fields
 * @param $limit
 * @author happy-code
 * @url happy-code.com
 */
private function _mongodb_get_random (MongoCollection $collection, $where = array(), $fields = array(), $limit = false) {

    // Total docs
    $count = $collection->find($where, $fields)->count();

    if (!$limit) {
        // Get all docs
        $limit = $count;
    }

    $data = array();
    for( $i = 0; $i < $limit; $i++ ) {

        // Skip documents
        $skip = rand(0, ($count-1) );
        if ($skip !== 0) {
            $doc = $collection->find($where, $fields)->skip($skip)->limit(1)->getNext();
        } else {
            $doc = $collection->find($where, $fields)->limit(1)->getNext();
        }

        if (is_array($doc)) {
            // Catch document
            $data[ $doc['_id']->{'$id'} ] = $doc;
            // Ignore current document when making the next iteration
            $where['_id']['$nin'][] = $doc['_id'];
        }

        // Every iteration catch document and decrease in the total number of document
        $count--;

    }

    return $data;
}

Answer #17

অনুলিপি ছাড়াই র্যান্ডম ডক্সগুলির একটি নির্ধারিত সংখ্যা পেতে:

  1. প্রথম সব আইড পেতে
  2. নথি আকার পেতে
  3. লুপ র্যান্ডম সূচক পেতে এবং ডুপ্লিকেট এড়িয়ে যান

    number_of_docs=7
    db.collection('preguntas').find({},{_id:1}).toArray(function(err, arr) {
    count=arr.length
    idsram=[]
    rans=[]
    while(number_of_docs!=0){
        var R = Math.floor(Math.random() * count);
        if (rans.indexOf(R) > -1) {
         continue
          } else {           
                   ans.push(R)
                   idsram.push(arr[R]._id)
                   number_of_docs--
                    }
        }
    db.collection('preguntas').find({}).toArray(function(err1, doc1) {
                    if (err1) { console.log(err1); return;  }
                   res.send(doc1)
                });
            });

Answer #18

সমাধান অ আমার জন্য ভাল কাজ করে। অনেক ফাঁক আছে এবং সেট ছোট যখন বিশেষ করে। এই আমার জন্য খুব ভাল কাজ (php):

$count = $collection->count($search);
$skip = mt_rand(0, $count - 1);
$result = $collection->find($search)->skip($skip)->limit(1)->getNext();

Answer #19

মংডোডিবি 3.2 এর জন্য আপডেট

3.2 সমষ্টি পাইপলাইন $sample চালু।

এটি অনুশীলন মধ্যে নির্বাণ একটি ভাল ব্লগ পোস্ট আছে

পুরোনো সংস্করণের জন্য (পূর্ববর্তী উত্তর)

এটি আসলে একটি বৈশিষ্ট্য অনুরোধ: http://jira.mongodb.org/browse/SERVER-533 কিন্তু এটি "ফিক্স করবেন না" এর অধীনে দায়ের করা হয়েছিল।

সংগ্রহের বাইরে একটি র্যান্ডম নথি নির্বাচন করার জন্য কুকুরের একটি খুব ভাল রেসিপি রয়েছে: http://cookbook.mongodb.org/patterns/random-attribute/

রেসিপি প্যারাফেস করতে, আপনি আপনার নথিতে র্যান্ডম সংখ্যা বরাদ্দ করুন:

db.docs.save( { key : 1, ..., random : Math.random() } )

তারপর একটি এলোমেলো নথি নির্বাচন করুন:

rand = Math.random()
result = db.docs.findOne( { key : 2, random : { $gte : rand } } )
if ( result == null ) {
  result = db.docs.findOne( { key : 2, random : { $lte : rand } } )
}

$gte এবং $lte উভয় $gte হচ্ছে একটি র্যান্ডম নম্বর নিকটবর্তী rand সাথে ডকুমেন্টটি সন্ধান করা প্রয়োজন।

এবং অবশ্যই আপনি এলোমেলো ক্ষেত্রে সূচী করতে চান:

db.docs.ensureIndex( { key : 1, random :1 } )

যদি আপনি ইতিমধ্যে কোনও সূচকের বিরুদ্ধে অনুসন্ধান করছেন তবে কেবল এটি ছেড়ে দিন, random: 1 যুক্ত random: 1 এটিকে আবার যোগ করুন।





mongodb