Как получить случайный один документ из 1 миллиарда документов в mongoDB с помощью python? [дубликат]

этот вопрос уже есть ответ здесь:

Я хочу один случайный документ из коллекции mongoDB. Теперь моя коллекция mongoDB содержит более 1 миллиарда коллекций. Как получить один случайный документ из этой коллекции ?

5 ответов


добавить дополнительный столбец с именем random для вашей коллекции и сделайте так, чтобы значение в ней находилось между 0 и 1. Вы можете назначить случайные плавающие точки от 0 до 1 в этот столбец для каждой записи через [random.random() for _ in range(0, 10)].

затем:-

import random

collection = mongodb["collection_name"]

rand = random.random()  # rand will be a floating point between 0 to 1.
random_record = collection.find_one({ 'random' => { '$gte' => rand } })

MongoDB будет иметь свою собственную реализацию в свое время. Подали здесь - https://jira.mongodb.org/browse/SERVER-533

еще не реализовано на момент написания.


Я никогда не работал с MongoDB в Python, но есть общее решение для вашей проблемы. Вот сценарий оболочки MongoDB для получения одного случайного документа:

N = db.collection.count(condition)
db.collection.find(condition).limit(1).skip(Math.floor(Math.random()*N))

condition вот запрос MongoDB. Если вы хотите запросить всю коллекцию, используйте query = null.

это общее решение, поэтому оно работает с любым драйвером MongoDB.


обновление

я запустил тест для тестирования нескольких реализаций. Во-первых, я создал тест коллекция с 5567249 документами с проиндексированных случайного поля rnd.

Я выбрал три метода для сравнения друг с другом:

Первый способ:

db.collection.find().limit(1).skip(Math.floor(Math.random()*N))

Второй способ:

db.collection.find({rnd: {$gte: Math.random()}}).sort({rnd:1}).limit(1)

Третий способ:

db.collection.findOne({rnd: {$gte: Math.random()}})

я запускал каждый метод 10 раз и получал среднее вычислительное время:

method 1: 882.1 msec
method 2: 1.2 msec
method 3: 0.6 msec

этот тест показывает, что мое решение не самое быстрое.

но третье решение не хороший, потому что он находит первый элемент в базе данных (сортировка в естественный порядок) С rnd > random(). Таким образом, его выход не является случайным.

Я думаю, что второй способ является лучшим для частого использования. Но у него есть один недостаток: он требует изменения всей базы данных и обеспечения дополнительного индекса.


С MongoDB 3.2, Это можно сделать с помощью С $sample оператор, как описано в docs. Это очень быстро. Следующий код будет случайным образом выбирать 20 документов из коллекции.

db.collection.aggregate( [ { $sample: {size: 20} } ] )

если вам нужно выбрать случайные документы с определенными критериями, вы можете использовать его с $match opperator

db.collection.aggregate([ 
    { $sample: {size: 20} }, 
    { $match:{"yourField": value} } 
  ])

остерегайтесь заказа! Если я ищу в своей небольшой базе данных около 100k документов, эта команда выше занимает 15 мс, а при переключении порядок, это 1750ms (более чем в 100 раз медленнее). Причина, конечно, очевидна. Кроме того, в этом порядке вы получаете подмножество этих случайных 20 документов...


в исполнительской манере? Тяжело, мягко говоря, без изменения ваших данных.

представьте, что вы пытаетесь получить rand () 1,000,000 из документов 1b. Это будет медленно, очень медленно. Это связано с тем, что MongoDB не эффективно использует индексы при пропуске.

как сказал @Calvin, MongoDB имеет запрос функции для получения случайных документов, однако он еще не реализован.

самый эффективный способ сделать это, atm, если вы должны были делать это регулярно, это добавить автоматический incrementing id к вашим записям:http://www.mongodb.org/display/DOCS/How + to + Make+an + Auto + Incrementing + поле и используйте это для rand() on.

редактировать

для уточнения; при использовании Auto incrementing id вам нужно будет сначала выполнить один запрос (если вы не отслеживаете его другим способом), чтобы получить наибольшее значение поля. Вы можете запросить коллекцию счетчиков или саму коллекцию и отсортировать в обратном порядке (sort({field:-1})) и limit(1) в получите наибольшее значение для rand().

Вам также необходимо учитывать изменения в данных, что означает, что вы действительно хотите $gte этой случайной позиции.

моя идея может быть объяснена подробнее здесь:php mongodb найти n-ю запись в коллекции


Если ваши объекты имеют int id на них, вы можете сделать что-то вроде

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